diff --git a/src/lib/components/organisms/Category/Category.svelte b/src/lib/components/organisms/Category/Category.svelte index 81471e6..3728f5f 100644 --- a/src/lib/components/organisms/Category/Category.svelte +++ b/src/lib/components/organisms/Category/Category.svelte @@ -1,6 +1,7 @@
diff --git a/src/lib/modules/filesystem/category.ts b/src/lib/modules/filesystem/category.ts index 310a220..dc25506 100644 --- a/src/lib/modules/filesystem/category.ts +++ b/src/lib/modules/filesystem/category.ts @@ -52,25 +52,76 @@ const fetchFromServer = async (id: CategoryId, masterKey: CryptoKey) => { metadata, subCategories: subCategoriesRaw, files: filesRaw, - } = await trpc().category.get.query({ id }); - const [subCategories, files] = await Promise.all([ - Promise.all( - subCategoriesRaw.map(async (category) => ({ + } = await trpc().category.get.query({ id, recurse: true }); + const subCategories = await Promise.all( + subCategoriesRaw.map(async (category) => { + const decrypted = await decryptCategoryMetadata(category, masterKey); + const existing = await IndexedDB.getCategoryInfo(category.id); + await IndexedDB.storeCategoryInfo({ id: category.id, - ...(await decryptCategoryMetadata(category, masterKey)), - })), - ), - filesRaw - ? Promise.all( - filesRaw.map(async (file) => ({ + parentId: id, + name: decrypted.name, + files: existing?.files ?? [], + isFileRecursive: existing?.isFileRecursive ?? false, + }); + return { + id: category.id, + ...decrypted, + }; + }), + ); + + const existingFiles = filesRaw + ? await IndexedDB.bulkGetFileInfos(filesRaw.map((file) => file.id)) + : []; + const files = filesRaw + ? await Promise.all( + filesRaw.map(async (file, index) => { + const decrypted = await decryptFileMetadata(file, masterKey); + const existing = existingFiles[index]; + if (existing) { + const categoryIds = file.isRecursive + ? existing.categoryIds + : Array.from(new Set([...existing.categoryIds, id as number])); + await IndexedDB.storeFileInfo({ + id: file.id, + parentId: existing.parentId, + contentType: file.contentType, + name: decrypted.name, + createdAt: decrypted.createdAt, + lastModifiedAt: decrypted.lastModifiedAt, + categoryIds, + }); + } + return { id: file.id, contentType: file.contentType, isRecursive: file.isRecursive, - ...(await decryptFileMetadata(file, masterKey)), - })), - ) - : undefined, - ]); + ...decrypted, + }; + }), + ) + : undefined; + + const decryptedMetadata = metadata + ? await decryptCategoryMetadata(metadata, masterKey) + : undefined; + if (id !== "root" && metadata && decryptedMetadata) { + const existingCategory = await IndexedDB.getCategoryInfo(id); + await IndexedDB.storeCategoryInfo({ + id: id as number, + parentId: metadata.parent, + name: decryptedMetadata.name, + files: + files?.map((file) => ({ + id: file.id, + isRecursive: file.isRecursive, + })) ?? + existingCategory?.files ?? + [], + isFileRecursive: existingCategory?.isFileRecursive ?? false, + }); + } if (id === "root") { return { @@ -84,7 +135,7 @@ const fetchFromServer = async (id: CategoryId, masterKey: CryptoKey) => { exists: true as const, subCategories, files, - ...(await decryptCategoryMetadata(metadata!, masterKey)), + ...decryptedMetadata!, }; } } catch (e) { diff --git a/src/lib/modules/filesystem/directory.ts b/src/lib/modules/filesystem/directory.ts index 6417758..6449480 100644 --- a/src/lib/modules/filesystem/directory.ts +++ b/src/lib/modules/filesystem/directory.ts @@ -39,22 +39,52 @@ const fetchFromServer = async (id: DirectoryId, masterKey: CryptoKey) => { subDirectories: subDirectoriesRaw, files: filesRaw, } = await trpc().directory.get.query({ id }); - const [subDirectories, files] = await Promise.all([ + const existingFiles = await IndexedDB.bulkGetFileInfos(filesRaw.map((file) => file.id)); + const [subDirectories, files, decryptedMetadata] = await Promise.all([ Promise.all( - subDirectoriesRaw.map(async (directory) => ({ - id: directory.id, - ...(await decryptDirectoryMetadata(directory, masterKey)), - })), + subDirectoriesRaw.map(async (directory) => { + const decrypted = await decryptDirectoryMetadata(directory, masterKey); + await IndexedDB.storeDirectoryInfo({ + id: directory.id, + parentId: id, + name: decrypted.name, + }); + return { + id: directory.id, + ...decrypted, + }; + }), ), Promise.all( - filesRaw.map(async (file) => ({ - id: file.id, - contentType: file.contentType, - ...(await decryptFileMetadata(file, masterKey)), - })), + filesRaw.map(async (file, index) => { + const decrypted = await decryptFileMetadata(file, masterKey); + await IndexedDB.storeFileInfo({ + id: file.id, + parentId: id, + contentType: file.contentType, + name: decrypted.name, + createdAt: decrypted.createdAt, + lastModifiedAt: decrypted.lastModifiedAt, + categoryIds: existingFiles[index]?.categoryIds ?? [], + }); + return { + id: file.id, + contentType: file.contentType, + ...decrypted, + }; + }), ), + metadata ? decryptDirectoryMetadata(metadata, masterKey) : undefined, ]); + if (id !== "root" && metadata && decryptedMetadata) { + await IndexedDB.storeDirectoryInfo({ + id, + parentId: metadata.parent, + name: decryptedMetadata.name, + }); + } + if (id === "root") { return { id, @@ -69,7 +99,7 @@ const fetchFromServer = async (id: DirectoryId, masterKey: CryptoKey) => { parentId: metadata!.parent, subDirectories, files, - ...(await decryptDirectoryMetadata(metadata!, masterKey)), + ...decryptedMetadata!, }; } } catch (e) { diff --git a/src/lib/modules/filesystem/file.ts b/src/lib/modules/filesystem/file.ts index d8411bf..45fef78 100644 --- a/src/lib/modules/filesystem/file.ts +++ b/src/lib/modules/filesystem/file.ts @@ -66,15 +66,26 @@ const bulkFetchFromIndexedDB = async (ids: number[]) => { const fetchFromServer = async (id: number, masterKey: CryptoKey) => { try { const { categories: categoriesRaw, ...metadata } = await trpc().file.get.query({ id }); - const [categories] = await Promise.all([ + const [categories, decryptedMetadata] = await Promise.all([ Promise.all( categoriesRaw.map(async (category) => ({ id: category.id, ...(await decryptCategoryMetadata(category, masterKey)), })), ), + decryptFileMetadata(metadata, masterKey), ]); + await IndexedDB.storeFileInfo({ + id, + parentId: metadata.parent, + contentType: metadata.contentType, + name: decryptedMetadata.name, + createdAt: decryptedMetadata.createdAt, + lastModifiedAt: decryptedMetadata.lastModifiedAt, + categoryIds: categories.map((category) => category.id), + }); + return { id, exists: true as const, @@ -82,7 +93,7 @@ const fetchFromServer = async (id: number, masterKey: CryptoKey) => { contentType: metadata.contentType, contentIv: metadata.contentIv, categories, - ...(await decryptFileMetadata(metadata, masterKey)), + ...decryptedMetadata, }; } catch (e) { if (isTRPCClientError(e) && e.data?.code === "NOT_FOUND") { @@ -97,12 +108,25 @@ const bulkFetchFromServer = async (ids: number[], masterKey: CryptoKey) => { const filesRaw = await trpc().file.bulkGet.query({ ids }); const files = await Promise.all( filesRaw.map(async (file) => { - const categories = await Promise.all( - file.categories.map(async (category) => ({ - id: category.id, - ...(await decryptCategoryMetadata(category, masterKey)), - })), - ); + const [categories, decryptedMetadata] = await Promise.all([ + Promise.all( + file.categories.map(async (category) => ({ + id: category.id, + ...(await decryptCategoryMetadata(category, masterKey)), + })), + ), + decryptFileMetadata(file, masterKey), + ]); + + await IndexedDB.storeFileInfo({ + id: file.id, + parentId: file.parent, + contentType: file.contentType, + name: decryptedMetadata.name, + createdAt: decryptedMetadata.createdAt, + lastModifiedAt: decryptedMetadata.lastModifiedAt, + categoryIds: categories.map((category) => category.id), + }); return { id: file.id, exists: true as const, @@ -110,7 +134,7 @@ const bulkFetchFromServer = async (ids: number[], masterKey: CryptoKey) => { contentType: file.contentType, contentIv: file.contentIv, categories, - ...(await decryptFileMetadata(file, masterKey)), + ...decryptedMetadata, }; }), );