useDecryptedAsset()
useDecryptedAsset is the low-level composable shared by SwImage and SwAsyncText. It abstracts the "remote-asset fetch → conditional AES decryption → IndexedDB persistent caching → state machine" pipeline. Application code rarely calls it directly, but it's available when you need to build custom encrypted-asset loaders (custom store tables, custom cache encodings).
Usage
Real .bnc decryption (status + result)
加载中...
The toCache / fromCache hooks let the caller decide both the cache format and the final business-result format:
// Example 1: encrypted image → Blob URL (this is exactly what SwImage does internally)
const { status, result: blobUrl } = useDecryptedAsset<Blob, string>({
url: computed(() => props.src),
key: imgKey,
table: 'image',
toCache: buf => new Blob([buf], { type: detectMime(buf) }),
fromCache: blob => URL.createObjectURL(blob),
})
// Example 2: encrypted text → string (reactively watching url changes — SwAsyncText's pattern)
const { result: text } = useDecryptedAsset<Uint8Array, string>({
url: computed(() => props.url),
key: imgKey,
table: 'text',
toCache: buf => new Uint8Array(buf),
fromCache: bytes => new TextDecoder().decode(bytes),
reactive: true,
})
How It Works
- SSR short-circuit: when
import.meta.serveristrue, returns immediately.statusstays'loading'; no network request, no decryption - Cache lookup:
fileId = md5(new URL(url).pathname).toUpperCase(). Queries the IndexedDB store table first; on hit, returnsfromCache(data) - Remote fetch + conditional decryption: on miss,
fetch(url)returns anArrayBuffer; ifurlcontains.bnc→decryptBinary(buf, key), otherwise skips decryption and goes straight totoCache - Cache write: the
toCache-encoded data is written to IndexedDB (instant on next visit);resultflips fromnull→ business result;statusfrom'loading'→'loaded'. The cache write is a degradable side path — it is not awaited (rendering never waits on the DB) and a write failure is silently ignored (fw#380) - Reactive reload: when
reactive: true,watchEffectwatchesurlfor reactive changes and re-runs the pipeline; withfalse(default), only triggers once viaonMounted
Options
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
url | MaybeRef<string> | ✓ | — | Asset URL. Accepts a reactive value (Ref / computed) |
key | string | ✓ | — | AES decryption key. Only used for .bnc URLs; ignored on the plain path but still required |
table | 'image' | 'text' | ✓ | — | IndexedDB store-table name. Two are reserved: 'image' for image-class assets, 'text' for text-class |
toCache | (buffer: ArrayBuffer) => TCached | ✓ | — | Encodes the (decrypted) ArrayBuffer into the cache format (e.g. new Blob([buf]) / new Uint8Array(buf)) |
fromCache | (cached: TCached) => TResult | ✓ | — | Decodes the cache format into the business result (e.g. URL.createObjectURL(blob) / new TextDecoder().decode(bytes)) |
reactive | boolean | false | true watches url reactively via watchEffect; false triggers once via onMounted |
Return value
| Name | Type | Description |
|---|---|---|
status | Ref<'loading' | 'loaded' | 'error'> | Current load state. Always 'loading' during SSR |
result | Ref<TResult | null> | Decoded business result. null means loading (or SSR); non-null means ready |
Caveats
- Client-only — depends on IndexedDB / fetch / Web Crypto. The function returns immediately during SSR; the caller's
statusstays'loading'. Render a skeleton placeholder forresult === null - Encryption routing is automatic from the URL: contains
.bnc→ decrypt, otherwise skip. No need for callers to branch - The dbGet/dbPut data shape is
{ id: string, data: TCached }, compatible with the existingSwImage/SwAsyncTextcache format - Cache-write failures are silently ignored (fw#380): rendering is unaffected (
resultcomes from the in-memorycacheData) and the rejection never bubbles up as anunhandledrejectionpollutingerrorHandlerreports. The typical trigger is writing a Blob to IndexedDB in storage-restricted WebKit environments (crawlers / Safari private mode / restricted WebViews). A cache-read failure is treated as a miss and falls back to remote loading; network, decryption, and conversion failures still setstatus='error' - Adding new store-table names requires registering the schema in
framework/src/runtime/utils/db.tsfirst; otherwise IndexedDB writes will fail - Stale requests: each load clears the previous result and resets the status to
loading. Only the latest request may update the result and status. An empty URL or scope disposal invalidates earlier requests; network requests already sent are not actively cancelled.