mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-06-20 21:00:41 +00:00
feat: improve offline PWA resilience
This commit is contained in:
@@ -302,6 +302,11 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
await Promise.all([refetchCiphers(), refetchFolders(), refetchSends()]);
|
||||
};
|
||||
|
||||
const requireOnlineWrite = () => {
|
||||
if (session?.accessToken) return;
|
||||
throw new Error(t('txt_offline_vault_readonly'));
|
||||
};
|
||||
|
||||
const syncVaultCoreInBackground = (options?: { includeFolders?: boolean }) => {
|
||||
const tasks: Promise<unknown>[] = [Promise.resolve(refetchCiphers())];
|
||||
if (options?.includeFolders) {
|
||||
@@ -447,6 +452,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
|
||||
async createVaultItem(draft: VaultDraft, attachments: File[] = []) {
|
||||
if (!session) return;
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
const optimistic = optimisticCipherFromDraft(draft, null);
|
||||
patchDecryptedCiphers((prev) => [optimistic, ...prev.filter((cipher) => cipher.id !== optimistic.id)]);
|
||||
try {
|
||||
@@ -471,6 +482,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
|
||||
async updateVaultItem(cipher: Cipher, draft: VaultDraft, options?: { addFiles?: File[]; removeAttachmentIds?: string[] }) {
|
||||
if (!session) return;
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
if (hasUnresolvedCipherData(cipher)) {
|
||||
throw new Error(t('txt_decrypt_failed_2'));
|
||||
}
|
||||
@@ -543,6 +560,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async deleteVaultItem(cipher: Cipher) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
const previousCipher = { ...cipher };
|
||||
if (cipher.deletedDate || (cipher as { deletedAt?: string | null }).deletedAt) {
|
||||
try {
|
||||
@@ -571,6 +594,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async archiveVaultItem(cipher: Cipher) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
const previousCipher = { ...cipher };
|
||||
const archivedDate = new Date().toISOString();
|
||||
patchCipherBatch([cipher.id], (current) => ({ ...current, archivedDate, deletedDate: null, revisionDate: archivedDate }));
|
||||
@@ -587,6 +616,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async unarchiveVaultItem(cipher: Cipher) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
const previousCipher = { ...cipher };
|
||||
const revisionDate = new Date().toISOString();
|
||||
patchCipherBatch([cipher.id], (current) => ({ ...current, archivedDate: null, revisionDate }));
|
||||
@@ -603,6 +638,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async bulkDeleteVaultItems(ids: string[]) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await bulkDeleteCiphers(authedFetch, ids);
|
||||
const deletedDate = new Date().toISOString();
|
||||
@@ -616,6 +657,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async bulkArchiveVaultItems(ids: string[]) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await bulkArchiveCiphers(authedFetch, ids);
|
||||
const archivedDate = new Date().toISOString();
|
||||
@@ -629,6 +676,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async bulkUnarchiveVaultItems(ids: string[]) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await bulkUnarchiveCiphers(authedFetch, ids);
|
||||
patchCipherBatch(ids, (cipher) => ({ ...cipher, archivedDate: null }));
|
||||
@@ -641,6 +694,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async bulkMoveVaultItems(ids: string[], folderId: string | null) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await bulkMoveCiphers(authedFetch, ids, folderId);
|
||||
patchCipherBatch(ids, (cipher) => ({ ...cipher, folderId }));
|
||||
@@ -658,6 +717,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
onNotify('error', t('txt_folder_name_is_required'));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
if (!session) throw new Error(t('txt_vault_key_unavailable'));
|
||||
const created = await createFolder(authedFetch, session, folderName);
|
||||
@@ -683,6 +748,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
onNotify('error', t('txt_folder_not_found'));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await deleteFolder(authedFetch, id);
|
||||
patchFolderBatch([id], () => null);
|
||||
@@ -706,6 +777,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
onNotify('error', t('txt_folder_name_is_required'));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
if (!session) throw new Error(t('txt_vault_key_unavailable'));
|
||||
await updateFolder(authedFetch, session, id, nextName);
|
||||
@@ -719,6 +796,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async bulkRestoreVaultItems(ids: string[]) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await bulkRestoreCiphers(authedFetch, ids);
|
||||
patchCipherBatch(ids, (cipher) => ({ ...cipher, deletedDate: null }));
|
||||
@@ -731,6 +814,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async bulkPermanentDeleteVaultItems(ids: string[]) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await bulkPermanentDeleteCiphers(authedFetch, ids);
|
||||
patchCipherBatch(ids, () => null);
|
||||
@@ -745,6 +834,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
async bulkDeleteFolders(folderIds: string[]) {
|
||||
const ids = Array.from(new Set(folderIds.map((id) => String(id || '').trim()).filter(Boolean)));
|
||||
if (!ids.length) return;
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await bulkDeleteFolders(authedFetch, ids);
|
||||
const removedIds = new Set(ids);
|
||||
@@ -765,6 +860,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
|
||||
async createSend(draft: SendDraft, autoCopyLink: boolean) {
|
||||
if (!session) return;
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const fileName = draft.type === 'file' ? String(draft.file?.name || '').trim() : '';
|
||||
if (fileName) {
|
||||
@@ -790,6 +891,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
|
||||
async updateSend(send: Send, draft: SendDraft, autoCopyLink: boolean) {
|
||||
if (!session) return;
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
const updated = await updateSend(authedFetch, session, send, draft);
|
||||
await refetchSends();
|
||||
@@ -806,6 +913,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async deleteSend(send: Send) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await deleteSend(authedFetch, send.id);
|
||||
await refetchSends();
|
||||
@@ -817,6 +930,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
},
|
||||
|
||||
async bulkDeleteSends(ids: string[]) {
|
||||
try {
|
||||
requireOnlineWrite();
|
||||
} catch (error) {
|
||||
onNotify('error', error instanceof Error ? error.message : t('txt_offline_vault_readonly'));
|
||||
throw error;
|
||||
}
|
||||
try {
|
||||
await bulkDeleteSends(authedFetch, ids);
|
||||
await refetchSends();
|
||||
@@ -833,6 +952,7 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
|
||||
attachments: ImportAttachmentFile[] = []
|
||||
): Promise<ImportResultSummary> {
|
||||
if (!session?.symEncKey || !session?.symMacKey) throw new Error(t('txt_vault_key_unavailable'));
|
||||
requireOnlineWrite();
|
||||
|
||||
const mode = options.folderMode || 'original';
|
||||
const targetFolderId = (options.targetFolderId || '').trim() || null;
|
||||
|
||||
Reference in New Issue
Block a user