db (IndexedDB)
A thin IndexedDB wrapper built on Dexie. The framework uses it to cache decrypted .bnc assets (the persistence layer behind SwImage / SwAsyncText / useDecryptedAsset). Business code can also use it directly for client-side persistence of large binary / structured data. All 3 functions are auto-imported.
How It Works
- A Dexie instance (database name
database, version 1) is created at module load, with two fixed stores:image— decrypted image binaries / blob URL cachetext— decrypted text fragment cache
- Every record carries an auto-incrementing
++idand anupdated_atindex for time-based eviction. - Each API lazily opens the database on first call; Dexie handles concurrent races. The instance is a module-level singleton — all callers in the same tab share one connection.
dbPutautomatically overwritesupdated_at(second-precision timestamp); callers never maintain it by hand.
API
| Function | Signature | Notes |
|---|---|---|
dbPut | (data: object, storeName: string) => Promise<void> | Insert or update a record (data must contain an id field as the primary key); writes updated_at automatically |
dbGet | (id: string, storeName: string) => Promise<unknown> | Get a single record by id; undefined on miss |
dbClear | (storeName: string) => Promise<void> | Clear the given store |
Examples
dbPut / dbGet (persists across reloads)
// Cache a decrypted image blob URL
await dbPut({ id: 'cover.bnc', url: blobUrl }, 'image')
// Read the cache; decrypt from origin on miss
const hit = await dbGet('cover.bnc', 'image')
const url = hit?.url ?? await decryptAndCache('cover.bnc')
// Clear all caches on logout
await dbClear('image')
await dbClear('text')
Caveats
Client only (DB-001, blocker)
IndexedDB is a browser API and does not exist in Node.js — calling during SSR throws immediately. All db APIs must run inside onMounted / an IS_CLIENT guard / a client-only component:
// ❌ Called at setup top level — "indexedDB is not defined" during SSR
const hit = await dbGet('cover.bnc', 'image')
// ✅ Inside onMounted
onMounted(async () => {
const hit = await dbGet('cover.bnc', 'image')
})
storeName must be 'image' or 'text' (DB-002, warning)
The schema has exactly these two stores, but the storeName parameter is a bare string with no compile-time check. Passing an undefined store name (e.g. 'user' / 'cover') gives you a Dexie "ghost table" — writes succeed without errors, but the data goes into the void and can never be read back, which is extremely hard to debug:
// ❌ 'cover' is not a store created by the framework → write succeeds, read never does
await dbPut({ id: 'x', url }, 'cover')
const hit = await dbGet('x', 'cover') // forever undefined
// ✅ Only use the two framework-created store names
await dbPut({ id: 'x', url }, 'image')
If your business needs its own table structure, create your own Dexie instance in the business layer — do not reuse the framework's database.