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

  1. A Dexie instance (database name database, version 1) is created at module load, with two fixed stores:
    • image — decrypted image binaries / blob URL cache
    • text — decrypted text fragment cache
  2. Every record carries an auto-incrementing ++id and an updated_at index for time-based eviction.
  3. 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.
  4. dbPut automatically overwrites updated_at (second-precision timestamp); callers never maintain it by hand.

API

FunctionSignatureNotes
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.