wavelength-web
Browser SDK factory, configuration, and passkey ceremony API for Wavelength web apps.
@lightninglabs/wavelength-web is the browser/wasm transport for the Wavelength SDK: it
runs the embedded daemon as WebAssembly, either in a dedicated Web Worker (the
default) or on the page’s main thread, and exposes it as a standard
WavelengthClient. createWebWalletEngine()
wraps that client in a WalletEngine
in one call, which is the entry point most apps want. It also ships the
browser (WebAuthn/PRF) passkey ceremony.
Configuration
defaultConfig
functionReturns a ready-to-use RuntimeConfig for a network, preloaded with the
canonical public REST gateway endpoints the web transport dials, merged with
any overrides. This is a shallow merge of top-level RuntimeConfig fields.
Pass overrides to set dataDir or point at your own infrastructure.
function defaultConfig( network: PresetNetwork, overrides?: Partial<RuntimeConfig>,): RuntimeConfig| Parameter | Type | Description |
|---|---|---|
network | PresetNetwork | The Bitcoin network to run against; mainnet and regtest are excluded because they have no preset. Use signet for development and testing. |
overrides | Partial<RuntimeConfig> | Optional. Fields that override the network preset's defaults. Default: {}. |
RuntimeConfigA complete configuration object for client.start() or the engine factory’s config.
import { defaultConfig } from '@lightninglabs/wavelength-web';
const config = defaultConfig('signet', { dataDir: 'my-wallet' });'mainnet' and 'regtest' are not accepted: mainnet has no public
deployment yet, and regtest’s local ports vary per development environment.
Build their RuntimeConfig by hand, mainnet with your own gateway URLs and
allowMainnet, regtest with local URLs and the insecure-transport flags.
On web, arkServerAddress and swapServerAddress are REST URLs, and
walletEsploraUrl is an HTTP Esplora endpoint. The web transport rejects
arkServerTlsCertPath. It accepts swapServerTlsCertPath only when
disableSwaps: true, which suppresses every swap field.
The per-network endpoint values are on the
wavelength-core reference.
Creating a client
createWebClient
functionCreates and returns a WavelengthClient that runs the embedded daemon in the
browser. Call once at application startup, then wrap it with
createWalletEngine from @lightninglabs/wavelength-core (or use
createWebWalletEngine below to do both in one call)
or call start(defaultConfig(network)) directly. Defaults to the Web Worker
transport (WorkerWavelengthClient); pass runtimeThread: 'main' to run on the page’s main thread instead.
function createWebClient( options?: WebClientOptions,): WavelengthClient| Parameter | Type | Description |
|---|---|---|
options | WebClientOptions | Optional browser-specific settings. Defaults to worker-thread mode with page-relative runtime assets. |
WavelengthClientA live client instance. Call ready() to wait for the WASM runtime to load, then start(config) to boot the daemon.
WebClientOptions
typeBrowser-specific options for createWebClient. The config passed to
client.start() is separate: use defaultConfig(network) from
@lightninglabs/wavelength-web.
type WebClientOptions = { workerURL?: string; runtimeBaseUrl?: string; runtimeThread?: RuntimeThread; debug?: boolean;};| Parameter | Type | Description |
|---|---|---|
workerURL | string | Overrides the worker entry point. By default the worker client spawns the worker its bundler emits from new URL("./wavewalletdk-worker.js", import.meta.url); pass this to point at a custom-hosted copy instead. runtimeBaseUrl is still forwarded to the worker even when this is set. Default: bundler-emitted worker URL. |
runtimeBaseUrl | string | Base URL the daemon runtime binaries (wavewalletdk.wasm.gz, wasm_exec.js, sqlite-*.js) are resolved against. Unset resolves relative to the document: worker mode computes the document base URL and forwards it to the worker so it resolves page-relative just like main-thread mode. Default: unset (page-relative). |
runtimeThread | RuntimeThread | Which thread runs the WASM runtime. 'main' produces a MainThreadWavelengthClient that blocks rendering while busy; use it only when Worker support is unavailable. Default: 'worker'. |
debug | boolean | Logs every RPC request and response payload to the console. Payloads can include addresses and amounts, so treat this as a development-only aid and never enable it in a shipped app. Main-thread mode logs facade calls directly; worker mode forwards the flag into the worker so it can log there too. Default: false. |
RuntimeThread
typeSelects which thread the wasm runtime runs on: 'worker' (default) in a
dedicated Web Worker that keeps the UI thread free, or 'main' on the page’s
main thread as an escape hatch (for example, environments without Worker
support).
type RuntimeThread = 'main' | 'worker';Creating an engine
createWebWalletEngine
functionCreates a WalletEngine over the browser/wasm transport: the one-call setup for a web app. It builds the client with createWebClient() internally, so you only need this one factory. Pass the result to WavelengthProvider from wavelength-react, or drive it directly without React.
function createWebWalletEngine( options?: WebWalletEngineOptions,): WalletEngine| Parameter | Type | Description |
|---|---|---|
options | WebWalletEngineOptions | Optional. The same browser-specific settings as createWebClient, plus the engine's config and autoStart. |
WalletEngineA live engine driving a freshly built web client. See WalletEngine for its full behavior, including the background processes it runs automatically.
WebWalletEngineOptions
The browser-specific settings from WebClientOptions combined with WalletEngineOptions’s config/autoStart union (minus client, which this factory builds for you): the types require a config when autoStart is enabled, so autoStart: true without config is a compile error.
type WebWalletEngineOptions = WebClientOptions & ( | { config: RuntimeConfig; autoStart: true } | { config?: RuntimeConfig; autoStart?: false } );| Parameter | Type | Description |
|---|---|---|
workerURL | string | Same as WebClientOptions.workerURL. |
runtimeBaseUrl | string | Same as WebClientOptions.runtimeBaseUrl. |
runtimeThread | RuntimeThread | Same as WebClientOptions.runtimeThread. |
debug | boolean | Same as WebClientOptions.debug. |
config | RuntimeConfig | Required when autoStart is true. Default runtime config used by autoStart and by the engine's start() when called with no argument. |
autoStart | true | false | Optional. Start the runtime automatically once it is ready. Setting it to true requires config. |
import { createWebWalletEngine, defaultConfig } from '@lightninglabs/wavelength-web';import { WavelengthProvider } from '@lightninglabs/wavelength-react';
const engine = createWebWalletEngine({ runtimeBaseUrl: 'https://your-host/wavewalletdk/', config: defaultConfig('signet'), autoStart: true,});
export function Root() { return <WavelengthProvider engine={engine}>{/* your app */}</WavelengthProvider>;}Transports
MainThreadWavelengthClient
classRuns the wasm runtime on the page’s main thread. It implements
WavelengthClient directly and is
the escape hatch for environments without Web Worker support (or where
main-thread execution is preferred for another reason). Unlike worker mode it
blocks rendering while the runtime is busy.
class MainThreadWavelengthClient implements WavelengthClient { constructor(options?: WebClientOptions);}| Parameter | Type | Description |
|---|---|---|
options | WebClientOptions | Same options accepted by createWebClient. runtimeThread is ignored here since the constructor already picks the main thread. |
Prefer createWebClient({ runtimeThread: 'main' }) over constructing this
class directly; only reach for the class import when you need to branch
construction logic yourself (for example, feature-detecting Worker support at
runtime).
WorkerWavelengthClient is the default transport returned by createWebClient()
(when runtimeThread is unset or 'worker'). It is not exported directly,
select it via createWebClient(). Worker mode requires a daemon that stores
the encrypted seed in OPFS rather than localStorage (which is window-only
and unavailable inside a Worker); the daemon shipped with this package already
does this. See the browser support guide for
which browsers provide OPFS and the other APIs worker mode depends on.
Runtime assets and hosting
RUNTIME_ASSETS
constThe canonical set of daemon runtime binaries the wasm client loads at
runtime, resolved against runtimeBaseUrl. RUNTIME_ASSET_FILES is just
Object.values(RUNTIME_ASSETS). This set is built by wavelength (make wasm-wallet) and version-locked to the embedded wavelength daemon, so the
files must be hosted side by side at one base URL.
const RUNTIME_ASSETS: { wasm: string; wasmGz: string; wasmExec: string; sqliteBridge: string; sqliteWorker: string; sqlite: string; sqliteWasm: string; sqliteOpfsProxy: string;};The values are fixed filenames, not just string-typed placeholders:
| Key | Filename |
|---|---|
wasm |
wavewalletdk.wasm |
wasmGz |
wavewalletdk.wasm.gz |
wasmExec |
wasm_exec.js |
sqliteBridge |
sqlite-bridge.js |
sqliteWorker |
sqlite-worker.js |
sqlite |
sqlite3.js |
sqliteWasm |
sqlite3.wasm |
sqliteOpfsProxy |
sqlite3-opfs-async-proxy.js |
RUNTIME_ASSET_FILES
constFlat list of every runtime binary that must be hosted together at
runtimeBaseUrl: wavewalletdk.wasm, wavewalletdk.wasm.gz, wasm_exec.js,
sqlite-bridge.js, sqlite-worker.js, sqlite3.js, sqlite3.wasm,
sqlite3-opfs-async-proxy.js (that is, Object.values(RUNTIME_ASSETS)). Host
these files and point runtimeBaseUrl at them before calling
client.ready().
const RUNTIME_ASSET_FILES: readonly string[];RUNTIME_MANIFEST_VERSION
constThe daemon build this SDK release is paired with: the generated types, the
client methods, and the runtime asset set all come from this one daemon
revision. Hosted asset sets live in a directory named after this value, so a
version bump changes every asset URL and browsers can never serve a stale
cached runtime. Defined in (and re-exported from)
@lightninglabs/wavelength-core.
const RUNTIME_MANIFEST_VERSION: string;Asset resolution and loading
runtimeBaseUrl controls where each file in RUNTIME_ASSETS is fetched
from:
- Trailing slash: a base URL is normalized by appending a trailing slash
if missing before resolving each asset name against it, so
https://assets.example.com/wavewalletdkandhttps://assets.example.com/wavewalletdk/behave the same. - Unset base: with no
runtimeBaseUrl, the bare filename is used and resolves relative to the document. In worker mode the worker cannot resolve page-relative paths itself, so the client computes the document’s base URL (document.baseURI) on the main thread and forwards it to the worker as part of its$initmessage, keeping worker mode and main-thread mode page-relative in the same way. - Compressed-first wasm loading: the client prefers the gzip-compressed
wavewalletdk.wasm.gzbinary, inflating it through aDecompressionStreamand instantiating the resulting bytes, when the browser supportsDecompressionStream. If that path fails (or the API is unavailable), it falls back to fetching the uncompressedwavewalletdk.wasmand instantiating it viaWebAssembly.instantiateStreaming. - Streaming-to-ArrayBuffer fallback:
instantiateStreamingrequires the server to serve the wasm response with anapplication/wasmcontent type. If the host is misconfigured and omits it, streaming instantiation throws and the client retries by reading the same response into anArrayBufferand callingWebAssembly.instantiateon the bytes directly, so a misconfigured MIME type does not break self-hosted runtimes. - Worker entry resolution: the worker script itself (unlike the daemon
binaries above) ships inside
@lightninglabs/wavelength-weband is emitted by your bundler vianew URL('../wavewalletdk-worker.js', import.meta.url), so it versions with the SDK and needs no separate hosting.runtimeBaseUrlis still forwarded to the worker (via its$initmessage) even when you override the worker entry point withworkerURL, since the two settings are independent:workerURLonly changes where the worker script itself loads from.
See the hosting runtime assets guide for a complete self-hosting walkthrough.
Passkeys (browser)
webPasskeyCeremony
constBrowser (WebAuthn/PRF) implementation of the
PasskeyCeremony contract. It is
literally the three standalone functions below grouped into one object; pass
it to useWalletPasskey from wavelength-react, or call the functions directly.
const webPasskeyCeremony: PasskeyCeremony;const webPasskeyCeremony: PasskeyCeremony = { supportsPasskeyPrf, registerPasskeyWallet, assertPasskeyPrf,};supportsPasskeyPrf
functionReports whether a user-verifying platform authenticator is available, which is a prerequisite for WebAuthn PRF.
function supportsPasskeyPrf(): Promise<boolean>;Promise<boolean>true when a platform authenticator that can perform user verification is available.
registerPasskeyWallet
functionCreates a new platform passkey and returns its PRF output and credential id.
Some browsers do not surface the PRF result from create(), so this falls
back to an assertion scoped to the just-created credential to read it
reliably without prompting a chooser.
function registerPasskeyWallet( appName: string,): Promise<PasskeyAssertion>;| Parameter | Type | Description |
|---|---|---|
appName | string | Used as both the WebAuthn relying-party name (rp.name) and the account display name shown by the platform passkey UI. |
Promise<PasskeyAssertion>The new credential’s PRF output and credential id. Rejects if registration is cancelled.
assertPasskeyPrf
functionAuthenticates with a passkey and returns its PRF output plus the credential id used.
function assertPasskeyPrf( allowCredentialId?: string,): Promise<PasskeyAssertion>;| Parameter | Type | Description |
|---|---|---|
allowCredentialId | string | Optional. When set, the assertion is scoped to that one credential (base64url id from a prior PasskeyAssertion.credentialId) so the OS unlocks it directly without a chooser. When omitted, the assertion is discoverable (an empty allowCredentials list) so a synced passkey can be offered even on a device that has never seen this wallet. |
Promise<PasskeyAssertion>The asserted credential’s PRF output and credential id. Rejects if authentication is cancelled.
PasskeyAssertion
typeResult of a passkey registration or assertion ceremony. Defined in
@lightninglabs/wavelength-core
and surfaced here through the re-export (see the callout at the top of this
page); shown in full because it is the return type of the two functions
above.
type PasskeyAssertion = { prfOutput: string; credentialId: string;};| Parameter | Type | Description |
|---|---|---|
prfOutput | string | The WebAuthn PRF extension output, as a lower-case hex string. |
credentialId | string | The base64url-encoded WebAuthn credential id. Safe to persist and pass back into assertPasskeyPrf(allowCredentialId) to scope a later assertion to this credential. |
Reproducibility. Both functions evaluate the PRF extension against a
fixed salt, SHA-256("wavewalletdk-passkey:v1"), a fixed namespace chosen
client-side. Using the same fixed salt on every
device/platform is what makes the derived wallet reproducible: asserting the
same passkey anywhere yields the same prfOutput, and therefore the same
derived wallet.
Discoverable vs. scoped assertions. assertPasskeyPrf() called with no
argument performs a discoverable assertion (empty allowCredentials),
letting the platform’s passkey chooser surface any matching synced passkey,
including on a device that has never seen this wallet before. Passing
allowCredentialId instead performs a scoped assertion limited to that one
credential, which lets the OS unlock it directly without showing a chooser.
Re-exported from wavelength-core
Types like SendRequest and ReceiveRequest referenced by
WavelengthClient methods
(send, prepareSend, receive, and so on) originate in
@lightninglabs/wavelength-core and are available
here only because wavelength-web re-exports the entire core package (see the
callout at the top of this page). The .d.ts filename shown in each
signature below is illustrative of the shape, not of which package physically
declares the type.
SendRequest
typeParameters accepted by prepareSend() and send(). SendRequest is a
discriminated union: provide invoice for a Lightning send, or
onchainAddress for an on-chain send. The two branches are mutually
exclusive; sweepAll exists only on the on-chain branch.
type SendRequest = | { invoice: string; amountSat?: number; note?: string; maxFeeSat?: number; } | { onchainAddress: string; amountSat?: number; sweepAll?: boolean; note?: string; maxFeeSat?: number; };| Parameter | Type | Description |
|---|---|---|
invoice | string | BOLT11 lightning invoice to pay. Mutually exclusive with onchainAddress. |
onchainAddress | string | Bech32 Bitcoin address for an on-chain send. Mutually exclusive with invoice. |
amountSat | number | Required at runtime for on-chain sends unless sweepAll is true; the TypeScript type does not enforce this. |
note | string | Optional memo stored with the activity entry. |
maxFeeSat | number | Optional fee ceiling for the send. |
sweepAll | boolean | Drain every live VTXO to onchainAddress. Only present on the on-chain branch. |
ReceiveRequest
typeParameters accepted by receive().
type ReceiveRequest = { amountSat: number; memo?: string;};| Parameter | Type | Description |
|---|---|---|
amountSat | number | Invoice amount in satoshis. |
memo | string | Optional description embedded in the invoice. |
See also
- wavelength-core reference for
WavelengthClient,WalletEngine,RuntimeConfig,WalletInfo,Balance,Entry, and every other re-exported type. - wavelength-react reference for
WavelengthProviderand the hooks that consume an engine created here. - Hosting runtime assets for a full self-hosting walkthrough of the files listed above.