파일 및 디렉터리 목록을 IndexedDB에 캐싱하도록 구현

This commit is contained in:
static
2025-01-17 12:22:51 +09:00
parent 7e711c1b8f
commit 7aa6ba0eab
23 changed files with 285 additions and 165 deletions

View File

@@ -3,8 +3,8 @@
import { untrack } from "svelte";
import type { Writable } from "svelte/store";
import { TopBar } from "$lib/components";
import { getFileInfo } from "$lib/modules/file";
import { masterKeyStore, type FileInfo } from "$lib/stores";
import { getFileInfo, type FileInfo } from "$lib/modules/filesystem";
import { masterKeyStore } from "$lib/stores";
import { requestFileDownload } from "./service";
type ContentType = "image" | "video";
@@ -27,7 +27,7 @@
});
$effect(() => {
if ($info && !isDownloaded) {
if ($info?.contentIv && $info?.dataKey && !isDownloaded) {
untrack(() => {
isDownloaded = true;
@@ -37,7 +37,7 @@
contentType = "video";
}
requestFileDownload(data.id, $info.contentIv, $info.dataKey).then(async (res) => {
requestFileDownload(data.id, $info.contentIv!, $info.dataKey!).then(async (res) => {
content = new Blob([res], { type: $info.contentType });
if (content.type === "image/heic" || content.type === "image/heif") {
const { default: heic2any } = await import("heic2any");

View File

@@ -3,8 +3,9 @@
import type { Writable } from "svelte/store";
import { TopBar } from "$lib/components";
import type { FileCacheIndex } from "$lib/indexedDB";
import { getFileCacheIndex, getFileInfo } from "$lib/modules/file";
import { masterKeyStore, type FileInfo } from "$lib/stores";
import { getFileCacheIndex } from "$lib/modules/file";
import { getFileInfo, type FileInfo } from "$lib/modules/filesystem";
import { masterKeyStore } from "$lib/stores";
import File from "./File.svelte";
import { formatFileSize, deleteFileCache as doDeleteFileCache } from "./service";

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import type { Writable } from "svelte/store";
import type { FileCacheIndex } from "$lib/indexedDB";
import type { FileInfo } from "$lib/stores";
import type { FileInfo } from "$lib/modules/filesystem";
import { formatDate, formatFileSize } from "./service";
import IconDraft from "~icons/material-symbols/draft";

View File

@@ -4,8 +4,8 @@
import { goto } from "$app/navigation";
import { TopBar } from "$lib/components";
import { FloatingButton } from "$lib/components/buttons";
import { getDirectoryInfo } from "$lib/modules/file";
import { masterKeyStore, hmacSecretStore, type DirectoryInfo } from "$lib/stores";
import { getDirectoryInfo, type DirectoryInfo } from "$lib/modules/filesystem";
import { masterKeyStore, hmacSecretStore } from "$lib/stores";
import CreateBottomSheet from "./CreateBottomSheet.svelte";
import CreateDirectoryModal from "./CreateDirectoryModal.svelte";
import DeleteDirectoryEntryModal from "./DeleteDirectoryEntryModal.svelte";

View File

@@ -1,14 +1,13 @@
<script lang="ts">
import { untrack } from "svelte";
import { get, type Writable } from "svelte/store";
import { getDirectoryInfo, getFileInfo } from "$lib/modules/file";
import {
fileUploadStatusStore,
masterKeyStore,
getDirectoryInfo,
getFileInfo,
type DirectoryInfo,
type FileInfo,
type FileUploadStatus,
} from "$lib/stores";
} from "$lib/modules/filesystem";
import { fileUploadStatusStore, masterKeyStore, type FileUploadStatus } from "$lib/stores";
import File from "./File.svelte";
import SubDirectory from "./SubDirectory.svelte";
import { SortBy, sortEntries } from "./service";
@@ -110,7 +109,7 @@
</script>
{#if subDirectories.length + files.length > 0}
<div class="pb-[4.5rem]">
<div class="space-y-1 pb-[4.5rem]">
{#each subDirectories as { info }}
<SubDirectory {info} onclick={onEntryClick} onOpenMenuClick={onEntryMenuClick} />
{/each}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import type { Writable } from "svelte/store";
import type { FileInfo } from "$lib/stores";
import type { FileInfo } from "$lib/modules/filesystem";
import { formatDateTime } from "./service";
import type { SelectedDirectoryEntry } from "../service";
@@ -17,6 +17,8 @@
const openFile = () => {
const { id, dataKey, dataKeyVersion, name } = $info!;
if (!dataKey || !dataKeyVersion) return; // TODO: Error handling
setTimeout(() => {
onclick({ type: "file", id, dataKey, dataKeyVersion, name });
}, 100);
@@ -26,6 +28,8 @@
e.stopPropagation();
const { id, dataKey, dataKeyVersion, name } = $info!;
if (!dataKey || !dataKeyVersion) return; // TODO: Error handling
setTimeout(() => {
onOpenMenuClick({ type: "file", id, dataKey, dataKeyVersion, name });
}, 100);

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import type { Writable } from "svelte/store";
import type { DirectoryInfo } from "$lib/stores";
import type { DirectoryInfo } from "$lib/modules/filesystem";
import type { SelectedDirectoryEntry } from "../service";
import IconFolder from "~icons/material-symbols/folder";
@@ -18,6 +18,8 @@
const openDirectory = () => {
const { id, dataKey, dataKeyVersion, name } = $info as SubDirectoryInfo;
if (!dataKey || !dataKeyVersion) return; // TODO: Error handling
setTimeout(() => {
onclick({ type: "directory", id, dataKey, dataKeyVersion, name });
}, 100);
@@ -27,6 +29,8 @@
e.stopPropagation();
const { id, dataKey, dataKeyVersion, name } = $info as SubDirectoryInfo;
if (!dataKey || !dataKeyVersion) return; // TODO: Error handling
setTimeout(() => {
onOpenMenuClick({ type: "directory", id, dataKey, dataKeyVersion, name });
}, 100);

View File

@@ -47,7 +47,7 @@ export const requestDirectoryCreation = async (
const { dataKey, dataKeyVersion } = await generateDataKey();
const nameEncrypted = await encryptString(name, dataKey);
await callPostApi<DirectoryCreateRequest>("/api/directory/create", {
parentId,
parent: parentId,
mekVersion: masterKey.version,
dek: await wrapDataKey(dataKey, masterKey.key),
dekVersion: dataKeyVersion.toISOString(),

View File

@@ -20,6 +20,7 @@ export const GET: RequestHandler = async ({ locals, params }) => {
return json(
directoryInfoResponse.parse({
metadata: metadata && {
parent: metadata.parentId,
mekVersion: metadata.mekVersion,
dek: metadata.encDek,
dekVersion: metadata.dekVersion.toISOString(),

View File

@@ -9,11 +9,11 @@ export const POST: RequestHandler = async ({ locals, request }) => {
const zodRes = directoryCreateRequest.safeParse(await request.json());
if (!zodRes.success) error(400, "Invalid request body");
const { parentId, mekVersion, dek, dekVersion, name, nameIv } = zodRes.data;
const { parent, mekVersion, dek, dekVersion, name, nameIv } = zodRes.data;
await createDirectory({
userId,
parentId,
parentId: parent,
mekVersion,
encDek: dek,
dekVersion: new Date(dekVersion),

View File

@@ -17,6 +17,7 @@ export const GET: RequestHandler = async ({ locals, params }) => {
const { id } = zodRes.data;
const {
parentId,
mekVersion,
encDek,
dekVersion,
@@ -28,6 +29,7 @@ export const GET: RequestHandler = async ({ locals, params }) => {
} = await getFileInformation(userId, id);
return json(
fileInfoResponse.parse({
parent: parentId,
mekVersion,
dek: encDek,
dekVersion: dekVersion.toISOString(),

View File

@@ -12,7 +12,7 @@ const parseFileMetadata = (userId: number, json: string) => {
const zodRes = fileUploadRequest.safeParse(JSON.parse(json));
if (!zodRes.success) error(400, "Invalid request body");
const {
parentId,
parent,
mekVersion,
dek,
dekVersion,
@@ -32,7 +32,7 @@ const parseFileMetadata = (userId: number, json: string) => {
return {
userId,
parentId,
parentId: parent,
mekVersion,
encDek: dek,
dekVersion: new Date(dekVersion),