Browser Extensions
The recommended setup for a browser extension or dapp — IdbProviderV3 for storage, session-key resume as the primary unlock, deriveWallets(N) with chunked progress, and argon2BackendInfo() to detect the slow CSP fallback.
wative-core runs in the browser with the same API as Node. Beyond the one-time setup on Node & Browser (the Buffer polyfill and storage durability), four opt-in choices make a wallet extension fast and resilient. The library's defaults stay backward-compatible, so set these four deliberately.
| Concern | Reach for | Why |
|---|---|---|
| Storage | IdbProviderV3 | one key derivation per container — unlock stays fast at any account size |
| Unlock | session-key resume, password fallback | reopen an evicted background page with no password and no key stretching |
| Bulk derive | deriveWallets(N) with { chunkSize, onProgress } | one write, and a loop that yields so the tab never freezes |
| Resilience | argon2BackendInfo() on startup | detect a CSP that forces the slow fallback and warn the user |
1 — Storage: IdbProviderV3
import { Workspace, IdbProviderV3 } from "wative-core";
const provider = await IdbProviderV3.create("my-wallet"); // opt-in
const ws = await Workspace.open({ provider, password });IdbProviderV3 derives one container key rather than one per stored secret, so unlocking a large account stays fast instead of slowing down as wallets are added. It is also the only provider that can hand out a session key. A workspace it writes cannot be opened by older library versions, so choose it before the first write.
The default IdbProvider is unchanged and still supported. IdbProviderV3 is a sibling you construct yourself; create takes the same options. See IdbProvider.
2 — Unlock: session key first, password as fallback
An extension's background page is evicted often, and re-prompting for the password each time is the main friction. A v3 workspace hands out a 32-byte session key that reopens it with no password:
// On the first (password) unlock, in the foreground:
const key = ws.exportSessionKey(); // 32 bytes
await chrome.storage.session.set({ wk: Array.from(key) }); // memory-only; cleared when the browser quits
// Later, when the background page wakes with no password:
const { wk } = await chrome.storage.session.get("wk");
const ws2 = await Workspace.openWithSessionKey(provider, Uint8Array.from(wk));
// or resume a locked handle you still hold: await ws.unlockWithSessionKey(key);The session key opens the same records the password does. Keep it in a memory-only store such as chrome.storage.session, never in local/sync storage or on disk. A wrong key leaves the workspace locked; an account with its own password still needs that password; a v2 provider has no such key (exportSessionKey() throws UNSUPPORTED_OP).
See Session keys for the full contract.
3 — Bulk derivation without freezing the tab
Add wallets in one call, and pass { chunkSize, onProgress } so a large derivation yields to the browser between chunks and can drive a progress bar:
await account.deriveWallets(400, {
chunkSize: 20, // yield to the UI every 20 wallets
onProgress: (done, total) => setBar(done / total),
});Without options, deriveWallets(N) runs as one uninterrupted block — fine for a small count or off the main thread. With options it derives in chunks that yield a macrotask between them, so the main thread paints. Either way the whole batch writes to storage exactly once.
Do not loop deriveWallets(1) to add many wallets: each call rewrites the whole account record, so the cost grows super-linearly with the account's total wallet count. One deriveWallets(N) is a single write.
See Wallets.
4 — Resilience: detect the key-derivation backend
Argon2 runs on a bundled WebAssembly build. A Content-Security-Policy without 'wasm-unsafe-eval' blocks WebAssembly, and the library falls back to a pure-JS implementation that is roughly 17× slower — correct, but an unlock that was a fraction of a second becomes several. Detect it on startup and tell the user:
import { argon2BackendInfo } from "wative-core";
// After the first unlock (it resolves lazily; before that it reads "unresolved"):
const info = argon2BackendInfo();
if (!info.wasm) {
showSlowModeNotice(); // suggest granting 'wasm-unsafe-eval' in the extension's CSP
}The library also logs the fallback once to the console. See Key derivation.