chore: moved temp script storage to idb (closes #1)
All checks were successful
Docs / build (push) Successful in 2m25s

This commit is contained in:
alina 🌸 2025-01-21 05:45:02 +03:00
parent efbb7c0b11
commit c2107bf01d
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
3 changed files with 70 additions and 22 deletions

View file

@ -2,7 +2,8 @@ import { unknownToError } from '@fuman/utils'
import { IS_SAFARI } from '../utils/env.ts' import { IS_SAFARI } from '../utils/env.ts'
import { clearAvatarCache, handleAvatarRequest } from './avatar.ts' import { clearAvatarCache, handleAvatarRequest } from './avatar.ts'
import { requestCache } from './cache.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 declare const self: ServiceWorkerGlobalScope
@ -70,6 +71,7 @@ function handleMessage(msg: SwMessage) {
} }
case 'CLEAR_CACHE': { case 'CLEAR_CACHE': {
clearCache() clearCache()
forgetAllScripts()
break break
} }
case 'CLEAR_AVATAR_CACHE': { case 'CLEAR_AVATAR_CACHE': {

View file

@ -1,13 +1,12 @@
import { utf8 } from '@fuman/utils' import { utf8 } from '@fuman/utils'
import { VfsStorage } from '../vfs/storage.ts' import { VfsStorage } from '../vfs/storage.ts'
import { generateImportMap, generateRunnerHtml } from './iframe/html.ts' import { generateImportMap, generateRunnerHtml } from './iframe/html.ts'
import { getScriptFile } from './scripts.ts'
const libraryCache = new Map<string, Map<string, Uint8Array>>() const libraryCache = new Map<string, Map<string, Uint8Array>>()
let importMapCache: Record<string, string> | undefined let importMapCache: Record<string, string> | undefined
let vfs: VfsStorage | undefined let vfs: VfsStorage | undefined
const scriptsStorage = new Map<string, string>()
async function getVfs() { async function getVfs() {
if (!vfs) { if (!vfs) {
vfs = await VfsStorage.create() vfs = await VfsStorage.create()
@ -32,24 +31,8 @@ async function loadLibrary(name: string) {
return map return map
} }
export function uploadScript(name: string, files: Record<string, string>) {
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() { export function clearCache() {
libraryCache.clear() libraryCache.clear()
scriptsStorage.clear()
importMapCache = undefined importMapCache = undefined
vfs = undefined vfs = undefined
} }
@ -80,12 +63,17 @@ export async function handleRuntimeRequest(url: URL) {
} }
if (path.startsWith('script/')) { if (path.startsWith('script/')) {
const scriptId = path.slice('script/'.length) const scriptIdWithPath = path.slice('script/'.length)
if (!scriptsStorage.has(scriptId)) { 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('Not found', { status: 404 })
} }
return new Response(scriptsStorage.get(scriptId)!, { return new Response(file, {
headers: { headers: {
'Content-Type': 'application/javascript', 'Content-Type': 'application/javascript',
'Cache-Control': 'no-cache, no-store, must-revalidate', 'Cache-Control': 'no-cache, no-store, must-revalidate',

View file

@ -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<string, string>
}
}
}
let db: IDBPDatabase<Schema> | undefined
async function getDb() {
if (!db) {
db = await openDB<Schema>('mtcute-repl-scripts', 1, {
upgrade(db) {
db.createObjectStore('scripts', { keyPath: 'id' })
},
})
}
return db
}
export async function uploadScript(id: string, files: Record<string, string>) {
const db = await getDb()
await db.put('scripts', { id, files })
}
const cachedScripts = new Map<string, Record<string, string>>()
export async function getScriptFile(id: string, fileName: string): Promise<string | null> {
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<void> {
const db = await getDb()
await db.delete('scripts', id)
cachedScripts.delete(id)
}
export async function forgetAllScripts(): Promise<void> {
const db = await getDb()
await db.clear('scripts')
cachedScripts.clear()
}