From c2107bf01d74ca84431206ff2f6c79f7906672bf Mon Sep 17 00:00:00 2001 From: alina sireneva Date: Tue, 21 Jan 2025 05:45:02 +0300 Subject: [PATCH] chore: moved temp script storage to idb (closes #1) --- packages/worker/src/sw/main.ts | 4 ++- packages/worker/src/sw/runtime.ts | 30 +++++----------- packages/worker/src/sw/scripts.ts | 58 +++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 packages/worker/src/sw/scripts.ts diff --git a/packages/worker/src/sw/main.ts b/packages/worker/src/sw/main.ts index 0978962..5d295da 100644 --- a/packages/worker/src/sw/main.ts +++ b/packages/worker/src/sw/main.ts @@ -2,7 +2,8 @@ import { unknownToError } from '@fuman/utils' import { IS_SAFARI } from '../utils/env.ts' import { clearAvatarCache, handleAvatarRequest } from './avatar.ts' import { requestCache } from './cache.ts' -import { clearCache, forgetScript, handleRuntimeRequest, uploadScript } from './runtime.ts' +import { clearCache, handleRuntimeRequest } from './runtime.ts' +import { forgetAllScripts, forgetScript, uploadScript } from './scripts.ts' declare const self: ServiceWorkerGlobalScope @@ -70,6 +71,7 @@ function handleMessage(msg: SwMessage) { } case 'CLEAR_CACHE': { clearCache() + forgetAllScripts() break } case 'CLEAR_AVATAR_CACHE': { diff --git a/packages/worker/src/sw/runtime.ts b/packages/worker/src/sw/runtime.ts index 3782222..34b3c6c 100644 --- a/packages/worker/src/sw/runtime.ts +++ b/packages/worker/src/sw/runtime.ts @@ -1,13 +1,12 @@ import { utf8 } from '@fuman/utils' import { VfsStorage } from '../vfs/storage.ts' import { generateImportMap, generateRunnerHtml } from './iframe/html.ts' +import { getScriptFile } from './scripts.ts' const libraryCache = new Map>() let importMapCache: Record | undefined let vfs: VfsStorage | undefined -const scriptsStorage = new Map() - async function getVfs() { if (!vfs) { vfs = await VfsStorage.create() @@ -32,24 +31,8 @@ async function loadLibrary(name: string) { return map } -export function uploadScript(name: string, files: Record) { - for (const [fileName, contents] of Object.entries(files)) { - scriptsStorage.set(`${name}/${fileName}`, contents) - } -} - -export function forgetScript(name: string) { - const folder = `${name}/` - for (const path of scriptsStorage.keys()) { - if (path.startsWith(folder)) { - scriptsStorage.delete(path) - } - } -} - export function clearCache() { libraryCache.clear() - scriptsStorage.clear() importMapCache = undefined vfs = undefined } @@ -80,12 +63,17 @@ export async function handleRuntimeRequest(url: URL) { } if (path.startsWith('script/')) { - const scriptId = path.slice('script/'.length) - if (!scriptsStorage.has(scriptId)) { + const scriptIdWithPath = path.slice('script/'.length) + const idx = scriptIdWithPath.indexOf('/') + const scriptId = scriptIdWithPath.slice(0, idx) + const fileName = scriptIdWithPath.slice(idx + 1) + + const file = await getScriptFile(scriptId, fileName) + if (!file) { return new Response('Not found', { status: 404 }) } - return new Response(scriptsStorage.get(scriptId)!, { + return new Response(file, { headers: { 'Content-Type': 'application/javascript', 'Cache-Control': 'no-cache, no-store, must-revalidate', diff --git a/packages/worker/src/sw/scripts.ts b/packages/worker/src/sw/scripts.ts new file mode 100644 index 0000000..6ca5a46 --- /dev/null +++ b/packages/worker/src/sw/scripts.ts @@ -0,0 +1,58 @@ +import type { DBSchema, IDBPDatabase } from 'idb' +import { openDB } from 'idb' + +interface Schema extends DBSchema { + scripts: { + key: string + value: { + id: string + files: Record + } + } +} +let db: IDBPDatabase | undefined + +async function getDb() { + if (!db) { + db = await openDB('mtcute-repl-scripts', 1, { + upgrade(db) { + db.createObjectStore('scripts', { keyPath: 'id' }) + }, + }) + } + + return db +} + +export async function uploadScript(id: string, files: Record) { + const db = await getDb() + + await db.put('scripts', { id, files }) +} + +const cachedScripts = new Map>() + +export async function getScriptFile(id: string, fileName: string): Promise { + if (cachedScripts.has(id)) { + return cachedScripts.get(id)![fileName] + } + + const db = await getDb() + const res = await db.get('scripts', id) + if (!res) return null + + cachedScripts.set(id, res.files) + return res.files[fileName] +} + +export async function forgetScript(id: string): Promise { + const db = await getDb() + await db.delete('scripts', id) + cachedScripts.delete(id) +} + +export async function forgetAllScripts(): Promise { + const db = await getDb() + await db.clear('scripts') + cachedScripts.clear() +}