import { getAllFileInfos } from "$lib/indexedDB/filesystem"; import { decryptData } from "$lib/modules/crypto"; import { getFileCache, storeFileCache, deleteFileCache, getFileThumbnailCache, storeFileThumbnailCache, deleteFileThumbnailCache, downloadFile, } from "$lib/modules/file"; import { getThumbnailUrl } from "$lib/modules/thumbnail"; import type { FileThumbnailUploadRequest } from "$lib/server/schemas"; import { trpc } from "$trpc/client"; export const requestFileDownload = async ( fileId: number, fileEncryptedIv: string, dataKey: CryptoKey, ) => { const cache = await getFileCache(fileId); if (cache) return cache; const fileBuffer = await downloadFile(fileId, fileEncryptedIv, dataKey); storeFileCache(fileId, fileBuffer); // Intended return fileBuffer; }; export const requestFileThumbnailUpload = async ( fileId: number, dataKeyVersion: Date, thumbnailEncrypted: { ciphertext: ArrayBuffer; iv: string }, ) => { const form = new FormData(); form.set( "metadata", JSON.stringify({ dekVersion: dataKeyVersion.toISOString(), contentIv: thumbnailEncrypted.iv, } satisfies FileThumbnailUploadRequest), ); form.set("content", new Blob([thumbnailEncrypted.ciphertext])); return await fetch(`/api/file/${fileId}/thumbnail/upload`, { method: "POST", body: form }); }; export const requestFileThumbnailDownload = async (fileId: number, dataKey?: CryptoKey) => { const cache = await getFileThumbnailCache(fileId); if (cache || !dataKey) return cache; let thumbnailInfo; try { thumbnailInfo = await trpc().file.thumbnail.query({ id: fileId }); } catch { // TODO: Error Handling return null; } const { contentIv: thumbnailEncryptedIv } = thumbnailInfo; const res = await fetch(`/api/file/${fileId}/thumbnail/download`); if (!res.ok) return null; const thumbnailEncrypted = await res.arrayBuffer(); const thumbnailBuffer = await decryptData(thumbnailEncrypted, thumbnailEncryptedIv, dataKey); storeFileThumbnailCache(fileId, thumbnailBuffer); // Intended return getThumbnailUrl(thumbnailBuffer); }; export const requestDeletedFilesCleanup = async () => { let liveFiles; try { liveFiles = await trpc().file.list.query(); } catch { // TODO: Error Handling return; } const liveFilesSet = new Set(liveFiles); const maybeCachedFiles = await getAllFileInfos(); await Promise.all( maybeCachedFiles .filter(({ id }) => !liveFilesSet.has(id)) .flatMap(({ id }) => [deleteFileCache(id), deleteFileThumbnailCache(id)]), ); };