feat: implement vault synchronization and decryption improvements

- Added background synchronization for vault core data, including optional folder updates.
- Introduced a new API endpoint to retrieve the vault revision date.
- Enhanced vault synchronization logic to utilize a caching mechanism for improved performance.
- Created a new vault cache module to handle IndexedDB storage for vault core snapshots.
- Implemented a worker for asynchronous decryption of vault data, improving UI responsiveness.
- Updated main application settings to adjust query stale time for better data freshness.
- Refactored vault-related API functions to support cache keys for more efficient data retrieval.
This commit is contained in:
shuaiplus
2026-04-28 22:10:34 +08:00
parent aa6f9210b4
commit 1b0386bf78
10 changed files with 702 additions and 331 deletions
+18 -5
View File
@@ -111,6 +111,14 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
await Promise.all([refetchCiphers(), refetchFolders(), refetchSends()]);
};
const syncVaultCoreInBackground = (options?: { includeFolders?: boolean }) => {
const tasks: Promise<unknown>[] = [Promise.resolve(refetchCiphers())];
if (options?.includeFolders) {
tasks.push(Promise.resolve(refetchFolders()));
}
void Promise.all(tasks).catch(() => undefined);
};
async function decryptAndPatch(encrypted: Cipher) {
if (!session?.symEncKey || !session?.symMacKey) {
await refetchCiphers();
@@ -202,7 +210,7 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
await uploadCipherAttachment(authedFetch, session, created.id, file, undefined, setAttachmentUploadPercent);
}
await decryptAndPatch(created);
if (draft.folderId) await refetchFolders();
syncVaultCoreInBackground({ includeFolders: !!draft.folderId || attachments.length > 0 });
onNotify('success', t('txt_item_created'));
} catch (error) {
onNotify('error', error instanceof Error ? error.message : t('txt_create_item_failed'));
@@ -230,7 +238,12 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
await uploadCipherAttachment(authedFetch, session, cipher.id, file, cipher, setAttachmentUploadPercent);
}
await decryptAndPatch(updated);
if (draft.folderId !== (cipher.folderId || '')) await refetchFolders();
syncVaultCoreInBackground({
includeFolders:
draft.folderId !== (cipher.folderId || '')
|| addFiles.length > 0
|| removeAttachmentIds.length > 0,
});
onNotify('success', t('txt_item_updated'));
} catch (error) {
onNotify('error', error instanceof Error ? error.message : t('txt_update_item_failed'));
@@ -263,7 +276,7 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
try {
const deleted = await deleteCipher(authedFetch, cipher.id);
await decryptAndPatch(deleted);
await refetchFolders();
syncVaultCoreInBackground({ includeFolders: true });
onNotify('success', t('txt_item_deleted'));
} catch (error) {
onNotify('error', error instanceof Error ? error.message : t('txt_delete_item_failed'));
@@ -275,7 +288,7 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
try {
const archived = await archiveCipher(authedFetch, cipher.id);
await decryptAndPatch(archived);
await refetchFolders();
syncVaultCoreInBackground({ includeFolders: true });
onNotify('success', t('txt_item_archived'));
} catch (error) {
onNotify('error', error instanceof Error ? error.message : t('txt_archive_item_failed'));
@@ -287,7 +300,7 @@ export default function useVaultSendActions(options: UseVaultSendActionsOptions)
try {
const unarchived = await unarchiveCipher(authedFetch, cipher.id);
await decryptAndPatch(unarchived);
await refetchFolders();
syncVaultCoreInBackground({ includeFolders: true });
onNotify('success', t('txt_item_unarchived'));
} catch (error) {
onNotify('error', error instanceof Error ? error.message : t('txt_unarchive_item_failed'));