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

function

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

wavelength-web.d.ts
function defaultConfig(
network: PresetNetwork,
overrides?: Partial<RuntimeConfig>,
): RuntimeConfig
ParameterTypeDescription
networkPresetNetworkThe Bitcoin network to run against; mainnet and regtest are excluded because they have no preset. Use signet for development and testing.
overridesPartial<RuntimeConfig>Optional. Fields that override the network preset's defaults. Default: {}.
ReturnsRuntimeConfig

A 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

function

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

wavelength-web.d.ts
function createWebClient(
options?: WebClientOptions,
): WavelengthClient
ParameterTypeDescription
optionsWebClientOptionsOptional browser-specific settings. Defaults to worker-thread mode with page-relative runtime assets.
ReturnsWavelengthClient

A live client instance. Call ready() to wait for the WASM runtime to load, then start(config) to boot the daemon.

WebClientOptions

type

Browser-specific options for createWebClient. The config passed to client.start() is separate: use defaultConfig(network) from @lightninglabs/wavelength-web.

wavelength-web.d.ts
type WebClientOptions = {
workerURL?: string;
runtimeBaseUrl?: string;
runtimeThread?: RuntimeThread;
debug?: boolean;
};
ParameterTypeDescription
workerURLstringOverrides 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.
runtimeBaseUrlstringBase 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).
runtimeThreadRuntimeThreadWhich thread runs the WASM runtime. 'main' produces a MainThreadWavelengthClient that blocks rendering while busy; use it only when Worker support is unavailable. Default: 'worker'.
debugbooleanLogs 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

type

Selects 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).

wavelength-web.d.ts
type RuntimeThread = 'main' | 'worker';

Creating an engine

createWebWalletEngine

function

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

wavelength-web.d.ts
function createWebWalletEngine(
options?: WebWalletEngineOptions,
): WalletEngine
ParameterTypeDescription
optionsWebWalletEngineOptionsOptional. The same browser-specific settings as createWebClient, plus the engine's config and autoStart.
ReturnsWalletEngine

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

wavelength-web.d.ts
type WebWalletEngineOptions = WebClientOptions &
(
| { config: RuntimeConfig; autoStart: true }
| { config?: RuntimeConfig; autoStart?: false }
);
ParameterTypeDescription
workerURLstringSame as WebClientOptions.workerURL.
runtimeBaseUrlstringSame as WebClientOptions.runtimeBaseUrl.
runtimeThreadRuntimeThreadSame as WebClientOptions.runtimeThread.
debugbooleanSame as WebClientOptions.debug.
configRuntimeConfigRequired when autoStart is true. Default runtime config used by autoStart and by the engine's start() when called with no argument.
autoStarttrue | falseOptional. Start the runtime automatically once it is ready. Setting it to true requires config.
main.tsx
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

class

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

wavelength-web.d.ts
class MainThreadWavelengthClient implements WavelengthClient {
constructor(options?: WebClientOptions);
}
ParameterTypeDescription
optionsWebClientOptionsSame 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

const

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

wavelength-web.d.ts
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

const

Flat 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().

wavelength-web.d.ts
const RUNTIME_ASSET_FILES: readonly string[];

RUNTIME_MANIFEST_VERSION

const

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

wavelength-web.d.ts
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/wavewalletdk and https://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 $init message, 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.gz binary, inflating it through a DecompressionStream and instantiating the resulting bytes, when the browser supports DecompressionStream. If that path fails (or the API is unavailable), it falls back to fetching the uncompressed wavewalletdk.wasm and instantiating it via WebAssembly.instantiateStreaming.
  • Streaming-to-ArrayBuffer fallback: instantiateStreaming requires the server to serve the wasm response with an application/wasm content type. If the host is misconfigured and omits it, streaming instantiation throws and the client retries by reading the same response into an ArrayBuffer and calling WebAssembly.instantiate on 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-web and is emitted by your bundler via new URL('../wavewalletdk-worker.js', import.meta.url), so it versions with the SDK and needs no separate hosting. runtimeBaseUrl is still forwarded to the worker (via its $init message) even when you override the worker entry point with workerURL, since the two settings are independent: workerURL only changes where the worker script itself loads from.

See the hosting runtime assets guide for a complete self-hosting walkthrough.

Passkeys (browser)

webPasskeyCeremony

const

Browser (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.

wavelength-web.d.ts
const webPasskeyCeremony: PasskeyCeremony;
const webPasskeyCeremony: PasskeyCeremony = {
supportsPasskeyPrf,
registerPasskeyWallet,
assertPasskeyPrf,
};

supportsPasskeyPrf

function

Reports whether a user-verifying platform authenticator is available, which is a prerequisite for WebAuthn PRF.

wavelength-web.d.ts
function supportsPasskeyPrf(): Promise<boolean>;
ReturnsPromise<boolean>

true when a platform authenticator that can perform user verification is available.

registerPasskeyWallet

function

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

wavelength-web.d.ts
function registerPasskeyWallet(
appName: string,
): Promise<PasskeyAssertion>;
ParameterTypeDescription
appNamestringUsed as both the WebAuthn relying-party name (rp.name) and the account display name shown by the platform passkey UI.
ReturnsPromise<PasskeyAssertion>

The new credential’s PRF output and credential id. Rejects if registration is cancelled.

assertPasskeyPrf

function

Authenticates with a passkey and returns its PRF output plus the credential id used.

wavelength-web.d.ts
function assertPasskeyPrf(
allowCredentialId?: string,
): Promise<PasskeyAssertion>;
ParameterTypeDescription
allowCredentialIdstringOptional. 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.
ReturnsPromise<PasskeyAssertion>

The asserted credential’s PRF output and credential id. Rejects if authentication is cancelled.

PasskeyAssertion

type

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

wavelength-core.d.ts
type PasskeyAssertion = {
prfOutput: string;
credentialId: string;
};
ParameterTypeDescription
prfOutputstringThe WebAuthn PRF extension output, as a lower-case hex string.
credentialIdstringThe 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

type

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

wavelength-web.d.ts
type SendRequest =
| {
invoice: string;
amountSat?: number;
note?: string;
maxFeeSat?: number;
}
| {
onchainAddress: string;
amountSat?: number;
sweepAll?: boolean;
note?: string;
maxFeeSat?: number;
};
ParameterTypeDescription
invoicestringBOLT11 lightning invoice to pay. Mutually exclusive with onchainAddress.
onchainAddressstringBech32 Bitcoin address for an on-chain send. Mutually exclusive with invoice.
amountSatnumberRequired at runtime for on-chain sends unless sweepAll is true; the TypeScript type does not enforce this.
notestringOptional memo stored with the activity entry.
maxFeeSatnumberOptional fee ceiling for the send.
sweepAllbooleanDrain every live VTXO to onchainAddress. Only present on the on-chain branch.

ReceiveRequest

type

Parameters accepted by receive().

wavelength-web.d.ts
type ReceiveRequest = {
amountSat: number;
memo?: string;
};
ParameterTypeDescription
amountSatnumberInvoice amount in satoshis.
memostringOptional description embedded in the invoice.

See also