'worker' (default)
Thread: Dedicated Web Worker. Storage: OPFS.
Production web apps. Keeps the UI responsive while the daemon runs.
The embedded daemon persists two kinds of browser-local data:
swapDatabaseFileName in
RuntimeConfig to name this SQLite file explicitly; set disableSwaps
to turn off the Lightning swap subsystem (and its storage) entirely. When
swaps are disabled, Wavelength suppresses preset and override swap fields.OPFS (Origin Private File System) is the production path. Files live under
the page origin in a private directory the page cannot enumerate from outside
the API. The shipped WASM daemon stores the encrypted seed and SQLite databases
in OPFS. Set dataDir in RuntimeConfig to choose a subdirectory (for
example '/my-wallet'); when unset the daemon uses its default.
localStorage is a window-only key/value store. It is not available inside Web Workers, so the default worker transport cannot use it for daemon storage. Main-thread mode can fall back to storage patterns that do not require OPFS, but you lose durable SQLite persistence and the UI thread blocks while the daemon runs.
Your app may still use localStorage for app-level markers (for example recording whether a wallet was created with a passkey or storing a passkey credential id for scoped unlock). The reference demo does this; daemon state remains in OPFS.
OPFS-backed SQLite requires SharedArrayBuffer, which browsers only expose
on cross-origin isolated pages.
Without isolation, OPFS persistence for the daemon will not come up cleanly.
Request persistent storage (navigator.storage.persist()) if you want the
browser to deprioritize eviction of origin data. It is best-effort and does not
replace backing up the recovery phrase.
// Ask the browser to treat this origin's storage as persistent.const granted = await navigator.storage.persist();Whether the browser grants the request depends on its own engagement heuristics (installed as a PWA, bookmarked, frequently visited, and similar signals). Do not rely on it being granted; treat it as best-effort.
createWebClient() accepts runtimeThread: 'worker' (default) or
'main'.
Thread: Dedicated Web Worker. Storage: OPFS.
Production web apps. Keeps the UI responsive while the daemon runs.
Thread: Page main thread. Storage: No OPFS SQLite path.
Escape hatch when Workers are unavailable or you cannot set COOP/COEP headers. Expect UI jank.
Worker mode spawns the bundled wavewalletdk-worker.js (override with
workerURL). The worker receives runtimeBaseUrl on init so it can fetch
wavewalletdk.wasm.gz, wasm_exec.js, and the SQLite bridge from your hosted asset
folder. Main-thread mode loads those scripts on the page directly.
import { createWebClient, defaultConfig } from '@lightninglabs/wavelength-web';
// Default: worker + OPFS (requires cross-origin isolation).const workerClient = createWebClient({ runtimeBaseUrl: 'https://your-host/wavewalletdk/',});
// Escape hatch: main thread, no OPFS persistence.const mainClient = createWebClient({ runtimeThread: 'main', runtimeBaseUrl: 'https://your-host/wavewalletdk/',});
// Choose a dataDir subdirectory for the daemon's on-disk tree.const config = defaultConfig('signet', { dataDir: '/my-wallet' });await workerClient.ready();await workerClient.start(config);Persistence requirements for the default worker path:
crossOriginIsolated is true and
SharedArrayBuffer is available.RUNTIME_ASSET_FILES) at runtimeBaseUrl.dataDir per wallet profile; changing it starts a fresh
on-disk tree.Wiping local wallet data means clearing both OPFS entries under your origin and
any app-level localStorage keys you wrote. See the demo’s wipe helper
(apps/web-wallet-demo/src/lib/wipeLocalData.ts) for a reference pattern, and
the wavelength-web reference for the client
start/stop lifecycle.