@bwalletx/connect 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/discover.ts","../src/pair.ts","../src/in-order.ts","../src/protocol.ts","../src/signin.ts","../src/button.ts","../src/element.ts"],"sourcesContent":["export { findBwalletX, discoverBwalletX, BWALLETX_RDNS, RDNS_EXTENSION, RDNS_MOBILE } from './discover.js';\nexport type { FoundWallet, FoundBy } from './discover.js';\nexport { pairBwalletX, restorePairing, clearPairing } from './pair.js';\nexport type { PairingOptions, PairConnectionOptions, PairStorage, PairedWallet, SocketLike, SocketFactory } from './pair.js';\nexport { signInWithBwalletX, connectBwalletX, LOGIN_PROTOCOL } from './signin.js';\nexport type { Challenge, SignInOptions, SignInResult, SignInMethod } from './signin.js';\nexport { renderButton, LOGO_URL } from './button.js';\nexport type { ButtonOptions } from './button.js';\nexport { inOrder } from './in-order.js';\nexport { defineBwalletxSignin, buildAuthorizeUrl, signinText, markSvg, SIGNIN_TAG, SIGNIN_CSS, GET_URL, WEB_WALLET_URL } from './element.js';\nexport type { SigninSize, SigninTheme, SigninLabel, SigninBrand, AuthorizeParams } from './element.js';\n","import type { WalletInterface } from '@bsv/sdk';\n\n/** Ids bWalletX announces in BRC-100 wallet discovery. */\nexport const RDNS_EXTENSION = 'com.bwalletx.extension';\nexport const RDNS_MOBILE = 'space.bwallet.mobile';\nexport const BWALLETX_RDNS = [RDNS_EXTENSION, RDNS_MOBILE] as const;\n\nexport type FoundBy = 'extension' | 'in-app';\n\nexport interface FoundWallet {\n wallet: WalletInterface;\n /** 'extension' for the Chrome extension; 'in-app' inside the bWalletX app's own browser. */\n method: FoundBy;\n rdns: string | null;\n}\n\n/**\n * Like findBwalletX, but also says which bWalletX answered.\n * Order: a BRC-100 announcement with a bWalletX rdns; then `window.CWI` (set by the in-app\n * browser, and by older builds that do not announce); otherwise null.\n */\nexport function discoverBwalletX(ms = 1200): Promise<FoundWallet | null> {\n if (typeof window === 'undefined') return Promise.resolve(null);\n return new Promise((resolve) => {\n let done = false;\n const finish = (r: FoundWallet | null) => {\n if (done) return;\n done = true;\n window.removeEventListener('brc100:announceWallet', onAnnounce);\n resolve(r);\n };\n const onAnnounce = (e: Event) => {\n const d = (e as CustomEvent).detail as { info?: { rdns?: string }; wallet?: WalletInterface } | undefined;\n const rdns = d?.info?.rdns ?? '';\n if (d?.wallet && (BWALLETX_RDNS as readonly string[]).includes(rdns)) {\n finish({ wallet: d.wallet, method: rdns === RDNS_EXTENSION ? 'extension' : 'in-app', rdns });\n }\n };\n window.addEventListener('brc100:announceWallet', onAnnounce);\n window.dispatchEvent(new Event('brc100:requestWallet'));\n setTimeout(() => {\n const cwi = (window as unknown as { CWI?: WalletInterface }).CWI;\n finish(cwi ? { wallet: cwi, method: 'in-app', rdns: null } : null);\n }, ms);\n });\n}\n\n/**\n * Find bWalletX in this page: the extension on a computer, or the wallet itself when the page is\n * open in bWalletX's in-app browser. Resolves null if nothing answered within `ms`.\n */\nexport async function findBwalletX(ms = 1200): Promise<WalletInterface | null> {\n return (await discoverBwalletX(ms))?.wallet ?? null;\n}\n","import { PrivateKey, type WalletInterface } from '@bsv/sdk';\nimport { inOrder } from './in-order.js';\nimport {\n DEFAULT_RELAY,\n PAIR_VERSION,\n QR_LIFETIME_S,\n Sealer,\n deriveSession,\n isSealed,\n newChannel,\n pairUrl,\n relaySocketUrl,\n type HelloFrame,\n type PairMessage,\n} from './protocol.js';\n\n/** localStorage-shaped storage. Methods may be sync or async. */\nexport interface PairStorage {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\n/** The minimum of the browser WebSocket API this package uses (the `ws` package also fits). */\nexport interface SocketLike {\n readonly readyState: number;\n onopen: ((ev: unknown) => void) | null;\n onmessage: ((ev: { data: unknown }) => void) | null;\n onerror: ((ev: unknown) => void) | null;\n onclose: ((ev: unknown) => void) | null;\n send(data: string): void;\n close(): void;\n}\nexport type SocketFactory = (url: string) => SocketLike;\n\nexport interface PairConnectionOptions {\n /** Where the pairing is kept so it survives a reload. Default: localStorage, else memory only. */\n storage?: PairStorage | null;\n /** Storage key. Default 'bwalletx.connect.pairing.v1'. */\n storageKey?: string;\n /** Opens a socket. Default: the global WebSocket. Pass one to run in Node or to test. */\n socket?: SocketFactory;\n /** Per-call timeout in ms. Default 120000. */\n callTimeoutMs?: number;\n}\n\nexport interface PairingOptions extends PairConnectionOptions {\n /** Show this link as a QR code, and as text to copy (web.bwalletx.com takes it pasted). */\n onLink: (link: string) => void;\n /** Show this 4-digit code. The wallet shows the same one; the user checks they match. */\n onCode: (code: string) => void;\n signal?: AbortSignal;\n /** Relay host. Default relay.bwallet.space. */\n relay?: string;\n /** This page's origin, as the relay will see it. Default location.origin. */\n origin?: string;\n}\n\n/** A BRC-100 wallet whose every call goes, end-to-end encrypted, to the paired phone or web wallet. */\nexport type PairedWallet = WalletInterface & {\n /** Close the relay connection. The pairing stays stored; the next call reconnects. */\n close(): void;\n /** Tell the wallet to unpair, close, and delete the stored pairing. */\n forget(): Promise<void>;\n};\n\ninterface StoredPairing {\n v: 1;\n c: string; // channel\n r: string; // relay host\n s: string; // our pairing private key (hex). Random; not a wallet key.\n k: string; // the wallet's pairing public key\n sent: number;\n lastSeen: number;\n pairedAt: number;\n}\n\nconst DEFAULT_KEY = 'bwalletx.connect.pairing.v1';\nconst OPEN = 1;\n\nfunction memoryStorage(): PairStorage {\n const m = new Map<string, string>();\n return { getItem: (k) => m.get(k) ?? null, setItem: (k, v) => void m.set(k, v), removeItem: (k) => void m.delete(k) };\n}\n\nfunction defaultStorage(): PairStorage {\n try {\n if (typeof localStorage !== 'undefined') return localStorage;\n } catch {\n /* blocked storage */\n }\n return memoryStorage();\n}\n\nfunction defaultSocket(): SocketFactory {\n return (url) => {\n if (typeof WebSocket === 'undefined') throw new Error('No WebSocket here. Pass options.socket.');\n return new WebSocket(url) as unknown as SocketLike;\n };\n}\n\nfunction parseStored(raw: string | null): StoredPairing | null {\n if (!raw) return null;\n try {\n const p = JSON.parse(raw) as Partial<StoredPairing>;\n const n = (x: unknown) => Number.isInteger(x) && (x as number) >= 0;\n if (p.v !== 1) return null;\n if (typeof p.c !== 'string' || !/^[A-Za-z0-9_-]{22}$/.test(p.c)) return null;\n if (typeof p.r !== 'string' || !/^[a-z0-9.-]+(:\\d+)?$/i.test(p.r)) return null;\n if (typeof p.s !== 'string' || !/^[0-9a-f]{64}$/i.test(p.s)) return null;\n if (typeof p.k !== 'string' || !/^0[23][0-9a-f]{64}$/i.test(p.k)) return null;\n if (!n(p.sent) || !n(p.lastSeen) || !n(p.pairedAt)) return null;\n return p as StoredPairing;\n } catch {\n return null;\n }\n}\n\nclass Link {\n private ws: SocketLike | null = null;\n private opening: Promise<void> | null = null;\n private waiting = new Map<string, { resolve: (v: unknown) => void; reject: (e: Error) => void; timer: ReturnType<typeof setTimeout> }>();\n private forgotten = false;\n\n constructor(\n private p: StoredPairing,\n private sealer: Sealer,\n private storage: PairStorage,\n private key: string,\n private socket: SocketFactory,\n private timeoutMs: number,\n ) {}\n\n /** Take over a socket that is already open (the one pairing used). */\n adopt(ws: SocketLike) {\n this.ws = ws;\n this.wire(ws);\n }\n\n private wire(ws: SocketLike) {\n ws.onmessage = inOrder((ev: { data: unknown }) => this.onFrame(String(ev.data)));\n ws.onerror = null;\n ws.onclose = () => {\n if (this.ws === ws) this.ws = null;\n this.failAll(new Error('The connection to bWalletX closed'));\n };\n }\n\n private persist() {\n if (this.forgotten) return;\n this.p = { ...this.p, ...this.sealer.counters };\n void Promise.resolve(this.storage.setItem(this.key, JSON.stringify(this.p))).catch(() => {});\n }\n\n private failAll(e: Error) {\n for (const w of this.waiting.values()) {\n clearTimeout(w.timer);\n w.reject(e);\n }\n this.waiting.clear();\n }\n\n private async ensure() {\n if (this.forgotten) throw new Error('This pairing was removed. Pair again.');\n if (this.ws && this.ws.readyState === OPEN) return;\n this.opening ??= this.reopen().finally(() => (this.opening = null));\n await this.opening;\n }\n\n private reopen() {\n // A fresh expiry lets the relay recreate the channel if it was dropped; the wallet rejoins on its own.\n const ws = this.socket(relaySocketUrl(this.p.r, this.p.c, 'site', Math.floor(Date.now() / 1000) + QR_LIFETIME_S - 10));\n return new Promise<void>((resolve, reject) => {\n ws.onopen = () => {\n this.ws = ws;\n this.wire(ws);\n resolve();\n };\n ws.onerror = () => reject(new Error('Could not reach the bWalletX pairing service'));\n ws.onclose = () => reject(new Error('Could not reach the bWalletX pairing service'));\n });\n }\n\n private async onFrame(raw: string) {\n let f: unknown;\n try {\n f = JSON.parse(raw);\n } catch {\n return;\n }\n const t = (f as { t?: string; error?: string }).t;\n if (t === 'relay' && (f as { error?: string }).error) {\n return this.failAll(new Error(`bWalletX pairing service: ${(f as { error: string }).error}`));\n }\n if (!isSealed(f)) return;\n const msg = await this.sealer.open(f);\n if (!msg) return;\n this.persist();\n if (msg.t === 'res') {\n const w = this.waiting.get(msg.id);\n if (!w) return;\n clearTimeout(w.timer);\n this.waiting.delete(msg.id);\n if (msg.error) w.reject(Object.assign(new Error(msg.error.message), { code: msg.error.code }));\n else w.resolve(msg.result);\n } else if (msg.t === 'close') {\n this.drop();\n this.failAll(new Error('bWalletX disconnected this site. Pair again.'));\n }\n }\n\n async call(action: string, params: unknown): Promise<unknown> {\n await this.ensure();\n const ws = this.ws!;\n const id = `${action}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n const result = new Promise<unknown>((resolve, reject) => {\n const timer = setTimeout(() => {\n if (this.waiting.delete(id)) reject(new Error('No answer from bWalletX. Open it, unlocked, and approve.'));\n }, this.timeoutMs);\n this.waiting.set(id, { resolve, reject, timer });\n });\n ws.send(JSON.stringify(await this.sealer.seal({ t: 'req', id, action, params } satisfies PairMessage)));\n this.persist();\n return result;\n }\n\n close() {\n const ws = this.ws;\n this.ws = null;\n ws?.close();\n }\n\n private drop() {\n this.forgotten = true;\n void Promise.resolve(this.storage.removeItem(this.key)).catch(() => {});\n this.close();\n }\n\n async forget() {\n if (this.forgotten) return;\n try {\n if (this.ws && this.ws.readyState === OPEN) {\n this.ws.send(JSON.stringify(await this.sealer.seal({ t: 'close', reason: 'site unpaired' })));\n }\n } catch {\n /* best effort */\n }\n this.drop();\n }\n\n wallet(): PairedWallet {\n return new Proxy({} as PairedWallet, {\n get: (_t, method) => {\n if (method === 'close') return () => this.close();\n if (method === 'forget') return () => this.forget();\n if (typeof method !== 'string' || method === 'then' || method === 'toJSON') return undefined;\n return (params: unknown) => this.call(method, params ?? {});\n },\n });\n }\n}\n\n/**\n * Pair with bWalletX on a phone (scan the QR) or web.bwalletx.com (paste the link).\n * Resolves with a wallet once the user taps Connect. The pairing is stored (see `storage`) so\n * `restorePairing()` can reconnect after a reload without a new QR.\n */\nexport function pairBwalletX(opts: PairingOptions): Promise<PairedWallet> {\n const storage = opts.storage === undefined ? defaultStorage() : (opts.storage ?? memoryStorage());\n const key = opts.storageKey ?? DEFAULT_KEY;\n const socket = opts.socket ?? defaultSocket();\n const relay = opts.relay ?? DEFAULT_RELAY;\n const origin = opts.origin ?? (typeof location !== 'undefined' ? location.origin : '');\n if (!origin) return Promise.reject(new Error('pairBwalletX needs options.origin outside a browser'));\n\n const siteKey = PrivateKey.fromRandom(); // a throwaway pairing key, not a wallet key\n const channel = newChannel();\n const expiry = Math.floor(Date.now() / 1000) + QR_LIFETIME_S;\n\n return new Promise<PairedWallet>((resolve, reject) => {\n if (opts.signal?.aborted) return reject(new Error('cancelled'));\n let ws: SocketLike;\n try {\n ws = socket(relaySocketUrl(relay, channel, 'site', expiry));\n } catch (e) {\n return reject(e);\n }\n let sealer: Sealer | null = null;\n let walletKey = '';\n let settled = false;\n const fail = (e: Error) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n ws.close();\n reject(e);\n };\n const timer = setTimeout(() => fail(new Error('The pairing code expired. Show a new one.')), QR_LIFETIME_S * 1000);\n opts.signal?.addEventListener('abort', () => fail(new Error('cancelled')));\n ws.onerror = () => fail(new Error('Could not reach the bWalletX pairing service'));\n ws.onclose = () => fail(new Error('The connection to bWalletX closed before pairing finished'));\n ws.onmessage = inOrder(async (ev: { data: unknown }) => {\n if (settled) return;\n let f: unknown;\n try {\n f = JSON.parse(String(ev.data));\n } catch {\n return;\n }\n if ((f as HelloFrame).t === 'hello' && !sealer) {\n walletKey = (f as HelloFrame).k;\n const s = await deriveSession(siteKey, walletKey, channel);\n sealer = new Sealer(s.key, 'site');\n opts.onCode(s.code);\n return;\n }\n if (!sealer || !isSealed(f)) return;\n const msg = await sealer.open(f);\n if (!msg) return;\n if (msg.t === 'ready') {\n settled = true;\n clearTimeout(timer);\n const p: StoredPairing = { v: 1, c: channel, r: relay, s: siteKey.toHex(), k: walletKey, ...sealer.counters, pairedAt: Date.now() };\n await Promise.resolve(storage.setItem(key, JSON.stringify(p))).catch(() => {});\n const link = new Link(p, sealer, storage, key, socket, opts.callTimeoutMs ?? 120_000);\n link.adopt(ws);\n resolve(link.wallet());\n } else if (msg.t === 'close') {\n fail(new Error('Pairing was declined in bWalletX'));\n }\n });\n opts.onLink(pairUrl({ v: PAIR_VERSION, r: relay, c: channel, k: siteKey.toPublicKey().toString(), o: origin, e: expiry }));\n });\n}\n\n/**\n * The wallet from a pairing stored by an earlier `pairBwalletX`, or null if there is none.\n * It connects on the first call. The wallet must still have this site paired.\n */\nexport async function restorePairing(opts: PairConnectionOptions = {}): Promise<PairedWallet | null> {\n const storage = opts.storage === undefined ? defaultStorage() : (opts.storage ?? memoryStorage());\n const key = opts.storageKey ?? DEFAULT_KEY;\n const p = parseStored(await Promise.resolve(storage.getItem(key)).catch(() => null));\n if (!p) return null;\n const { key: aes } = await deriveSession(PrivateKey.fromHex(p.s), p.k, p.c);\n const sealer = new Sealer(aes, 'site');\n sealer.restore({ sent: p.sent, lastSeen: p.lastSeen });\n return new Link(p, sealer, storage, key, opts.socket ?? defaultSocket(), opts.callTimeoutMs ?? 120_000).wallet();\n}\n\n/** Delete the stored pairing without telling the wallet. */\nexport async function clearPairing(opts: Pick<PairConnectionOptions, 'storage' | 'storageKey'> = {}) {\n const storage = opts.storage === undefined ? defaultStorage() : (opts.storage ?? memoryStorage());\n await Promise.resolve(storage.removeItem(opts.storageKey ?? DEFAULT_KEY)).catch(() => {});\n}\n","/**\n * Wrap an async frame handler so frames are handled one at a time, in arrival order.\n *\n * WebSocket `onmessage` does not wait for an async handler. The phone sends its plain `hello`\n * and then, as soon as the user taps Connect, a sealed `ready`. If the handler for `hello` is\n * still deriving the session key when `ready` arrives, a naive handler sees no key yet and drops\n * `ready`, so pairing never finishes. Chaining every frame onto one promise fixes that.\n */\nexport function inOrder<T>(handle: (frame: T) => Promise<void> | void, onError?: (e: unknown) => void) {\n let queue: Promise<void> = Promise.resolve();\n return (frame: T): Promise<void> => {\n queue = queue.then(() => handle(frame)).catch((e) => onError?.(e));\n return queue;\n };\n}\n","/**\n * Phone pairing protocol (tokenblaster.lol docs/wallet-connect.md §4), shared by the site side and\n * bWallet. Kept dependency-light (@bsv/sdk + WebCrypto) so the same file can be copied into sites\n * until it ships as @b0ase/wallet.\n *\n * QR: https://www.bwallet.space/pair?v=1&r=<relay host>&c=<channel>&k=<site pubkey>&o=<origin>&e=<expiry>\n * key: ECDH(secp256k1) → HKDF-SHA256(salt = channel bytes, info = \"bwallet-pair-v1\") → AES-256-GCM\n * frame: { s: seq, n: nonce b64, d: ciphertext b64 }, AAD = \"<sender role>|<s>\", s strictly increasing\n * code: first 2 bytes of SHA-256(key bits) → 4 digits, shown on both screens\n */\nimport { PrivateKey, PublicKey } from '@bsv/sdk';\n\nexport const PAIR_VERSION = '1';\nexport const PAIR_INFO = 'bwallet-pair-v1';\n// www: the bare domain redirects there, and app-link checks (Apple's AASA) don't follow redirects.\nexport const PAIR_HOST = 'www.bwallet.space';\nconst PAIR_HOSTS = new Set([PAIR_HOST, 'bwallet.space']);\nexport const DEFAULT_RELAY = 'relay.bwallet.space';\nexport const QR_LIFETIME_S = 120;\n\nexport type Role = 'site' | 'wallet';\nexport type WalletInfo = { name: string; icon?: string; rdns: string };\n\nexport type PairLink = { v: string; r: string; c: string; k: string; o: string; e: number };\n\n/** Plaintext messages inside encrypted frames. */\nexport type PairMessage =\n | { t: 'req'; id: string; action: string; params: unknown }\n | { t: 'res'; id: string; result?: unknown; error?: { code: string; message: string } }\n | { t: 'ready' }\n | { t: 'ping' }\n | { t: 'close'; reason: string };\n\n/** Unencrypted frames: from the relay, and the phone's hello (its key isn't shared yet). */\nexport type RelayFrame = { t: 'relay'; verifiedOrigin?: string; peer?: 'joined' | 'left'; role?: Role; error?: string };\nexport type HelloFrame = { t: 'hello'; k: string; info: WalletInfo };\nexport type SealedFrame = { s: number; n: string; d: string };\n\nconst enc = new TextEncoder();\nconst dec = new TextDecoder();\n\n// Chunked: String.fromCharCode(...bytes) overflows the call stack on large frames (signed transactions).\nconst binary = (bytes: Uint8Array) => {\n let s = '';\n for (let i = 0; i < bytes.length; i += 0x8000) s += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n return s;\n};\nexport const b64url = (bytes: Uint8Array) =>\n btoa(binary(bytes)).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\nexport const fromB64url = (s: string) => {\n const t = s.replace(/-/g, '+').replace(/_/g, '/');\n const bin = atob(t + '='.repeat((4 - (t.length % 4)) % 4));\n return Uint8Array.from(bin, (ch) => ch.charCodeAt(0));\n};\nconst b64 = (bytes: Uint8Array) => btoa(binary(bytes));\nconst fromB64 = (s: string) => Uint8Array.from(atob(s), (ch) => ch.charCodeAt(0));\n\nexport const newChannel = () => b64url(crypto.getRandomValues(new Uint8Array(16)));\n\nexport function pairUrl(link: PairLink): string {\n const q = new URLSearchParams({ v: link.v, r: link.r, c: link.c, k: link.k, o: link.o, e: String(link.e) });\n return `https://${PAIR_HOST}/pair?${q}`;\n}\n\n/** Parse a scanned QR (https link or bwallet:// fallback). Throws on anything else. */\nexport function parsePairUrl(text: string, nowS = Math.floor(Date.now() / 1000)): PairLink {\n const u = new URL(text.trim());\n const ok =\n (u.protocol === 'https:' && PAIR_HOSTS.has(u.host) && u.pathname === '/pair') ||\n (u.protocol === 'bwallet:' && /pair/.test(u.href));\n if (!ok) throw new Error('Not a bWallet pairing code');\n const g = (k: string) => u.searchParams.get(k) ?? '';\n const link: PairLink = { v: g('v'), r: g('r'), c: g('c'), k: g('k'), o: g('o'), e: Number(g('e')) };\n if (link.v !== PAIR_VERSION) throw new Error('This pairing code needs a newer bWallet');\n if (!/^[A-Za-z0-9_-]{22}$/.test(link.c)) throw new Error('Bad pairing code');\n if (!/^0[23][0-9a-f]{64}$/i.test(link.k)) throw new Error('Bad pairing code');\n if (!/^[a-z0-9.-]+(:\\d+)?$/i.test(link.r)) throw new Error('Bad pairing code');\n const o = new URL(link.o);\n if (o.origin !== link.o) throw new Error('Bad pairing code');\n if (!Number.isFinite(link.e) || link.e < nowS) throw new Error('This code has expired. Ask the site for a new one.');\n return link;\n}\n\nexport const relaySocketUrl = (relay: string, channel: string, role: Role, expiry?: number) => {\n const local = /^(localhost|127\\.0\\.0\\.1)(:\\d+)?$/.test(relay);\n const q = new URLSearchParams({ role });\n if (expiry) q.set('e', String(expiry));\n return `${local ? 'ws' : 'wss'}://${relay}/v1/c/${channel}?${q}`;\n};\n\n/** Shared AES key + 4-digit comparison code from my private key and their public key. */\nexport async function deriveSession(mine: PrivateKey, theirs: string, channel: string) {\n const point = mine.deriveSharedSecret(PublicKey.fromString(theirs));\n const ikm = new Uint8Array(point.encode(true) as number[]);\n const base = await crypto.subtle.importKey('raw', ikm, 'HKDF', false, ['deriveBits']);\n const bits = new Uint8Array(\n await crypto.subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt: fromB64url(channel), info: enc.encode(PAIR_INFO) },\n base,\n 256,\n ),\n );\n const key = await crypto.subtle.importKey('raw', bits, 'AES-GCM', false, ['encrypt', 'decrypt']);\n const h = new Uint8Array(await crypto.subtle.digest('SHA-256', bits));\n const code = String(((h[0] << 8) | h[1]) % 10000).padStart(4, '0');\n return { key, code };\n}\n\n/** One direction-aware encrypted pipe. `me` is the sender role used in the AAD. */\nexport class Sealer {\n private sent = 0;\n private lastSeen = 0;\n constructor(\n private key: CryptoKey,\n private me: Role,\n ) {}\n\n async seal(msg: PairMessage): Promise<SealedFrame> {\n const s = ++this.sent;\n const n = crypto.getRandomValues(new Uint8Array(12));\n const ct = new Uint8Array(\n await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv: n, additionalData: enc.encode(`${this.me}|${s}`) },\n this.key,\n enc.encode(JSON.stringify(msg)),\n ),\n );\n return { s, n: b64(n), d: b64(ct) };\n }\n\n /** Decrypts a frame from the other side; null for replays, reflections or tampering. */\n async open(f: SealedFrame): Promise<PairMessage | null> {\n if (!Number.isInteger(f.s) || f.s <= this.lastSeen) return null;\n const from: Role = this.me === 'site' ? 'wallet' : 'site';\n try {\n const pt = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: fromB64(f.n), additionalData: enc.encode(`${from}|${f.s}`) },\n this.key,\n fromB64(f.d),\n );\n this.lastSeen = f.s;\n return JSON.parse(dec.decode(pt)) as PairMessage;\n } catch {\n return null;\n }\n }\n\n /** For resuming a session after a reload: continue counters where they were. */\n get counters() {\n return { sent: this.sent, lastSeen: this.lastSeen };\n }\n restore(c: { sent: number; lastSeen: number }) {\n this.sent = c.sent;\n this.lastSeen = c.lastSeen;\n }\n}\n\nexport const isSealed = (x: unknown): x is SealedFrame =>\n !!x && typeof x === 'object' && 'd' in x && 'n' in x && 's' in x;\n","import type { WalletInterface, WalletProtocol } from '@bsv/sdk';\nimport { discoverBwalletX } from './discover.js';\nimport { pairBwalletX, restorePairing, type PairingOptions } from './pair.js';\n\n/** Security level 2, a protocol name used for nothing else. */\nexport const LOGIN_PROTOCOL: WalletProtocol = [2, 'bwallet sign in'];\n\n/** What your server's challenge route returns (createChallenge from '@bwalletx/connect/server'). */\nexport interface Challenge {\n nonce: string;\n message: string;\n keyID: string;\n protocolID?: WalletProtocol;\n}\n\nexport type SignInMethod = 'extension' | 'in-app' | 'pairing' | 'wallet';\n\nexport interface SignInOptions {\n /** Ask your server for a challenge for this identity key. */\n challenge: (identityKey: string) => Promise<Challenge>;\n /** Use this wallet instead of looking for one. `method` is then 'wallet'. */\n wallet?: WalletInterface;\n /** How to show the QR and code if pairing is needed. Without it, pairing is not tried. */\n pairing?: PairingOptions;\n /** Reuse a pairing stored by an earlier sign-in before showing a new QR. Default true. */\n reusePairing?: boolean;\n /** How long to wait for the extension or in-app browser to answer, in ms. Default 1200. */\n discoverMs?: number;\n}\n\nexport interface SignInResult {\n identityKey: string;\n /** DER signature as number[], ready to post to verifySignIn. */\n signature: number[];\n nonce: string;\n method: SignInMethod;\n /** The wallet that signed. Keep it to make more calls. */\n wallet: WalletInterface;\n}\n\n/** Find a wallet: extension or in-app browser first, then a stored pairing, then a new pairing. */\nexport async function connectBwalletX(\n opts: Pick<SignInOptions, 'wallet' | 'pairing' | 'reusePairing' | 'discoverMs'> = {},\n): Promise<{ wallet: WalletInterface; method: SignInMethod }> {\n if (opts.wallet) return { wallet: opts.wallet, method: 'wallet' };\n const found = await discoverBwalletX(opts.discoverMs);\n if (found) return { wallet: found.wallet, method: found.method };\n if (opts.reusePairing !== false) {\n const restored = await restorePairing(opts.pairing ?? {});\n if (restored) return { wallet: restored, method: 'pairing' };\n }\n if (!opts.pairing) {\n throw Object.assign(new Error('bWalletX was not found in this browser'), { code: 'NOT_FOUND' });\n }\n return { wallet: await pairBwalletX(opts.pairing), method: 'pairing' };\n}\n\n/**\n * Sign the server's challenge with the user's bWalletX identity key. Post the result's\n * identityKey, nonce and signature to your verify route.\n */\nexport async function signInWithBwalletX(opts: SignInOptions): Promise<SignInResult> {\n const { wallet, method } = await connectBwalletX(opts);\n if (method !== 'pairing') await wallet.waitForAuthentication({}).catch(() => {});\n const { publicKey: identityKey } = await wallet.getPublicKey({ identityKey: true });\n const c = await opts.challenge(identityKey);\n const { signature } = await wallet.createSignature({\n protocolID: c.protocolID ?? LOGIN_PROTOCOL,\n keyID: c.keyID,\n counterparty: 'anyone',\n data: Array.from(new TextEncoder().encode(c.message)),\n });\n return { identityKey, signature: Array.from(signature), nonce: c.nonce, method, wallet };\n}\n","const CSS = `\n.bwx-signin{display:inline-flex;align-items:center;gap:12px;min-height:48px;padding:10px 22px 10px 10px;border:0;border-radius:12px;cursor:pointer;background:linear-gradient(180deg,#fcd34d,#f59e0b);color:#000;text-align:left;font:700 16px/1.2 system-ui,-apple-system,\"Segoe UI\",sans-serif;box-shadow:0 8px 24px rgba(245,158,11,.2)}\n.bwx-signin:hover{background:linear-gradient(180deg,#fde68a,#fbbf24)}\n.bwx-signin:focus-visible{outline:2px solid #ffd24d;outline-offset:3px}\n.bwx-signin:disabled{opacity:.6;cursor:wait}\n.bwx-signin .bwx-mark{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;background:#000;flex:none}\n.bwx-signin small{display:block;font-size:11px;font-weight:500;color:rgba(0,0,0,.6)}`;\n\nexport const LOGO_URL = 'https://bwalletx.com/logo.svg';\n\nexport interface ButtonOptions {\n /** Second line under the label. Default \"also works with bWallet\". false hides it. */\n subtitle?: string | false;\n onClick?: (button: HTMLButtonElement) => void;\n}\n\n/** Put the gold \"Sign in with bWalletX\" button into `el` (replacing its contents). */\nexport function renderButton(el: HTMLElement | string, opts: ButtonOptions = {}): HTMLButtonElement {\n const host = typeof el === 'string' ? document.querySelector<HTMLElement>(el) : el;\n if (!host) throw new Error(`renderButton: no element ${String(el)}`);\n if (!document.getElementById('bwx-signin-css')) {\n const style = document.createElement('style');\n style.id = 'bwx-signin-css';\n style.textContent = CSS;\n document.head.appendChild(style);\n }\n const b = document.createElement('button');\n b.type = 'button';\n b.className = 'bwx-signin';\n const mark = document.createElement('span');\n mark.className = 'bwx-mark';\n const img = document.createElement('img');\n img.src = LOGO_URL;\n img.alt = '';\n img.width = 15;\n img.height = 20;\n mark.appendChild(img);\n const label = document.createElement('span');\n label.className = 'bwx-label';\n label.textContent = 'Sign in with bWalletX';\n const sub = opts.subtitle === undefined ? 'also works with bWallet' : opts.subtitle;\n if (sub) {\n const small = document.createElement('small');\n small.textContent = sub;\n label.appendChild(small);\n }\n b.append(mark, label);\n if (opts.onClick) b.addEventListener('click', () => opts.onClick!(b));\n host.replaceChildren(b);\n return b;\n}\n","/**\n * <bwalletx-signin>: the standard \"Sign in with bWalletX\" button as a framework-free web component.\n *\n * Design reference: the gold button in bit-sign's sign-in card (src/components/BwalletSignIn.tsx):\n * amber-300 → amber-500 vertical gradient, 12px radius, 16px/20px padding, 16px bold black label,\n * 11px subtitle at 60% black, a black 28px circle holding the gold \"b\", amber shadow.\n *\n * Attributes (all optional):\n * size lg (default) | md | sm | icon\n * theme gold (default) | dark | light\n * label signin (default) | continue | connect\n * brand bWalletX (default) | bWallet (store edition text)\n * subtitle on | off | <custom text>. Default on for lg/md, off for sm/icon and for brand=\"bWallet\"\n * full-width stretch to the container\n * loading show the spinner and set aria-busy\n * disabled disable the button\n * challenge-url / verify-url run the sign-in flow on click (POST JSON, as in the README)\n * get-url where \"Get bWalletX\" points. Default https://bwalletx.com/get\n * web-url the web wallet. Default https://web.bwalletx.com\n * discover-ms how long to wait for the wallet to answer. Default 1200\n * href plain link mode: navigate here on click\n * authorize-url (+ client-id, redirect-uri, scope) OAuth mode, for auth.bwalletx.com once it exists\n *\n * Events (bubble, composed):\n * bwalletx-signin on every click, before anything else. Cancelable: preventDefault() stops the\n * built-in behaviour so you can run your own flow.\n * bwalletx-signed-in detail { identityKey, method, nonce, signature, response }\n * bwalletx-not-found no bWalletX answered; the \"Get bWalletX\" row is shown\n * bwalletx-error detail { error }\n */\nimport { discoverBwalletX } from './discover.js';\nimport { signInWithBwalletX, type Challenge } from './signin.js';\n\nexport const SIGNIN_TAG = 'bwalletx-signin';\nexport const GET_URL = 'https://bwalletx.com/get';\nexport const WEB_WALLET_URL = 'https://web.bwalletx.com';\n\nexport type SigninSize = 'lg' | 'md' | 'sm' | 'icon';\nexport type SigninTheme = 'gold' | 'dark' | 'light';\nexport type SigninLabel = 'signin' | 'continue' | 'connect';\nexport type SigninBrand = 'bWalletX' | 'bWallet';\n\nconst VERBS: Record<SigninLabel, string> = { signin: 'Sign in with', continue: 'Continue with', connect: 'Connect' };\n\n/** The visible label for a label/brand pair, e.g. \"Sign in with bWalletX\". */\nexport function signinText(label: SigninLabel = 'signin', brand: SigninBrand = 'bWalletX'): string {\n return `${VERBS[label] ?? VERBS.signin} ${brand}`;\n}\n\nlet uid = 0;\n/** The gold \"b\" (bwalletx-site/logo.svg). Ids are unique per copy so several marks can share a page. */\nexport function markSvg(px = 20): string {\n const n = ++uid;\n return `<svg viewBox=\"23 8 74 100\" width=\"${Math.round(px * 0.74)}\" height=\"${px}\" aria-hidden=\"true\" focusable=\"false\"><defs><linearGradient id=\"bwxg${n}\" gradientUnits=\"userSpaceOnUse\" x1=\"0\" y1=\"12\" x2=\"0\" y2=\"105\"><stop offset=\"0\" stop-color=\"#FFE58A\"/><stop offset=\".55\" stop-color=\"#FFD24D\"/><stop offset=\"1\" stop-color=\"#C98F00\"/></linearGradient><mask id=\"bwxh${n}\"><rect width=\"140\" height=\"140\" fill=\"#fff\"/><circle cx=\"60\" cy=\"72\" r=\"15\" fill=\"#000\"/></mask></defs><g fill=\"url(#bwxg${n})\" mask=\"url(#bwxh${n})\"><polygon points=\"45,12 45,76 27,76 27,30\"/><circle cx=\"60\" cy=\"72\" r=\"33\"/></g></svg>`;\n}\n\nexport const SIGNIN_CSS = `\n:host{display:inline-block;vertical-align:middle;font-family:Inter,ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif}\n:host([full-width]){display:block;width:100%}\n:host([hidden]){display:none}\nbutton{all:unset;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:12px;width:100%;cursor:pointer;\n padding:16px 20px;border-radius:12px;font-size:16px;font-weight:700;line-height:1.2;text-align:left;\n background:linear-gradient(180deg,#fcd34d,#f59e0b);color:#000;\n box-shadow:0 10px 15px -3px rgba(245,158,11,.2),0 4px 6px -4px rgba(245,158,11,.2);\n transition:background .15s,transform .1s,box-shadow .15s,border-color .15s;-webkit-tap-highlight-color:transparent}\nbutton:hover{background:linear-gradient(180deg,#fde68a,#fbbf24)}\nbutton:active{transform:translateY(1px);background:linear-gradient(180deg,#fbbf24,#d97706)}\nbutton:focus-visible{outline:2px solid #b45309;outline-offset:3px}\nbutton:disabled{opacity:.6;cursor:not-allowed;transform:none}\nbutton[aria-busy=true]{cursor:wait}\n.mark{display:inline-flex;align-items:center;justify-content:center;flex:none;width:28px;height:28px;border-radius:50%;background:#000}\n.txt{display:flex;flex-direction:column;align-items:flex-start;min-width:0}\n.txt b{font-weight:700;white-space:nowrap}\n.txt small{font-size:11px;font-weight:500;color:rgba(0,0,0,.65);white-space:nowrap}\n.spin{width:16px;height:16px;border-radius:50%;border:2px solid rgba(255,210,77,.35);border-top-color:#ffd24d;animation:r .8s linear infinite}\n@keyframes r{to{transform:rotate(360deg)}}\n@media (prefers-reduced-motion:reduce){button{transition:none}button:active{transform:none}.spin{animation:none;border-color:#ffd24d;border-right-color:transparent}}\n/* sizes */\n:host([size=md]) button{padding:10px 16px;border-radius:10px;font-size:15px;gap:10px}\n:host([size=md]) .mark{width:24px;height:24px}\n:host([size=md]) .txt small{font-size:10.5px}\n:host([size=sm]) button{padding:6px 12px 6px 6px;border-radius:8px;font-size:13px;gap:8px;min-height:36px}\n:host([size=sm]) .mark{width:22px;height:22px}\n:host([size=icon]) button{width:48px;height:48px;padding:0;border-radius:50%;gap:0}\n:host([size=icon]) .mark{width:34px;height:34px}\n/* themes */\n:host([theme=dark]) button{background:#0a0a0a;color:#fafafa;border:1px solid #3f3f46;box-shadow:none}\n:host([theme=dark]) button:hover{background:#18181b;border-color:rgba(251,191,36,.6)}\n:host([theme=dark]) button:active{background:#000}\n:host([theme=dark]) button:focus-visible{outline-color:#fcd34d}\n:host([theme=dark]) .mark{box-shadow:inset 0 0 0 1px #3f3f46}\n:host([theme=dark]) .txt small{color:rgba(255,255,255,.65)}\n:host([theme=light]) button{background:#fff;color:#09090b;border:1px solid #d4d4d8;box-shadow:0 1px 2px rgba(0,0,0,.06)}\n:host([theme=light]) button:hover{background:#fafafa;border-color:#f59e0b}\n:host([theme=light]) button:active{background:#f4f4f5}\n:host([theme=light]) .txt small{color:#52525b}\n/* not found */\n.nf{margin-top:8px;font-size:12px;line-height:1.4;color:#71717a;text-align:center}\n.nf a{color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px}\n.nf a:focus-visible{outline:2px solid #b45309;outline-offset:2px;border-radius:2px}\n:host([theme=dark]) .nf,:host-context(.dark) .nf{color:#a1a1aa}\n.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n`;\n\n/** Optional OAuth parameters for authorize-url mode. auth.bwalletx.com is planned, not live. */\nexport interface AuthorizeParams { authorizeUrl: string; clientId?: string | null; redirectUri?: string | null; scope?: string | null }\n\nfunction b64url(bytes: Uint8Array): string {\n let s = '';\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Build an OAuth 2.1 authorization-code + S256 PKCE redirect URL, and keep the verifier, state and\n * nonce in sessionStorage under \"bwalletx:oauth\" for your callback page. Matches the plan in\n * bit-sign docs/SIGN-IN-WITH-BWALLETX.md. The provider is not live yet.\n */\nexport async function buildAuthorizeUrl(p: AuthorizeParams): Promise<string> {\n const rnd = (n: number) => b64url(crypto.getRandomValues(new Uint8Array(n)));\n const verifier = rnd(32);\n const state = rnd(16);\n const nonce = rnd(16);\n const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier)));\n const u = new URL(p.authorizeUrl, typeof location !== 'undefined' ? location.href : undefined);\n const set = (k: string, v: string | null | undefined) => { if (v) u.searchParams.set(k, v); };\n set('response_type', 'code');\n set('client_id', p.clientId);\n set('redirect_uri', p.redirectUri);\n set('scope', p.scope || 'openid profile');\n set('state', state);\n set('nonce', nonce);\n set('code_challenge', b64url(digest));\n set('code_challenge_method', 'S256');\n try { sessionStorage.setItem('bwalletx:oauth', JSON.stringify({ verifier, state, nonce })); } catch { /* storage blocked */ }\n return u.toString();\n}\n\nasync function postJson<T>(url: string, body: unknown): Promise<T> {\n const res = await fetch(url, { method: 'POST', credentials: 'include', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) throw new Error((data as { error?: string }).error ?? `HTTP ${res.status}`);\n return data as T;\n}\n\nconst OBSERVED = ['size', 'theme', 'label', 'brand', 'subtitle', 'loading', 'disabled', 'full-width', 'aria-label', 'get-url', 'web-url'];\n\n/** The element class. Created lazily so importing this module on a server is harmless. */\nfunction createClass(): CustomElementConstructor {\n return class BwalletxSigninElement extends HTMLElement {\n static get observedAttributes() { return OBSERVED; }\n #root: ShadowRoot;\n #notFound = false;\n #busy = false;\n\n constructor() {\n super();\n this.#root = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() { this.#render(); }\n attributeChangedCallback() { if (this.isConnected) this.#render(); }\n\n /** The inner <button>, for focus() and tests. */\n get button(): HTMLButtonElement | null { return this.#root.querySelector('button'); }\n get notFound() { return this.#notFound; }\n\n focus(opts?: FocusOptions) { this.button?.focus(opts); }\n\n #attr(name: string) { return this.getAttribute(name); }\n\n #render() {\n const size = (this.#attr('size') ?? 'lg') as SigninSize;\n const brand: SigninBrand = this.#attr('brand') === 'bWallet' ? 'bWallet' : 'bWalletX';\n const text = signinText((this.#attr('label') ?? 'signin') as SigninLabel, brand);\n const subAttr = this.#attr('subtitle');\n const subDefault = brand === 'bWalletX' && (size === 'lg' || size === 'md') ? 'also works with bWallet' : null;\n const subtitle = subAttr === null || subAttr === '' || subAttr === 'on' ? (subAttr === 'on' ? 'also works with bWallet' : subDefault)\n : subAttr === 'off' ? null : subAttr;\n const loading = this.hasAttribute('loading') || this.#busy;\n const disabled = this.hasAttribute('disabled');\n const markPx = size === 'icon' ? 24 : size === 'sm' ? 15 : size === 'md' ? 17 : 20;\n const aria = this.#attr('aria-label') ?? (subtitle && size !== 'icon' ? `${text}, ${subtitle}` : text);\n const getUrl = this.#attr('get-url') ?? GET_URL;\n const webUrl = this.#attr('web-url') ?? WEB_WALLET_URL;\n\n const esc = (s: string) => s.replace(/[&<>\"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' })[c]!);\n const label = size === 'icon' ? '' : `<span class=\"txt\" part=\"text\"><b part=\"label\">${esc(text)}</b>${subtitle ? `<small part=\"subtitle\">${esc(subtitle)}</small>` : ''}</span>`;\n const mark = loading ? '<span class=\"spin\" aria-hidden=\"true\"></span>' : markSvg(markPx);\n const nf = this.#notFound\n ? `<p class=\"nf\" part=\"not-found\" role=\"status\">bWalletX wasn't found in this browser. <a href=\"${esc(getUrl)}\" target=\"_blank\" rel=\"noopener\">Get ${brand}</a> or <a href=\"${esc(webUrl)}\" target=\"_blank\" rel=\"noopener\">use the web wallet</a>.</p>`\n : '';\n this.#root.innerHTML = `<style>${SIGNIN_CSS}</style><button type=\"button\" part=\"button\" aria-label=\"${esc(aria)}\" title=\"${esc(subtitle ? `${text} (${subtitle})` : text)}\"${disabled ? ' disabled' : ''}${loading ? ' aria-busy=\"true\"' : ''}><span class=\"mark\" part=\"mark\">${mark}</span>${label}</button>${loading ? '<span class=\"sr\" role=\"status\">Connecting to bWalletX…</span>' : ''}${nf}`;\n this.button!.addEventListener('click', () => void this.#click());\n }\n\n #emit(type: string, detail?: unknown, cancelable = false) {\n return this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable }));\n }\n\n #setBusy(on: boolean) { this.#busy = on; this.#render(); }\n\n async #click() {\n if (this.hasAttribute('disabled') || this.hasAttribute('loading') || this.#busy) return;\n if (!this.#emit('bwalletx-signin', { element: this }, true)) return;\n\n const href = this.#attr('href');\n const authorizeUrl = this.#attr('authorize-url');\n if (authorizeUrl) {\n location.assign(await buildAuthorizeUrl({ authorizeUrl, clientId: this.#attr('client-id'), redirectUri: this.#attr('redirect-uri'), scope: this.#attr('scope') }));\n return;\n }\n if (href) { location.assign(href); return; }\n\n const challengeUrl = this.#attr('challenge-url');\n if (!challengeUrl) return; // event-only mode: the page runs its own flow\n\n this.#notFound = false;\n this.#setBusy(true);\n try {\n const ms = Number(this.#attr('discover-ms')) || 1200;\n const found = await discoverBwalletX(ms);\n if (!found) {\n this.#notFound = true;\n this.#emit('bwalletx-not-found');\n return;\n }\n const r = await signInWithBwalletX({ wallet: found.wallet, challenge: (identityKey) => postJson<Challenge>(challengeUrl, { identityKey }) });\n const verifyUrl = this.#attr('verify-url');\n const response = verifyUrl ? await postJson(verifyUrl, { identityKey: r.identityKey, nonce: r.nonce, signature: r.signature }) : null;\n this.#emit('bwalletx-signed-in', { identityKey: r.identityKey, method: found.method, nonce: r.nonce, signature: r.signature, response });\n } catch (error) {\n this.#emit('bwalletx-error', { error });\n } finally {\n this.#setBusy(false);\n }\n }\n };\n}\n\n/** Register <bwalletx-signin> (once). Safe to call on a server: it does nothing there. */\nexport function defineBwalletxSignin(tag = SIGNIN_TAG): CustomElementConstructor | undefined {\n if (typeof window === 'undefined' || typeof customElements === 'undefined') return undefined;\n const existing = customElements.get(tag);\n if (existing) return existing;\n const C = createClass();\n customElements.define(tag, C);\n return C;\n}\n"],"mappings":"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","names":["import_sdk","b64url"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/discover.ts","../src/pair.ts","../src/in-order.ts","../src/protocol.ts","../src/signin.ts","../src/button.ts","../src/element.ts","../src/pay.ts","../src/wallets.ts","../src/modal.ts"],"sourcesContent":["export { findBwalletX, discoverBwalletX, BWALLETX_RDNS, RDNS_EXTENSION, RDNS_MOBILE } from './discover.js';\nexport type { FoundWallet, FoundBy } from './discover.js';\nexport { pairBwalletX, restorePairing, clearPairing } from './pair.js';\nexport type { PairingOptions, PairConnectionOptions, PairStorage, PairedWallet, SocketLike, SocketFactory } from './pair.js';\nexport { signInWithBwalletX, connectBwalletX, LOGIN_PROTOCOL } from './signin.js';\nexport type { Challenge, SignInOptions, SignInResult, SignInMethod } from './signin.js';\nexport { renderButton, LOGO_URL } from './button.js';\nexport type { ButtonOptions } from './button.js';\nexport { inOrder } from './in-order.js';\nexport { defineBwalletxSignin, buildAuthorizeUrl, signinText, markSvg, SIGNIN_TAG, SIGNIN_CSS, GET_URL, WEB_WALLET_URL } from './element.js';\nexport type { SigninSize, SigninTheme, SigninLabel, SigninBrand, AuthorizeParams } from './element.js';\nexport { pay, tip, buyToken, amountInSats, resolvePaymailP2P, PaymentError, BRC29_PROTOCOL, isPaymail, isIdentityKeyHex } from './pay.js';\nexport type { PayRequest, PayResult, PayOptions, PayOutput, PaySource, LegacyPayer, Brc29Remittance, BuyTokenRequest, TokenQuote, PaymentErrorCode } from './pay.js';\nexport { discoverWallets, brc100Option, pairingOption, handcashAdapter } from './wallets.js';\nexport type { WalletOption, ConnectedWallet, WalletKind, DiscoverWalletsOptions, HandCashAdapterOptions } from './wallets.js';\nexport { pairingModal, pickWallet, qrSvg } from './modal.js';\nexport type { PairingModalOptions } from './modal.js';\n","import type { WalletInterface } from '@bsv/sdk';\n\n/** Ids bWalletX announces in BRC-100 wallet discovery. */\nexport const RDNS_EXTENSION = 'com.bwalletx.extension';\nexport const RDNS_MOBILE = 'space.bwallet.mobile';\nexport const BWALLETX_RDNS = [RDNS_EXTENSION, RDNS_MOBILE] as const;\n\nexport type FoundBy = 'extension' | 'in-app';\n\nexport interface FoundWallet {\n wallet: WalletInterface;\n /** 'extension' for the Chrome extension; 'in-app' inside the bWalletX app's own browser. */\n method: FoundBy;\n rdns: string | null;\n}\n\n/**\n * Like findBwalletX, but also says which bWalletX answered.\n * Order: a BRC-100 announcement with a bWalletX rdns; then `window.CWI` (set by the in-app\n * browser, and by older builds that do not announce); otherwise null.\n */\nexport function discoverBwalletX(ms = 1200): Promise<FoundWallet | null> {\n if (typeof window === 'undefined') return Promise.resolve(null);\n return new Promise((resolve) => {\n let done = false;\n const finish = (r: FoundWallet | null) => {\n if (done) return;\n done = true;\n window.removeEventListener('brc100:announceWallet', onAnnounce);\n resolve(r);\n };\n const onAnnounce = (e: Event) => {\n const d = (e as CustomEvent).detail as { info?: { rdns?: string }; wallet?: WalletInterface } | undefined;\n const rdns = d?.info?.rdns ?? '';\n if (d?.wallet && (BWALLETX_RDNS as readonly string[]).includes(rdns)) {\n finish({ wallet: d.wallet, method: rdns === RDNS_EXTENSION ? 'extension' : 'in-app', rdns });\n }\n };\n window.addEventListener('brc100:announceWallet', onAnnounce);\n window.dispatchEvent(new Event('brc100:requestWallet'));\n setTimeout(() => {\n const cwi = (window as unknown as { CWI?: WalletInterface }).CWI;\n finish(cwi ? { wallet: cwi, method: 'in-app', rdns: null } : null);\n }, ms);\n });\n}\n\n/**\n * Find bWalletX in this page: the extension on a computer, or the wallet itself when the page is\n * open in bWalletX's in-app browser. Resolves null if nothing answered within `ms`.\n */\nexport async function findBwalletX(ms = 1200): Promise<WalletInterface | null> {\n return (await discoverBwalletX(ms))?.wallet ?? null;\n}\n","import { PrivateKey, type WalletInterface } from '@bsv/sdk';\nimport { inOrder } from './in-order.js';\nimport {\n DEFAULT_RELAY,\n PAIR_VERSION,\n QR_LIFETIME_S,\n Sealer,\n deriveSession,\n isSealed,\n newChannel,\n pairUrl,\n relaySocketUrl,\n type HelloFrame,\n type PairMessage,\n} from './protocol.js';\n\n/** localStorage-shaped storage. Methods may be sync or async. */\nexport interface PairStorage {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\n/** The minimum of the browser WebSocket API this package uses (the `ws` package also fits). */\nexport interface SocketLike {\n readonly readyState: number;\n onopen: ((ev: unknown) => void) | null;\n onmessage: ((ev: { data: unknown }) => void) | null;\n onerror: ((ev: unknown) => void) | null;\n onclose: ((ev: unknown) => void) | null;\n send(data: string): void;\n close(): void;\n}\nexport type SocketFactory = (url: string) => SocketLike;\n\nexport interface PairConnectionOptions {\n /** Where the pairing is kept so it survives a reload. Default: localStorage, else memory only. */\n storage?: PairStorage | null;\n /** Storage key. Default 'bwalletx.connect.pairing.v1'. */\n storageKey?: string;\n /** Opens a socket. Default: the global WebSocket. Pass one to run in Node or to test. */\n socket?: SocketFactory;\n /** Per-call timeout in ms. Default 120000. */\n callTimeoutMs?: number;\n}\n\nexport interface PairingOptions extends PairConnectionOptions {\n /** Show this link as a QR code, and as text to copy (web.bwalletx.com takes it pasted). */\n onLink: (link: string) => void;\n /** Show this 4-digit code. The wallet shows the same one; the user checks they match. */\n onCode: (code: string) => void;\n signal?: AbortSignal;\n /** Relay host. Default relay.bwallet.space. */\n relay?: string;\n /** This page's origin, as the relay will see it. Default location.origin. */\n origin?: string;\n}\n\n/** A BRC-100 wallet whose every call goes, end-to-end encrypted, to the paired phone or web wallet. */\nexport type PairedWallet = WalletInterface & {\n /** Close the relay connection. The pairing stays stored; the next call reconnects. */\n close(): void;\n /** Tell the wallet to unpair, close, and delete the stored pairing. */\n forget(): Promise<void>;\n};\n\ninterface StoredPairing {\n v: 1;\n c: string; // channel\n r: string; // relay host\n s: string; // our pairing private key (hex). Random; not a wallet key.\n k: string; // the wallet's pairing public key\n sent: number;\n lastSeen: number;\n pairedAt: number;\n}\n\nconst DEFAULT_KEY = 'bwalletx.connect.pairing.v1';\nconst OPEN = 1;\n\nfunction memoryStorage(): PairStorage {\n const m = new Map<string, string>();\n return { getItem: (k) => m.get(k) ?? null, setItem: (k, v) => void m.set(k, v), removeItem: (k) => void m.delete(k) };\n}\n\nfunction defaultStorage(): PairStorage {\n try {\n if (typeof localStorage !== 'undefined') return localStorage;\n } catch {\n /* blocked storage */\n }\n return memoryStorage();\n}\n\nfunction defaultSocket(): SocketFactory {\n return (url) => {\n if (typeof WebSocket === 'undefined') throw new Error('No WebSocket here. Pass options.socket.');\n return new WebSocket(url) as unknown as SocketLike;\n };\n}\n\nfunction parseStored(raw: string | null): StoredPairing | null {\n if (!raw) return null;\n try {\n const p = JSON.parse(raw) as Partial<StoredPairing>;\n const n = (x: unknown) => Number.isInteger(x) && (x as number) >= 0;\n if (p.v !== 1) return null;\n if (typeof p.c !== 'string' || !/^[A-Za-z0-9_-]{22}$/.test(p.c)) return null;\n if (typeof p.r !== 'string' || !/^[a-z0-9.-]+(:\\d+)?$/i.test(p.r)) return null;\n if (typeof p.s !== 'string' || !/^[0-9a-f]{64}$/i.test(p.s)) return null;\n if (typeof p.k !== 'string' || !/^0[23][0-9a-f]{64}$/i.test(p.k)) return null;\n if (!n(p.sent) || !n(p.lastSeen) || !n(p.pairedAt)) return null;\n return p as StoredPairing;\n } catch {\n return null;\n }\n}\n\nclass Link {\n private ws: SocketLike | null = null;\n private opening: Promise<void> | null = null;\n private waiting = new Map<string, { resolve: (v: unknown) => void; reject: (e: Error) => void; timer: ReturnType<typeof setTimeout> }>();\n private forgotten = false;\n\n constructor(\n private p: StoredPairing,\n private sealer: Sealer,\n private storage: PairStorage,\n private key: string,\n private socket: SocketFactory,\n private timeoutMs: number,\n ) {}\n\n /** Take over a socket that is already open (the one pairing used). */\n adopt(ws: SocketLike) {\n this.ws = ws;\n this.wire(ws);\n }\n\n private wire(ws: SocketLike) {\n ws.onmessage = inOrder((ev: { data: unknown }) => this.onFrame(String(ev.data)));\n ws.onerror = null;\n ws.onclose = () => {\n if (this.ws === ws) this.ws = null;\n this.failAll(new Error('The connection to bWalletX closed'));\n };\n }\n\n private persist() {\n if (this.forgotten) return;\n this.p = { ...this.p, ...this.sealer.counters };\n void Promise.resolve(this.storage.setItem(this.key, JSON.stringify(this.p))).catch(() => {});\n }\n\n private failAll(e: Error) {\n for (const w of this.waiting.values()) {\n clearTimeout(w.timer);\n w.reject(e);\n }\n this.waiting.clear();\n }\n\n private async ensure() {\n if (this.forgotten) throw new Error('This pairing was removed. Pair again.');\n if (this.ws && this.ws.readyState === OPEN) return;\n this.opening ??= this.reopen().finally(() => (this.opening = null));\n await this.opening;\n }\n\n private reopen() {\n // A fresh expiry lets the relay recreate the channel if it was dropped; the wallet rejoins on its own.\n const ws = this.socket(relaySocketUrl(this.p.r, this.p.c, 'site', Math.floor(Date.now() / 1000) + QR_LIFETIME_S - 10));\n return new Promise<void>((resolve, reject) => {\n ws.onopen = () => {\n this.ws = ws;\n this.wire(ws);\n resolve();\n };\n ws.onerror = () => reject(new Error('Could not reach the bWalletX pairing service'));\n ws.onclose = () => reject(new Error('Could not reach the bWalletX pairing service'));\n });\n }\n\n private async onFrame(raw: string) {\n let f: unknown;\n try {\n f = JSON.parse(raw);\n } catch {\n return;\n }\n const t = (f as { t?: string; error?: string }).t;\n if (t === 'relay' && (f as { error?: string }).error) {\n return this.failAll(new Error(`bWalletX pairing service: ${(f as { error: string }).error}`));\n }\n if (!isSealed(f)) return;\n const msg = await this.sealer.open(f);\n if (!msg) return;\n this.persist();\n if (msg.t === 'res') {\n const w = this.waiting.get(msg.id);\n if (!w) return;\n clearTimeout(w.timer);\n this.waiting.delete(msg.id);\n if (msg.error) w.reject(Object.assign(new Error(msg.error.message), { code: msg.error.code }));\n else w.resolve(msg.result);\n } else if (msg.t === 'close') {\n this.drop();\n this.failAll(new Error('bWalletX disconnected this site. Pair again.'));\n }\n }\n\n async call(action: string, params: unknown): Promise<unknown> {\n await this.ensure();\n const ws = this.ws!;\n const id = `${action}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n const result = new Promise<unknown>((resolve, reject) => {\n const timer = setTimeout(() => {\n if (this.waiting.delete(id)) reject(new Error('No answer from bWalletX. Open it, unlocked, and approve.'));\n }, this.timeoutMs);\n this.waiting.set(id, { resolve, reject, timer });\n });\n ws.send(JSON.stringify(await this.sealer.seal({ t: 'req', id, action, params } satisfies PairMessage)));\n this.persist();\n return result;\n }\n\n close() {\n const ws = this.ws;\n this.ws = null;\n ws?.close();\n }\n\n private drop() {\n this.forgotten = true;\n void Promise.resolve(this.storage.removeItem(this.key)).catch(() => {});\n this.close();\n }\n\n async forget() {\n if (this.forgotten) return;\n try {\n if (this.ws && this.ws.readyState === OPEN) {\n this.ws.send(JSON.stringify(await this.sealer.seal({ t: 'close', reason: 'site unpaired' })));\n }\n } catch {\n /* best effort */\n }\n this.drop();\n }\n\n wallet(): PairedWallet {\n return new Proxy({} as PairedWallet, {\n get: (_t, method) => {\n if (method === 'close') return () => this.close();\n if (method === 'forget') return () => this.forget();\n if (typeof method !== 'string' || method === 'then' || method === 'toJSON') return undefined;\n return (params: unknown) => this.call(method, params ?? {});\n },\n });\n }\n}\n\n/**\n * Pair with bWalletX on a phone (scan the QR) or web.bwalletx.com (paste the link).\n * Resolves with a wallet once the user taps Connect. The pairing is stored (see `storage`) so\n * `restorePairing()` can reconnect after a reload without a new QR.\n */\nexport function pairBwalletX(opts: PairingOptions): Promise<PairedWallet> {\n const storage = opts.storage === undefined ? defaultStorage() : (opts.storage ?? memoryStorage());\n const key = opts.storageKey ?? DEFAULT_KEY;\n const socket = opts.socket ?? defaultSocket();\n const relay = opts.relay ?? DEFAULT_RELAY;\n const origin = opts.origin ?? (typeof location !== 'undefined' ? location.origin : '');\n if (!origin) return Promise.reject(new Error('pairBwalletX needs options.origin outside a browser'));\n\n const siteKey = PrivateKey.fromRandom(); // a throwaway pairing key, not a wallet key\n const channel = newChannel();\n const expiry = Math.floor(Date.now() / 1000) + QR_LIFETIME_S;\n\n return new Promise<PairedWallet>((resolve, reject) => {\n if (opts.signal?.aborted) return reject(new Error('cancelled'));\n let ws: SocketLike;\n try {\n ws = socket(relaySocketUrl(relay, channel, 'site', expiry));\n } catch (e) {\n return reject(e);\n }\n let sealer: Sealer | null = null;\n let walletKey = '';\n let settled = false;\n const fail = (e: Error) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n ws.close();\n reject(e);\n };\n const timer = setTimeout(() => fail(new Error('The pairing code expired. Show a new one.')), QR_LIFETIME_S * 1000);\n opts.signal?.addEventListener('abort', () => fail(new Error('cancelled')));\n ws.onerror = () => fail(new Error('Could not reach the bWalletX pairing service'));\n ws.onclose = () => fail(new Error('The connection to bWalletX closed before pairing finished'));\n ws.onmessage = inOrder(async (ev: { data: unknown }) => {\n if (settled) return;\n let f: unknown;\n try {\n f = JSON.parse(String(ev.data));\n } catch {\n return;\n }\n if ((f as HelloFrame).t === 'hello' && !sealer) {\n walletKey = (f as HelloFrame).k;\n const s = await deriveSession(siteKey, walletKey, channel);\n sealer = new Sealer(s.key, 'site');\n opts.onCode(s.code);\n return;\n }\n if (!sealer || !isSealed(f)) return;\n const msg = await sealer.open(f);\n if (!msg) return;\n if (msg.t === 'ready') {\n settled = true;\n clearTimeout(timer);\n const p: StoredPairing = { v: 1, c: channel, r: relay, s: siteKey.toHex(), k: walletKey, ...sealer.counters, pairedAt: Date.now() };\n await Promise.resolve(storage.setItem(key, JSON.stringify(p))).catch(() => {});\n const link = new Link(p, sealer, storage, key, socket, opts.callTimeoutMs ?? 120_000);\n link.adopt(ws);\n resolve(link.wallet());\n } else if (msg.t === 'close') {\n fail(new Error('Pairing was declined in bWalletX'));\n }\n });\n opts.onLink(pairUrl({ v: PAIR_VERSION, r: relay, c: channel, k: siteKey.toPublicKey().toString(), o: origin, e: expiry }));\n });\n}\n\n/**\n * The wallet from a pairing stored by an earlier `pairBwalletX`, or null if there is none.\n * It connects on the first call. The wallet must still have this site paired.\n */\nexport async function restorePairing(opts: PairConnectionOptions = {}): Promise<PairedWallet | null> {\n const storage = opts.storage === undefined ? defaultStorage() : (opts.storage ?? memoryStorage());\n const key = opts.storageKey ?? DEFAULT_KEY;\n const p = parseStored(await Promise.resolve(storage.getItem(key)).catch(() => null));\n if (!p) return null;\n const { key: aes } = await deriveSession(PrivateKey.fromHex(p.s), p.k, p.c);\n const sealer = new Sealer(aes, 'site');\n sealer.restore({ sent: p.sent, lastSeen: p.lastSeen });\n return new Link(p, sealer, storage, key, opts.socket ?? defaultSocket(), opts.callTimeoutMs ?? 120_000).wallet();\n}\n\n/** Delete the stored pairing without telling the wallet. */\nexport async function clearPairing(opts: Pick<PairConnectionOptions, 'storage' | 'storageKey'> = {}) {\n const storage = opts.storage === undefined ? defaultStorage() : (opts.storage ?? memoryStorage());\n await Promise.resolve(storage.removeItem(opts.storageKey ?? DEFAULT_KEY)).catch(() => {});\n}\n","/**\n * Wrap an async frame handler so frames are handled one at a time, in arrival order.\n *\n * WebSocket `onmessage` does not wait for an async handler. The phone sends its plain `hello`\n * and then, as soon as the user taps Connect, a sealed `ready`. If the handler for `hello` is\n * still deriving the session key when `ready` arrives, a naive handler sees no key yet and drops\n * `ready`, so pairing never finishes. Chaining every frame onto one promise fixes that.\n */\nexport function inOrder<T>(handle: (frame: T) => Promise<void> | void, onError?: (e: unknown) => void) {\n let queue: Promise<void> = Promise.resolve();\n return (frame: T): Promise<void> => {\n queue = queue.then(() => handle(frame)).catch((e) => onError?.(e));\n return queue;\n };\n}\n","/**\n * Phone pairing protocol (tokenblaster.lol docs/wallet-connect.md §4), shared by the site side and\n * bWallet. Kept dependency-light (@bsv/sdk + WebCrypto) so the same file can be copied into sites\n * until it ships as @b0ase/wallet.\n *\n * QR: https://www.bwallet.space/pair?v=1&r=<relay host>&c=<channel>&k=<site pubkey>&o=<origin>&e=<expiry>\n * key: ECDH(secp256k1) → HKDF-SHA256(salt = channel bytes, info = \"bwallet-pair-v1\") → AES-256-GCM\n * frame: { s: seq, n: nonce b64, d: ciphertext b64 }, AAD = \"<sender role>|<s>\", s strictly increasing\n * code: first 2 bytes of SHA-256(key bits) → 4 digits, shown on both screens\n */\nimport { PrivateKey, PublicKey } from '@bsv/sdk';\n\nexport const PAIR_VERSION = '1';\nexport const PAIR_INFO = 'bwallet-pair-v1';\n// www: the bare domain redirects there, and app-link checks (Apple's AASA) don't follow redirects.\nexport const PAIR_HOST = 'www.bwallet.space';\nconst PAIR_HOSTS = new Set([PAIR_HOST, 'bwallet.space']);\nexport const DEFAULT_RELAY = 'relay.bwallet.space';\nexport const QR_LIFETIME_S = 120;\n\nexport type Role = 'site' | 'wallet';\nexport type WalletInfo = { name: string; icon?: string; rdns: string };\n\nexport type PairLink = { v: string; r: string; c: string; k: string; o: string; e: number };\n\n/** Plaintext messages inside encrypted frames. */\nexport type PairMessage =\n | { t: 'req'; id: string; action: string; params: unknown }\n | { t: 'res'; id: string; result?: unknown; error?: { code: string; message: string } }\n | { t: 'ready' }\n | { t: 'ping' }\n | { t: 'close'; reason: string };\n\n/** Unencrypted frames: from the relay, and the phone's hello (its key isn't shared yet). */\nexport type RelayFrame = { t: 'relay'; verifiedOrigin?: string; peer?: 'joined' | 'left'; role?: Role; error?: string };\nexport type HelloFrame = { t: 'hello'; k: string; info: WalletInfo };\nexport type SealedFrame = { s: number; n: string; d: string };\n\nconst enc = new TextEncoder();\nconst dec = new TextDecoder();\n\n// Chunked: String.fromCharCode(...bytes) overflows the call stack on large frames (signed transactions).\nconst binary = (bytes: Uint8Array) => {\n let s = '';\n for (let i = 0; i < bytes.length; i += 0x8000) s += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n return s;\n};\nexport const b64url = (bytes: Uint8Array) =>\n btoa(binary(bytes)).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\nexport const fromB64url = (s: string) => {\n const t = s.replace(/-/g, '+').replace(/_/g, '/');\n const bin = atob(t + '='.repeat((4 - (t.length % 4)) % 4));\n return Uint8Array.from(bin, (ch) => ch.charCodeAt(0));\n};\nconst b64 = (bytes: Uint8Array) => btoa(binary(bytes));\nconst fromB64 = (s: string) => Uint8Array.from(atob(s), (ch) => ch.charCodeAt(0));\n\nexport const newChannel = () => b64url(crypto.getRandomValues(new Uint8Array(16)));\n\nexport function pairUrl(link: PairLink): string {\n const q = new URLSearchParams({ v: link.v, r: link.r, c: link.c, k: link.k, o: link.o, e: String(link.e) });\n return `https://${PAIR_HOST}/pair?${q}`;\n}\n\n/** Parse a scanned QR (https link or bwallet:// fallback). Throws on anything else. */\nexport function parsePairUrl(text: string, nowS = Math.floor(Date.now() / 1000)): PairLink {\n const u = new URL(text.trim());\n const ok =\n (u.protocol === 'https:' && PAIR_HOSTS.has(u.host) && u.pathname === '/pair') ||\n (u.protocol === 'bwallet:' && /pair/.test(u.href));\n if (!ok) throw new Error('Not a bWallet pairing code');\n const g = (k: string) => u.searchParams.get(k) ?? '';\n const link: PairLink = { v: g('v'), r: g('r'), c: g('c'), k: g('k'), o: g('o'), e: Number(g('e')) };\n if (link.v !== PAIR_VERSION) throw new Error('This pairing code needs a newer bWallet');\n if (!/^[A-Za-z0-9_-]{22}$/.test(link.c)) throw new Error('Bad pairing code');\n if (!/^0[23][0-9a-f]{64}$/i.test(link.k)) throw new Error('Bad pairing code');\n if (!/^[a-z0-9.-]+(:\\d+)?$/i.test(link.r)) throw new Error('Bad pairing code');\n const o = new URL(link.o);\n if (o.origin !== link.o) throw new Error('Bad pairing code');\n if (!Number.isFinite(link.e) || link.e < nowS) throw new Error('This code has expired. Ask the site for a new one.');\n return link;\n}\n\nexport const relaySocketUrl = (relay: string, channel: string, role: Role, expiry?: number) => {\n const local = /^(localhost|127\\.0\\.0\\.1)(:\\d+)?$/.test(relay);\n const q = new URLSearchParams({ role });\n if (expiry) q.set('e', String(expiry));\n return `${local ? 'ws' : 'wss'}://${relay}/v1/c/${channel}?${q}`;\n};\n\n/** Shared AES key + 4-digit comparison code from my private key and their public key. */\nexport async function deriveSession(mine: PrivateKey, theirs: string, channel: string) {\n const point = mine.deriveSharedSecret(PublicKey.fromString(theirs));\n const ikm = new Uint8Array(point.encode(true) as number[]);\n const base = await crypto.subtle.importKey('raw', ikm, 'HKDF', false, ['deriveBits']);\n const bits = new Uint8Array(\n await crypto.subtle.deriveBits(\n { name: 'HKDF', hash: 'SHA-256', salt: fromB64url(channel), info: enc.encode(PAIR_INFO) },\n base,\n 256,\n ),\n );\n const key = await crypto.subtle.importKey('raw', bits, 'AES-GCM', false, ['encrypt', 'decrypt']);\n const h = new Uint8Array(await crypto.subtle.digest('SHA-256', bits));\n const code = String(((h[0] << 8) | h[1]) % 10000).padStart(4, '0');\n return { key, code };\n}\n\n/** One direction-aware encrypted pipe. `me` is the sender role used in the AAD. */\nexport class Sealer {\n private sent = 0;\n private lastSeen = 0;\n constructor(\n private key: CryptoKey,\n private me: Role,\n ) {}\n\n async seal(msg: PairMessage): Promise<SealedFrame> {\n const s = ++this.sent;\n const n = crypto.getRandomValues(new Uint8Array(12));\n const ct = new Uint8Array(\n await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv: n, additionalData: enc.encode(`${this.me}|${s}`) },\n this.key,\n enc.encode(JSON.stringify(msg)),\n ),\n );\n return { s, n: b64(n), d: b64(ct) };\n }\n\n /** Decrypts a frame from the other side; null for replays, reflections or tampering. */\n async open(f: SealedFrame): Promise<PairMessage | null> {\n if (!Number.isInteger(f.s) || f.s <= this.lastSeen) return null;\n const from: Role = this.me === 'site' ? 'wallet' : 'site';\n try {\n const pt = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: fromB64(f.n), additionalData: enc.encode(`${from}|${f.s}`) },\n this.key,\n fromB64(f.d),\n );\n this.lastSeen = f.s;\n return JSON.parse(dec.decode(pt)) as PairMessage;\n } catch {\n return null;\n }\n }\n\n /** For resuming a session after a reload: continue counters where they were. */\n get counters() {\n return { sent: this.sent, lastSeen: this.lastSeen };\n }\n restore(c: { sent: number; lastSeen: number }) {\n this.sent = c.sent;\n this.lastSeen = c.lastSeen;\n }\n}\n\nexport const isSealed = (x: unknown): x is SealedFrame =>\n !!x && typeof x === 'object' && 'd' in x && 'n' in x && 's' in x;\n","import type { WalletInterface, WalletProtocol } from '@bsv/sdk';\nimport { discoverBwalletX } from './discover.js';\nimport { pairBwalletX, restorePairing, type PairingOptions } from './pair.js';\n\n/** Security level 2, a protocol name used for nothing else. */\nexport const LOGIN_PROTOCOL: WalletProtocol = [2, 'bwallet sign in'];\n\n/** What your server's challenge route returns (createChallenge from '@bwalletx/connect/server'). */\nexport interface Challenge {\n nonce: string;\n message: string;\n keyID: string;\n protocolID?: WalletProtocol;\n}\n\nexport type SignInMethod = 'extension' | 'in-app' | 'pairing' | 'wallet';\n\nexport interface SignInOptions {\n /** Ask your server for a challenge for this identity key. */\n challenge: (identityKey: string) => Promise<Challenge>;\n /** Use this wallet instead of looking for one. `method` is then 'wallet'. */\n wallet?: WalletInterface;\n /** How to show the QR and code if pairing is needed. Without it, pairing is not tried. */\n pairing?: PairingOptions;\n /** Reuse a pairing stored by an earlier sign-in before showing a new QR. Default true. */\n reusePairing?: boolean;\n /** How long to wait for the extension or in-app browser to answer, in ms. Default 1200. */\n discoverMs?: number;\n}\n\nexport interface SignInResult {\n identityKey: string;\n /** DER signature as number[], ready to post to verifySignIn. */\n signature: number[];\n nonce: string;\n method: SignInMethod;\n /** The wallet that signed. Keep it to make more calls. */\n wallet: WalletInterface;\n}\n\n/** Find a wallet: extension or in-app browser first, then a stored pairing, then a new pairing. */\nexport async function connectBwalletX(\n opts: Pick<SignInOptions, 'wallet' | 'pairing' | 'reusePairing' | 'discoverMs'> = {},\n): Promise<{ wallet: WalletInterface; method: SignInMethod }> {\n if (opts.wallet) return { wallet: opts.wallet, method: 'wallet' };\n const found = await discoverBwalletX(opts.discoverMs);\n if (found) return { wallet: found.wallet, method: found.method };\n if (opts.reusePairing !== false) {\n const restored = await restorePairing(opts.pairing ?? {});\n if (restored) return { wallet: restored, method: 'pairing' };\n }\n if (!opts.pairing) {\n throw Object.assign(new Error('bWalletX was not found in this browser'), { code: 'NOT_FOUND' });\n }\n return { wallet: await pairBwalletX(opts.pairing), method: 'pairing' };\n}\n\n/**\n * Sign the server's challenge with the user's bWalletX identity key. Post the result's\n * identityKey, nonce and signature to your verify route.\n */\nexport async function signInWithBwalletX(opts: SignInOptions): Promise<SignInResult> {\n const { wallet, method } = await connectBwalletX(opts);\n if (method !== 'pairing') await wallet.waitForAuthentication({}).catch(() => {});\n const { publicKey: identityKey } = await wallet.getPublicKey({ identityKey: true });\n const c = await opts.challenge(identityKey);\n const { signature } = await wallet.createSignature({\n protocolID: c.protocolID ?? LOGIN_PROTOCOL,\n keyID: c.keyID,\n counterparty: 'anyone',\n data: Array.from(new TextEncoder().encode(c.message)),\n });\n return { identityKey, signature: Array.from(signature), nonce: c.nonce, method, wallet };\n}\n","const CSS = `\n.bwx-signin{display:inline-flex;align-items:center;gap:12px;min-height:48px;padding:10px 22px 10px 10px;border:0;border-radius:12px;cursor:pointer;background:linear-gradient(180deg,#fcd34d,#f59e0b);color:#000;text-align:left;font:700 16px/1.2 system-ui,-apple-system,\"Segoe UI\",sans-serif;box-shadow:0 8px 24px rgba(245,158,11,.2)}\n.bwx-signin:hover{background:linear-gradient(180deg,#fde68a,#fbbf24)}\n.bwx-signin:focus-visible{outline:2px solid #ffd24d;outline-offset:3px}\n.bwx-signin:disabled{opacity:.6;cursor:wait}\n.bwx-signin .bwx-mark{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;background:#000;flex:none}\n.bwx-signin small{display:block;font-size:11px;font-weight:500;color:rgba(0,0,0,.6)}`;\n\nexport const LOGO_URL = 'https://bwalletx.com/logo.svg';\n\nexport interface ButtonOptions {\n /** Second line under the label. Default \"also works with bWallet\". false hides it. */\n subtitle?: string | false;\n onClick?: (button: HTMLButtonElement) => void;\n}\n\n/** Put the gold \"Sign in with bWalletX\" button into `el` (replacing its contents). */\nexport function renderButton(el: HTMLElement | string, opts: ButtonOptions = {}): HTMLButtonElement {\n const host = typeof el === 'string' ? document.querySelector<HTMLElement>(el) : el;\n if (!host) throw new Error(`renderButton: no element ${String(el)}`);\n if (!document.getElementById('bwx-signin-css')) {\n const style = document.createElement('style');\n style.id = 'bwx-signin-css';\n style.textContent = CSS;\n document.head.appendChild(style);\n }\n const b = document.createElement('button');\n b.type = 'button';\n b.className = 'bwx-signin';\n const mark = document.createElement('span');\n mark.className = 'bwx-mark';\n const img = document.createElement('img');\n img.src = LOGO_URL;\n img.alt = '';\n img.width = 15;\n img.height = 20;\n mark.appendChild(img);\n const label = document.createElement('span');\n label.className = 'bwx-label';\n label.textContent = 'Sign in with bWalletX';\n const sub = opts.subtitle === undefined ? 'also works with bWallet' : opts.subtitle;\n if (sub) {\n const small = document.createElement('small');\n small.textContent = sub;\n label.appendChild(small);\n }\n b.append(mark, label);\n if (opts.onClick) b.addEventListener('click', () => opts.onClick!(b));\n host.replaceChildren(b);\n return b;\n}\n","/**\n * <bwalletx-signin>: the standard \"Sign in with bWalletX\" button as a framework-free web component.\n *\n * Design reference: the gold button in bit-sign's sign-in card (src/components/BwalletSignIn.tsx):\n * amber-300 → amber-500 vertical gradient, 12px radius, 16px/20px padding, 16px bold black label,\n * 11px subtitle at 60% black, a black 28px circle holding the gold \"b\", amber shadow.\n *\n * Attributes (all optional):\n * size lg (default) | md | sm | icon\n * theme gold (default) | dark | light\n * label signin (default) | continue | connect\n * brand bWalletX (default) | bWallet (store edition text)\n * subtitle on | off | <custom text>. Default on for lg/md, off for sm/icon and for brand=\"bWallet\"\n * full-width stretch to the container\n * loading show the spinner and set aria-busy\n * disabled disable the button\n * challenge-url / verify-url run the sign-in flow on click (POST JSON, as in the README)\n * get-url where \"Get bWalletX\" points. Default https://bwalletx.com/get\n * web-url the web wallet. Default https://web.bwalletx.com\n * discover-ms how long to wait for the wallet to answer. Default 1200\n * href plain link mode: navigate here on click\n * authorize-url (+ client-id, redirect-uri, scope) OAuth mode, for auth.bwalletx.com once it exists\n *\n * Events (bubble, composed):\n * bwalletx-signin on every click, before anything else. Cancelable: preventDefault() stops the\n * built-in behaviour so you can run your own flow.\n * bwalletx-signed-in detail { identityKey, method, nonce, signature, response }\n * bwalletx-not-found no bWalletX answered; the \"Get bWalletX\" row is shown\n * bwalletx-error detail { error }\n */\nimport { discoverBwalletX } from './discover.js';\nimport { signInWithBwalletX, type Challenge } from './signin.js';\n\nexport const SIGNIN_TAG = 'bwalletx-signin';\nexport const GET_URL = 'https://bwalletx.com/get';\nexport const WEB_WALLET_URL = 'https://web.bwalletx.com';\n\nexport type SigninSize = 'lg' | 'md' | 'sm' | 'icon';\nexport type SigninTheme = 'gold' | 'dark' | 'light';\nexport type SigninLabel = 'signin' | 'continue' | 'connect';\nexport type SigninBrand = 'bWalletX' | 'bWallet';\n\nconst VERBS: Record<SigninLabel, string> = { signin: 'Sign in with', continue: 'Continue with', connect: 'Connect' };\n\n/** The visible label for a label/brand pair, e.g. \"Sign in with bWalletX\". */\nexport function signinText(label: SigninLabel = 'signin', brand: SigninBrand = 'bWalletX'): string {\n return `${VERBS[label] ?? VERBS.signin} ${brand}`;\n}\n\nlet uid = 0;\n/** The gold \"b\" (bwalletx-site/logo.svg). Ids are unique per copy so several marks can share a page. */\nexport function markSvg(px = 20): string {\n const n = ++uid;\n return `<svg viewBox=\"23 8 74 100\" width=\"${Math.round(px * 0.74)}\" height=\"${px}\" aria-hidden=\"true\" focusable=\"false\"><defs><linearGradient id=\"bwxg${n}\" gradientUnits=\"userSpaceOnUse\" x1=\"0\" y1=\"12\" x2=\"0\" y2=\"105\"><stop offset=\"0\" stop-color=\"#FFE58A\"/><stop offset=\".55\" stop-color=\"#FFD24D\"/><stop offset=\"1\" stop-color=\"#C98F00\"/></linearGradient><mask id=\"bwxh${n}\"><rect width=\"140\" height=\"140\" fill=\"#fff\"/><circle cx=\"60\" cy=\"72\" r=\"15\" fill=\"#000\"/></mask></defs><g fill=\"url(#bwxg${n})\" mask=\"url(#bwxh${n})\"><polygon points=\"45,12 45,76 27,76 27,30\"/><circle cx=\"60\" cy=\"72\" r=\"33\"/></g></svg>`;\n}\n\nexport const SIGNIN_CSS = `\n:host{display:inline-block;vertical-align:middle;font-family:Inter,ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif}\n:host([full-width]){display:block;width:100%}\n:host([hidden]){display:none}\nbutton{all:unset;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:12px;width:100%;cursor:pointer;\n padding:16px 20px;border-radius:12px;font-size:16px;font-weight:700;line-height:1.2;text-align:left;\n background:linear-gradient(180deg,#fcd34d,#f59e0b);color:#000;\n box-shadow:0 10px 15px -3px rgba(245,158,11,.2),0 4px 6px -4px rgba(245,158,11,.2);\n transition:background .15s,transform .1s,box-shadow .15s,border-color .15s;-webkit-tap-highlight-color:transparent}\nbutton:hover{background:linear-gradient(180deg,#fde68a,#fbbf24)}\nbutton:active{transform:translateY(1px);background:linear-gradient(180deg,#fbbf24,#d97706)}\nbutton:focus-visible{outline:2px solid #b45309;outline-offset:3px}\nbutton:disabled{opacity:.6;cursor:not-allowed;transform:none}\nbutton[aria-busy=true]{cursor:wait}\n.mark{display:inline-flex;align-items:center;justify-content:center;flex:none;width:28px;height:28px;border-radius:50%;background:#000}\n.txt{display:flex;flex-direction:column;align-items:flex-start;min-width:0}\n.txt b{font-weight:700;white-space:nowrap}\n.txt small{font-size:11px;font-weight:500;color:rgba(0,0,0,.65);white-space:nowrap}\n.spin{width:16px;height:16px;border-radius:50%;border:2px solid rgba(255,210,77,.35);border-top-color:#ffd24d;animation:r .8s linear infinite}\n@keyframes r{to{transform:rotate(360deg)}}\n@media (prefers-reduced-motion:reduce){button{transition:none}button:active{transform:none}.spin{animation:none;border-color:#ffd24d;border-right-color:transparent}}\n/* sizes */\n:host([size=md]) button{padding:10px 16px;border-radius:10px;font-size:15px;gap:10px}\n:host([size=md]) .mark{width:24px;height:24px}\n:host([size=md]) .txt small{font-size:10.5px}\n:host([size=sm]) button{padding:6px 12px 6px 6px;border-radius:8px;font-size:13px;gap:8px;min-height:36px}\n:host([size=sm]) .mark{width:22px;height:22px}\n:host([size=icon]) button{width:48px;height:48px;padding:0;border-radius:50%;gap:0}\n:host([size=icon]) .mark{width:34px;height:34px}\n/* themes */\n:host([theme=dark]) button{background:#0a0a0a;color:#fafafa;border:1px solid #3f3f46;box-shadow:none}\n:host([theme=dark]) button:hover{background:#18181b;border-color:rgba(251,191,36,.6)}\n:host([theme=dark]) button:active{background:#000}\n:host([theme=dark]) button:focus-visible{outline-color:#fcd34d}\n:host([theme=dark]) .mark{box-shadow:inset 0 0 0 1px #3f3f46}\n:host([theme=dark]) .txt small{color:rgba(255,255,255,.65)}\n:host([theme=light]) button{background:#fff;color:#09090b;border:1px solid #d4d4d8;box-shadow:0 1px 2px rgba(0,0,0,.06)}\n:host([theme=light]) button:hover{background:#fafafa;border-color:#f59e0b}\n:host([theme=light]) button:active{background:#f4f4f5}\n:host([theme=light]) .txt small{color:#52525b}\n/* not found */\n.nf{margin-top:8px;font-size:12px;line-height:1.4;color:#71717a;text-align:center}\n.nf a{color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px}\n.nf a:focus-visible{outline:2px solid #b45309;outline-offset:2px;border-radius:2px}\n:host([theme=dark]) .nf,:host-context(.dark) .nf{color:#a1a1aa}\n.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n`;\n\n/** Optional OAuth parameters for authorize-url mode. auth.bwalletx.com is planned, not live. */\nexport interface AuthorizeParams { authorizeUrl: string; clientId?: string | null; redirectUri?: string | null; scope?: string | null }\n\nfunction b64url(bytes: Uint8Array): string {\n let s = '';\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Build an OAuth 2.1 authorization-code + S256 PKCE redirect URL, and keep the verifier, state and\n * nonce in sessionStorage under \"bwalletx:oauth\" for your callback page. Matches the plan in\n * bit-sign docs/SIGN-IN-WITH-BWALLETX.md. The provider is not live yet.\n */\nexport async function buildAuthorizeUrl(p: AuthorizeParams): Promise<string> {\n const rnd = (n: number) => b64url(crypto.getRandomValues(new Uint8Array(n)));\n const verifier = rnd(32);\n const state = rnd(16);\n const nonce = rnd(16);\n const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier)));\n const u = new URL(p.authorizeUrl, typeof location !== 'undefined' ? location.href : undefined);\n const set = (k: string, v: string | null | undefined) => { if (v) u.searchParams.set(k, v); };\n set('response_type', 'code');\n set('client_id', p.clientId);\n set('redirect_uri', p.redirectUri);\n set('scope', p.scope || 'openid profile');\n set('state', state);\n set('nonce', nonce);\n set('code_challenge', b64url(digest));\n set('code_challenge_method', 'S256');\n try { sessionStorage.setItem('bwalletx:oauth', JSON.stringify({ verifier, state, nonce })); } catch { /* storage blocked */ }\n return u.toString();\n}\n\nasync function postJson<T>(url: string, body: unknown): Promise<T> {\n const res = await fetch(url, { method: 'POST', credentials: 'include', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) throw new Error((data as { error?: string }).error ?? `HTTP ${res.status}`);\n return data as T;\n}\n\nconst OBSERVED = ['size', 'theme', 'label', 'brand', 'subtitle', 'loading', 'disabled', 'full-width', 'aria-label', 'get-url', 'web-url'];\n\n/** The element class. Created lazily so importing this module on a server is harmless. */\nfunction createClass(): CustomElementConstructor {\n return class BwalletxSigninElement extends HTMLElement {\n static get observedAttributes() { return OBSERVED; }\n #root: ShadowRoot;\n #notFound = false;\n #busy = false;\n\n constructor() {\n super();\n this.#root = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() { this.#render(); }\n attributeChangedCallback() { if (this.isConnected) this.#render(); }\n\n /** The inner <button>, for focus() and tests. */\n get button(): HTMLButtonElement | null { return this.#root.querySelector('button'); }\n get notFound() { return this.#notFound; }\n\n focus(opts?: FocusOptions) { this.button?.focus(opts); }\n\n #attr(name: string) { return this.getAttribute(name); }\n\n #render() {\n const size = (this.#attr('size') ?? 'lg') as SigninSize;\n const brand: SigninBrand = this.#attr('brand') === 'bWallet' ? 'bWallet' : 'bWalletX';\n const text = signinText((this.#attr('label') ?? 'signin') as SigninLabel, brand);\n const subAttr = this.#attr('subtitle');\n const subDefault = brand === 'bWalletX' && (size === 'lg' || size === 'md') ? 'also works with bWallet' : null;\n const subtitle = subAttr === null || subAttr === '' || subAttr === 'on' ? (subAttr === 'on' ? 'also works with bWallet' : subDefault)\n : subAttr === 'off' ? null : subAttr;\n const loading = this.hasAttribute('loading') || this.#busy;\n const disabled = this.hasAttribute('disabled');\n const markPx = size === 'icon' ? 24 : size === 'sm' ? 15 : size === 'md' ? 17 : 20;\n const aria = this.#attr('aria-label') ?? (subtitle && size !== 'icon' ? `${text}, ${subtitle}` : text);\n const getUrl = this.#attr('get-url') ?? GET_URL;\n const webUrl = this.#attr('web-url') ?? WEB_WALLET_URL;\n\n const esc = (s: string) => s.replace(/[&<>\"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' })[c]!);\n const label = size === 'icon' ? '' : `<span class=\"txt\" part=\"text\"><b part=\"label\">${esc(text)}</b>${subtitle ? `<small part=\"subtitle\">${esc(subtitle)}</small>` : ''}</span>`;\n const mark = loading ? '<span class=\"spin\" aria-hidden=\"true\"></span>' : markSvg(markPx);\n const nf = this.#notFound\n ? `<p class=\"nf\" part=\"not-found\" role=\"status\">bWalletX wasn't found in this browser. <a href=\"${esc(getUrl)}\" target=\"_blank\" rel=\"noopener\">Get ${brand}</a> or <a href=\"${esc(webUrl)}\" target=\"_blank\" rel=\"noopener\">use the web wallet</a>.</p>`\n : '';\n this.#root.innerHTML = `<style>${SIGNIN_CSS}</style><button type=\"button\" part=\"button\" aria-label=\"${esc(aria)}\" title=\"${esc(subtitle ? `${text} (${subtitle})` : text)}\"${disabled ? ' disabled' : ''}${loading ? ' aria-busy=\"true\"' : ''}><span class=\"mark\" part=\"mark\">${mark}</span>${label}</button>${loading ? '<span class=\"sr\" role=\"status\">Connecting to bWalletX…</span>' : ''}${nf}`;\n this.button!.addEventListener('click', () => void this.#click());\n }\n\n #emit(type: string, detail?: unknown, cancelable = false) {\n return this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable }));\n }\n\n #setBusy(on: boolean) { this.#busy = on; this.#render(); }\n\n async #click() {\n if (this.hasAttribute('disabled') || this.hasAttribute('loading') || this.#busy) return;\n if (!this.#emit('bwalletx-signin', { element: this }, true)) return;\n\n const href = this.#attr('href');\n const authorizeUrl = this.#attr('authorize-url');\n if (authorizeUrl) {\n location.assign(await buildAuthorizeUrl({ authorizeUrl, clientId: this.#attr('client-id'), redirectUri: this.#attr('redirect-uri'), scope: this.#attr('scope') }));\n return;\n }\n if (href) { location.assign(href); return; }\n\n const challengeUrl = this.#attr('challenge-url');\n if (!challengeUrl) return; // event-only mode: the page runs its own flow\n\n this.#notFound = false;\n this.#setBusy(true);\n try {\n const ms = Number(this.#attr('discover-ms')) || 1200;\n const found = await discoverBwalletX(ms);\n if (!found) {\n this.#notFound = true;\n this.#emit('bwalletx-not-found');\n return;\n }\n const r = await signInWithBwalletX({ wallet: found.wallet, challenge: (identityKey) => postJson<Challenge>(challengeUrl, { identityKey }) });\n const verifyUrl = this.#attr('verify-url');\n const response = verifyUrl ? await postJson(verifyUrl, { identityKey: r.identityKey, nonce: r.nonce, signature: r.signature }) : null;\n this.#emit('bwalletx-signed-in', { identityKey: r.identityKey, method: found.method, nonce: r.nonce, signature: r.signature, response });\n } catch (error) {\n this.#emit('bwalletx-error', { error });\n } finally {\n this.#setBusy(false);\n }\n }\n };\n}\n\n/** Register <bwalletx-signin> (once). Safe to call on a server: it does nothing there. */\nexport function defineBwalletxSignin(tag = SIGNIN_TAG): CustomElementConstructor | undefined {\n if (typeof window === 'undefined' || typeof customElements === 'undefined') return undefined;\n const existing = customElements.get(tag);\n if (existing) return existing;\n const C = createClass();\n customElements.define(tag, C);\n return C;\n}\n","/**\n * Browser-side payment helpers on top of the BRC-100 wallet's createAction. Works with any\n * BRC-100 wallet. Each helper asks the wallet once; it never retries a spend. If a call fails\n * the error says whether the wallet may have sent anything (`maybeSent`).\n */\nimport { P2PKH, PublicKey, Transaction, Utils, type WalletInterface } from '@bsv/sdk';\n\n/** BRC-29 payment protocol id. */\nexport const BRC29_PROTOCOL: [2, string] = [2, '3241645161d8'];\n\nexport type PayTo = string; // paymail (name@domain), P2PKH address, or 66-hex identity key\n\nexport interface PayOutput {\n /** Locking script hex. */\n script: string;\n satoshis: number;\n description?: string;\n}\n\nexport interface PayRequest {\n to: PayTo;\n /** Amount in satoshis. Give this or `usd`. */\n sats?: number;\n /** Amount in US dollars, converted at `usdPerBsv` (or the live WhatsOnChain rate). */\n usd?: number;\n /** Shown in the wallet and, with `memoOnChain`, written in an OP_RETURN output. */\n memo?: string;\n memoOnChain?: boolean;\n /** Labels for the wallet's history. */\n labels?: string[];\n}\n\nexport interface PayOptions {\n /** Fixed rate for `usd`. Otherwise fetched from WhatsOnChain. */\n usdPerBsv?: number | (() => Promise<number>);\n /** Resolve a paymail to outputs. Default: bsvalias P2P payment destination (needs CORS on the paymail host). */\n resolvePaymail?: (paymail: string, sats: number) => Promise<{ outputs: PayOutput[]; reference?: string; submit?: (rawTxHex: string) => Promise<void> }>;\n fetch?: typeof fetch;\n}\n\nexport interface Brc29Remittance {\n senderIdentityKey: string;\n derivationPrefix: string;\n derivationSuffix: string;\n outputIndex: number;\n}\n\nexport interface PayResult {\n txid: string;\n /** Atomic BEEF (BRC-95) if the wallet returned it. Send it to your server's verifyPayment. */\n tx?: number[];\n sats: number;\n outputs: PayOutput[];\n /** For an identity-key payment: what the recipient needs to internalize the output (BRC-29). Deliver it to them. */\n remittance?: Brc29Remittance;\n}\n\nexport type PaymentErrorCode = 'BAD_REQUEST' | 'RESOLVE_FAILED' | 'RATE_FAILED' | 'WALLET_REJECTED' | 'WALLET_ERROR' | 'NOT_SUPPORTED';\n\nexport class PaymentError extends Error {\n constructor(\n readonly code: PaymentErrorCode,\n message: string,\n /** true when the wallet was asked to spend and the outcome is unknown. Check before trying again. */\n readonly maybeSent = false,\n readonly cause?: unknown,\n ) {\n super(message);\n this.name = 'PaymentError';\n }\n}\n\n/** A wallet that is not BRC-100 (the HandCash transitional adapter) can still pay through this. */\nexport interface LegacyPayer {\n pay(req: PayRequest & { sats: number }): Promise<PayResult>;\n}\nexport type PaySource = WalletInterface | LegacyPayer;\n\nconst isLegacy = (s: PaySource): s is LegacyPayer => typeof (s as LegacyPayer).pay === 'function' && typeof (s as WalletInterface).createAction !== 'function';\n\nexport const isIdentityKeyHex = (s: string) => /^0[23][0-9a-fA-F]{64}$/.test(s);\nexport const isPaymail = (s: string) => /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(s);\n\nfunction randomB64(n: number) {\n const b = new Uint8Array(n);\n globalThis.crypto.getRandomValues(b);\n return Utils.toBase64(Array.from(b));\n}\n\nfunction opReturn(text: string): string {\n const d = Utils.toArray(text, 'utf8');\n const len = d.length;\n const push = len < 0x4c ? [len] : len <= 0xff ? [0x4c, len] : [0x4d, len & 0xff, len >> 8];\n return Utils.toHex([0x00, 0x6a, ...push, ...d]);\n}\n\nconst clip = (s: string, n: number) => (s.length > n ? s.slice(0, n - 1) + '…' : s);\n/** createAction descriptions must be 5–50 bytes. */\nconst describe = (s: string) => clip(s.length < 5 ? `${s} payment`.trim() : s, 50);\n\nasync function usdRate(o: PayOptions): Promise<number> {\n if (typeof o.usdPerBsv === 'number') return o.usdPerBsv;\n try {\n if (typeof o.usdPerBsv === 'function') return await o.usdPerBsv();\n const r = await (o.fetch ?? fetch)('https://api.whatsonchain.com/v1/bsv/main/exchangerate');\n const j = (await r.json()) as { rate?: number };\n if (!r.ok || !(Number(j.rate) > 0)) throw new Error(`status ${r.status}`);\n return Number(j.rate);\n } catch (e) {\n throw new PaymentError('RATE_FAILED', `Could not get the BSV/USD rate: ${(e as Error).message}`, false, e);\n }\n}\n\n/** Satoshis for a request (sats as given, or usd converted, rounded up). */\nexport async function amountInSats(req: Pick<PayRequest, 'sats' | 'usd'>, o: PayOptions = {}): Promise<number> {\n if (req.sats != null) {\n if (!Number.isSafeInteger(req.sats) || req.sats <= 0) throw new PaymentError('BAD_REQUEST', 'sats must be a positive integer');\n return req.sats;\n }\n if (req.usd != null) {\n if (!(req.usd > 0)) throw new PaymentError('BAD_REQUEST', 'usd must be positive');\n return Math.max(1, Math.ceil((req.usd / (await usdRate(o))) * 1e8));\n }\n throw new PaymentError('BAD_REQUEST', 'Give sats or usd');\n}\n\n/** Default paymail resolver: bsvalias P2P Payment Destination (BRC-? / capability 2a40af698840). */\nexport async function resolvePaymailP2P(paymail: string, sats: number, f: typeof fetch = fetch) {\n const [alias, domain] = paymail.split('@');\n const fail = (m: string, e?: unknown) => new PaymentError('RESOLVE_FAILED', `Could not resolve ${paymail}: ${m}`, false, e);\n let caps: Record<string, string>;\n try {\n const r = await f(`https://${domain}/.well-known/bsvalias`);\n caps = ((await r.json()) as { capabilities: Record<string, string> }).capabilities;\n } catch (e) {\n throw fail('no bsvalias document (or CORS blocked it; resolve on your server and pass resolvePaymail)', e);\n }\n const fill = (u: string) => u.replace('{alias}', encodeURIComponent(alias)).replace('{domain.tld}', domain);\n const dest = caps?.['2a40af698840'];\n if (!dest) throw fail('it does not offer P2P payment destinations');\n let body: { outputs?: { script: string; satoshis: number }[]; reference?: string };\n try {\n const r = await f(fill(dest), { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ satoshis: sats }) });\n if (!r.ok) throw new Error(`status ${r.status}`);\n body = await r.json();\n } catch (e) {\n throw fail((e as Error).message, e);\n }\n if (!body.outputs?.length) throw fail('no outputs returned');\n const receive = caps['5f1323cddf31'];\n return {\n outputs: body.outputs.map((o) => ({ script: o.script, satoshis: o.satoshis })),\n reference: body.reference,\n submit: receive\n ? async (hex: string) => {\n await f(fill(receive), {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ hex, reference: body.reference, metadata: {} }),\n });\n }\n : undefined,\n };\n}\n\nasync function runAction(wallet: WalletInterface, description: string, outputs: PayOutput[], labels?: string[]) {\n try {\n return await wallet.createAction({\n description: describe(description),\n outputs: outputs.map((o) => ({ lockingScript: o.script, satoshis: o.satoshis, outputDescription: describe(o.description ?? 'payment') })),\n labels: labels?.length ? labels : undefined,\n options: { randomizeOutputs: false },\n });\n } catch (e) {\n const msg = (e as Error)?.message ?? String(e);\n const rejected = /denied|reject|cancel|abort|user/i.test(msg) || (e as { code?: unknown })?.code === 4001;\n // Not retried: a lost reply could mean the wallet already broadcast it.\n throw new PaymentError(rejected ? 'WALLET_REJECTED' : 'WALLET_ERROR', rejected ? 'The payment was declined in the wallet.' : `The wallet could not make the payment: ${msg}`, !rejected, e);\n }\n}\n\n/** Pay a paymail, address or identity key. One wallet prompt; never retried. */\nexport async function pay(source: PaySource, req: PayRequest, o: PayOptions = {}): Promise<PayResult> {\n const to = (req.to ?? '').trim();\n if (!to) throw new PaymentError('BAD_REQUEST', 'Give a recipient (to)');\n if (req.memo && req.memo.length > 1000) throw new PaymentError('BAD_REQUEST', 'memo is too long');\n const sats = await amountInSats(req, o);\n if (isLegacy(source)) return source.pay({ ...req, to, sats });\n\n let outputs: PayOutput[];\n let remittance: Brc29Remittance | undefined;\n let submit: ((hex: string) => Promise<void>) | undefined;\n if (isIdentityKeyHex(to)) {\n const derivationPrefix = randomB64(8);\n const derivationSuffix = randomB64(8);\n let pk: string;\n let me: string;\n try {\n ({ publicKey: pk } = await source.getPublicKey({ protocolID: BRC29_PROTOCOL, keyID: `${derivationPrefix} ${derivationSuffix}`, counterparty: to.toLowerCase() }));\n ({ publicKey: me } = await source.getPublicKey({ identityKey: true }));\n } catch (e) {\n throw new PaymentError('WALLET_ERROR', `The wallet could not derive the payment key: ${(e as Error).message}`, false, e);\n }\n outputs = [{ script: new P2PKH().lock(PublicKey.fromString(pk).toHash() as number[]).toHex(), satoshis: sats, description: 'payment' }];\n remittance = { senderIdentityKey: me, derivationPrefix, derivationSuffix, outputIndex: 0 };\n } else if (isPaymail(to)) {\n const r = await (o.resolvePaymail ?? ((p, s) => resolvePaymailP2P(p, s, o.fetch ?? fetch)))(to, sats);\n outputs = r.outputs;\n submit = r.submit;\n } else {\n try {\n outputs = [{ script: new P2PKH().lock(to).toHex(), satoshis: sats, description: 'payment' }];\n } catch {\n throw new PaymentError('BAD_REQUEST', `Not a paymail, address or identity key: ${to}`);\n }\n }\n if (req.memo && req.memoOnChain) outputs = [...outputs, { script: opReturn(req.memo), satoshis: 0, description: 'memo' }];\n\n const r = await runAction(source, req.memo || `Pay ${clip(to, 30)}`, outputs, req.labels);\n if (!r.txid) throw new PaymentError('WALLET_ERROR', 'The wallet did not return a txid', true);\n const tx = r.tx ? Array.from(r.tx) : undefined;\n if (submit && tx) {\n // Tell the paymail host about the tx. Best effort: the payment itself is already made.\n await submit(Transaction.fromAtomicBEEF(tx).toHex()).catch(() => {});\n }\n return { txid: r.txid, tx, sats, outputs, remittance };\n}\n\n/** pay() labelled as a tip. */\nexport function tip(source: PaySource, req: PayRequest, o: PayOptions = {}): Promise<PayResult> {\n return pay(source, { memo: 'Tip', ...req, labels: [...(req.labels ?? []), 'tip'] }, o);\n}\n\nexport interface TokenQuote {\n /** Outputs to fund, as your server priced them (e.g. payment to the seller + fee). */\n outputs: PayOutput[];\n description?: string;\n /** Called with the result after the wallet signs; e.g. POST txid + tx to your server for verifyPayment. */\n onPaid?: (r: PayResult) => Promise<void> | void;\n}\n\nexport interface BuyTokenRequest {\n token: string;\n amount: number | string;\n /** The hook point: return the outputs for this purchase (usually from your server). */\n quote: (req: { token: string; amount: number | string }) => Promise<TokenQuote>;\n labels?: string[];\n}\n\n/** Buy a token: your `quote` hook prices it, the wallet pays once, `onPaid` delivers it. */\nexport async function buyToken(source: PaySource, req: BuyTokenRequest): Promise<PayResult> {\n if (isLegacy(source)) throw new PaymentError('NOT_SUPPORTED', 'This wallet cannot buy tokens. Use a BRC-100 wallet such as bWalletX.');\n const q = await req.quote({ token: req.token, amount: req.amount });\n if (!q?.outputs?.length) throw new PaymentError('BAD_REQUEST', 'The quote returned no outputs');\n const sats = q.outputs.reduce((n, x) => n + x.satoshis, 0);\n const r = await runAction(source, q.description ?? `Buy ${clip(req.token, 30)}`, q.outputs, [...(req.labels ?? []), 'token-buy']);\n if (!r.txid) throw new PaymentError('WALLET_ERROR', 'The wallet did not return a txid', true);\n const res: PayResult = { txid: r.txid, tx: r.tx ? Array.from(r.tx) : undefined, sats, outputs: q.outputs };\n await q.onPaid?.(res);\n return res;\n}\n","/**\n * Every wallet the user could connect with, behind one interface. BRC-100 first: bWalletX, then any\n * other wallet that announces itself (Yours, Metanet, ...), the in-app browser, optional localhost\n * desktop wallets, phone pairing, and app-supplied adapters (e.g. the transitional HandCash one).\n */\nimport { WalletClient, type WalletInterface } from '@bsv/sdk';\nimport { BWALLETX_RDNS, RDNS_EXTENSION } from './discover.js';\nimport { pairBwalletX, restorePairing, type PairingOptions } from './pair.js';\nimport type { PaySource } from './pay.js';\n\nexport type WalletKind = 'brc100' | 'pairing' | 'handcash' | 'custom';\n\nexport interface ConnectedWallet {\n /** The BRC-100 wallet. null for a non-BRC-100 adapter (HandCash today). */\n wallet: WalletInterface | null;\n /** What pay/tip use: the BRC-100 wallet, or the adapter's own payer. */\n payer: PaySource | null;\n /** The identity public key (hex) when the wallet has one. */\n identityKey: string | null;\n handle?: string;\n paymail?: string;\n /** Which option connected. */\n optionId: string;\n kind: WalletKind;\n /** True for adapters kept only until the vendor ships BRC-100. */\n transitional?: boolean;\n}\n\nexport interface WalletOption {\n id: string;\n name: string;\n icon?: string;\n kind: WalletKind;\n rdns?: string;\n /** True for bWalletX (extension, in-app or paired). */\n isBwalletX: boolean;\n connect(): Promise<ConnectedWallet>;\n}\n\nasync function brc100Connected(wallet: WalletInterface, o: Pick<WalletOption, 'id' | 'kind'>): Promise<ConnectedWallet> {\n await wallet.waitForAuthentication({}).catch(() => {});\n const { publicKey } = await wallet.getPublicKey({ identityKey: true });\n return { wallet, payer: wallet, identityKey: publicKey, optionId: o.id, kind: o.kind };\n}\n\n/** Wrap any BRC-100 wallet as a picker option. */\nexport function brc100Option(wallet: WalletInterface, info: { id: string; name: string; icon?: string; rdns?: string; isBwalletX?: boolean }): WalletOption {\n const opt: WalletOption = {\n id: info.id,\n name: info.name,\n icon: info.icon,\n rdns: info.rdns,\n kind: 'brc100',\n isBwalletX: info.isBwalletX ?? false,\n connect: () => brc100Connected(wallet, opt),\n };\n return opt;\n}\n\n/** Phone / web.bwalletx.com pairing as an option (shows a QR through `pairing`). Reuses a stored pairing first. */\nexport function pairingOption(pairing: PairingOptions | (() => PairingOptions)): WalletOption {\n const opt: WalletOption = {\n id: 'bwalletx-pairing',\n name: 'bWalletX on your phone',\n kind: 'pairing',\n isBwalletX: true,\n async connect() {\n const p = typeof pairing === 'function' ? pairing() : pairing;\n const w = (await restorePairing(p)) ?? (await pairBwalletX(p));\n return brc100Connected(w, opt);\n },\n };\n return opt;\n}\n\nexport interface HandCashAdapterOptions {\n /**\n * Your existing HandCash Connect login (redirect/popup + your server route). Resolve with the\n * profile once the user is signed in. This package does not import any HandCash SDK.\n */\n login(): Promise<{ handle: string; paymail?: string; identityKey?: string }>;\n /** Your existing HandCash pay call (usually a server route using the auth token). Optional. */\n pay?: Extract<PaySource, { pay: unknown }>['pay'];\n icon?: string;\n}\n\n/**\n * TRANSITIONAL. Keeps existing HandCash users working behind the same picker until HandCash's\n * BRC-100 support ships; then remove this and HandCash appears as an ordinary BRC-100 wallet.\n */\nexport function handcashAdapter(o: HandCashAdapterOptions): WalletOption {\n const opt: WalletOption = {\n id: 'handcash',\n name: 'HandCash',\n icon: o.icon,\n kind: 'handcash',\n isBwalletX: false,\n async connect() {\n const p = await o.login();\n return {\n wallet: null,\n payer: o.pay ? { pay: o.pay } : null,\n identityKey: p.identityKey ?? null,\n handle: p.handle,\n paymail: p.paymail ?? `${p.handle.replace(/^\\$/, '')}@handcash.io`,\n optionId: opt.id,\n kind: 'handcash',\n transitional: true,\n };\n },\n };\n return opt;\n}\n\nexport interface DiscoverWalletsOptions {\n /** How long to collect BRC-100 announcements, ms. Default 1200. */\n ms?: number;\n /**\n * Also probe desktop wallets on localhost (Metanet / json-api on 3321, Cicada on 3301).\n * Off by default: some browsers prompt for local-network access.\n */\n probeLocal?: boolean;\n /** Add the phone pairing option (needs a way to show the QR, e.g. pairingModal()). */\n pairing?: PairingOptions | (() => PairingOptions);\n /** App-supplied options appended at the end (e.g. handcashAdapter(...)). */\n extra?: WalletOption[];\n}\n\nconst NAMES: Record<string, string> = { [RDNS_EXTENSION]: 'bWalletX', 'space.bwallet.mobile': 'bWalletX' };\n\nasync function probe(substrate: 'json-api' | 'Cicada', ms: number): Promise<WalletInterface | null> {\n try {\n const w = new WalletClient(substrate);\n const ok = await Promise.race([w.isAuthenticated({}).then(() => true), new Promise<boolean>((r) => setTimeout(() => r(false), ms))]);\n return ok ? w : null;\n } catch {\n return null;\n }\n}\n\n/** All wallets we can see, bWalletX first. SSR-safe: resolves [] (plus `extra`) outside a browser. */\nexport async function discoverWallets(o: DiscoverWalletsOptions = {}): Promise<WalletOption[]> {\n const out: WalletOption[] = [];\n const ms = o.ms ?? 1200;\n if (typeof window !== 'undefined') {\n const seen = new Map<string, WalletOption>();\n const onAnnounce = (e: Event) => {\n const d = (e as CustomEvent).detail as { info?: { rdns?: string; name?: string; icon?: string; uuid?: string }; wallet?: WalletInterface } | undefined;\n if (!d?.wallet) return;\n const rdns = d.info?.rdns ?? d.info?.uuid ?? `wallet-${seen.size}`;\n if (seen.has(rdns)) return;\n const isB = (BWALLETX_RDNS as readonly string[]).includes(rdns);\n seen.set(rdns, brc100Option(d.wallet, { id: rdns, rdns, name: NAMES[rdns] ?? d.info?.name ?? rdns, icon: d.info?.icon, isBwalletX: isB }));\n };\n window.addEventListener('brc100:announceWallet', onAnnounce);\n window.dispatchEvent(new Event('brc100:requestWallet'));\n const local = o.probeLocal ? Promise.all([probe('json-api', ms), probe('Cicada', ms)]) : Promise.resolve([null, null]);\n await new Promise((r) => setTimeout(r, ms));\n window.removeEventListener('brc100:announceWallet', onAnnounce);\n out.push(...seen.values());\n const cwi = (window as unknown as { CWI?: WalletInterface }).CWI;\n if (cwi && ![...seen.values()].some((x) => x.rdns === 'space.bwallet.mobile')) {\n out.push(brc100Option(cwi, { id: 'window.CWI', name: 'This app’s wallet', isBwalletX: false }));\n }\n const [json, cicada] = await local;\n if (json) out.push(brc100Option(json, { id: 'localhost:3321', name: 'Desktop wallet (localhost:3321)' }));\n if (cicada) out.push(brc100Option(cicada, { id: 'localhost:3301', name: 'Desktop wallet (localhost:3301)' }));\n }\n if (o.pairing) out.push(pairingOption(o.pairing));\n out.push(...(o.extra ?? []));\n // bWalletX first, transitional last; otherwise keep discovery order.\n const rank = (w: WalletOption) => (w.isBwalletX ? 0 : w.kind === 'handcash' ? 2 : 1);\n return out.map((w, i) => ({ w, i })).sort((a, b) => rank(a.w) - rank(b.w) || a.i - b.i).map((x) => x.w);\n}\n","/**\n * Built-in UI: the pairing QR modal and the wallet picker. Plain DOM, no framework, only created\n * when called in a browser.\n */\nimport qrcode from 'qrcode-generator';\nimport type { PairingOptions } from './pair.js';\nimport type { WalletOption } from './wallets.js';\n\nconst CSS = `\n.bwx-ov{position:fixed;inset:0;z-index:2147483000;background:rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center;padding:16px;font:15px/1.4 system-ui,-apple-system,Segoe UI,Roboto,sans-serif}\n.bwx-box{background:#0b0b0b;color:#f4f1e8;border:1px solid #3a3220;border-radius:16px;width:min(360px,100%);padding:20px;box-shadow:0 20px 60px rgba(0,0,0,.5)}\n.bwx-box h2{margin:0 0 6px;font-size:18px;color:#e8c766}\n.bwx-box p{margin:0 0 14px;color:#bdb6a3;font-size:14px}\n.bwx-qr{background:#fff;border-radius:12px;padding:12px;display:flex;justify-content:center}\n.bwx-qr svg{width:100%;height:auto;max-width:260px}\n.bwx-code{margin:14px 0 0;text-align:center;font-size:28px;letter-spacing:.3em;color:#e8c766;font-variant-numeric:tabular-nums}\n.bwx-row{display:flex;gap:8px;margin-top:14px}\n.bwx-btn{flex:1;border:1px solid #3a3220;background:#15130e;color:#f4f1e8;border-radius:10px;padding:10px 12px;font:inherit;cursor:pointer}\n.bwx-btn:hover{border-color:#e8c766}\n.bwx-list{display:flex;flex-direction:column;gap:8px}\n.bwx-opt{display:flex;align-items:center;gap:10px;text-align:left}\n.bwx-opt img{width:24px;height:24px;border-radius:6px}\n.bwx-tag{margin-left:auto;font-size:11px;color:#8d866f}\n`;\n\nfunction mount(): { root: HTMLDivElement; box: HTMLDivElement; close: () => void } {\n const root = document.createElement('div');\n root.className = 'bwx-ov';\n root.setAttribute('role', 'dialog');\n root.setAttribute('aria-modal', 'true');\n const style = document.createElement('style');\n style.textContent = CSS;\n const box = document.createElement('div');\n box.className = 'bwx-box';\n root.append(style, box);\n document.body.appendChild(root);\n return { root, box, close: () => root.remove() };\n}\n\nfunction el<K extends keyof HTMLElementTagNameMap>(tag: K, cls?: string, text?: string) {\n const e = document.createElement(tag);\n if (cls) e.className = cls;\n if (text != null) e.textContent = text;\n return e;\n}\n\n/** An SVG QR code for `text` (error correction M). */\nexport function qrSvg(text: string): string {\n const q = qrcode(0, 'M');\n q.addData(text);\n q.make();\n return q.createSvgTag({ cellSize: 4, margin: 2, scalable: true });\n}\n\nexport interface PairingModalOptions {\n title?: string;\n /** Called when the user closes the modal (the pairing is then aborted). */\n onCancel?: () => void;\n}\n\n/**\n * PairingOptions that show a QR modal. Pass to signInWithBwalletX({ pairing: pairingModal() }) or\n * connectBwalletX. The modal opens when the link is ready and shows the match code. Call `close()`\n * once pairing settles (useBwalletX does this for you); Cancel aborts the pairing.\n */\nexport function pairingModal(o: PairingModalOptions = {}): PairingOptions & { close(): void } {\n const ac = new AbortController();\n let ui: ReturnType<typeof mount> | null = null;\n let codeEl: HTMLDivElement | null = null;\n const close = () => {\n ui?.close();\n ui = null;\n };\n ac.signal.addEventListener('abort', close);\n return {\n signal: ac.signal,\n close,\n onLink(link) {\n if (typeof document === 'undefined') return;\n close();\n ui = mount();\n const h = el('h2', '', o.title ?? 'Connect bWalletX');\n const p = el('p', '', 'Scan with bWalletX on your phone, or paste the link into web.bwalletx.com.');\n const qr = el('div', 'bwx-qr');\n qr.innerHTML = qrSvg(link);\n codeEl = el('div', 'bwx-code', '');\n codeEl.setAttribute('aria-live', 'polite');\n const row = el('div', 'bwx-row');\n const copy = el('button', 'bwx-btn', 'Copy link');\n copy.onclick = () => void navigator.clipboard?.writeText(link).then(() => (copy.textContent = 'Copied'));\n const cancel = el('button', 'bwx-btn', 'Cancel');\n cancel.onclick = () => {\n o.onCancel?.();\n ac.abort();\n };\n row.append(copy, cancel);\n ui.box.append(h, p, qr, codeEl, row);\n },\n onCode(code) {\n if (codeEl) {\n codeEl.textContent = code;\n const p = ui?.box.querySelector('p');\n if (p) p.textContent = 'Check bWalletX shows the same code, then tap Connect.';\n }\n },\n };\n}\n\n/** Show the picker; resolves with the chosen option, or null if closed. */\nexport function pickWallet(options: WalletOption[], o: { title?: string } = {}): Promise<WalletOption | null> {\n if (typeof document === 'undefined') return Promise.resolve(null);\n return new Promise((resolve) => {\n const ui = mount();\n const done = (w: WalletOption | null) => {\n ui.close();\n resolve(w);\n };\n ui.box.append(el('h2', '', o.title ?? 'Choose a wallet'));\n if (!options.length) ui.box.append(el('p', '', 'No wallet found. Get bWalletX at bwalletx.com.'));\n const list = el('div', 'bwx-list');\n for (const w of options) {\n const b = el('button', 'bwx-btn bwx-opt');\n if (w.icon) {\n const img = el('img');\n img.src = w.icon;\n img.alt = '';\n b.append(img);\n }\n b.append(el('span', '', w.name));\n if (w.kind === 'handcash') b.append(el('span', 'bwx-tag', 'until BRC-100'));\n b.onclick = () => done(w);\n list.append(b);\n }\n const cancel = el('button', 'bwx-btn', 'Cancel');\n cancel.onclick = () => done(null);\n ui.root.onclick = (e) => e.target === ui.root && done(null);\n ui.box.append(list, el('div', 'bwx-row'));\n (ui.box.lastChild as HTMLElement).append(cancel);\n });\n}\n"],"mappings":"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","names":["import_sdk","el","b64url","import_sdk","r","import_sdk","CSS","qrcode"]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { WalletInterface, WalletProtocol } from '@bsv/sdk';
2
+ import { f as PairingOptions, W as WalletOption } from './wallets-VOKIKBbO.cjs';
3
+ export { g as BRC29_PROTOCOL, i as Brc29Remittance, B as BuyTokenRequest, C as ConnectedWallet, D as DiscoverWalletsOptions, H as HandCashAdapterOptions, L as LegacyPayer, j as PairConnectionOptions, k as PairStorage, l as PairedWallet, b as PayOptions, m as PayOutput, P as PayRequest, a as PayResult, n as PaySource, c as PaymentError, o as PaymentErrorCode, S as SocketFactory, q as SocketLike, T as TokenQuote, r as WalletKind, s as amountInSats, d as brc100Option, t as buyToken, u as clearPairing, e as discoverWallets, h as handcashAdapter, v as isIdentityKeyHex, w as isPaymail, x as pairBwalletX, p as pairingOption, y as pay, z as resolvePaymailP2P, A as restorePairing, E as tip } from './wallets-VOKIKBbO.cjs';
2
4
  export { AuthorizeParams, GET_URL, SIGNIN_CSS, SIGNIN_TAG, SigninBrand, SigninLabel, SigninSize, SigninTheme, WEB_WALLET_URL, buildAuthorizeUrl, defineBwalletxSignin, markSvg, signinText } from './element.cjs';
3
5
 
4
6
  /** Ids bWalletX announces in BRC-100 wallet discovery. */
@@ -24,67 +26,6 @@ declare function discoverBwalletX(ms?: number): Promise<FoundWallet | null>;
24
26
  */
25
27
  declare function findBwalletX(ms?: number): Promise<WalletInterface | null>;
26
28
 
27
- /** localStorage-shaped storage. Methods may be sync or async. */
28
- interface PairStorage {
29
- getItem(key: string): string | null | Promise<string | null>;
30
- setItem(key: string, value: string): void | Promise<void>;
31
- removeItem(key: string): void | Promise<void>;
32
- }
33
- /** The minimum of the browser WebSocket API this package uses (the `ws` package also fits). */
34
- interface SocketLike {
35
- readonly readyState: number;
36
- onopen: ((ev: unknown) => void) | null;
37
- onmessage: ((ev: {
38
- data: unknown;
39
- }) => void) | null;
40
- onerror: ((ev: unknown) => void) | null;
41
- onclose: ((ev: unknown) => void) | null;
42
- send(data: string): void;
43
- close(): void;
44
- }
45
- type SocketFactory = (url: string) => SocketLike;
46
- interface PairConnectionOptions {
47
- /** Where the pairing is kept so it survives a reload. Default: localStorage, else memory only. */
48
- storage?: PairStorage | null;
49
- /** Storage key. Default 'bwalletx.connect.pairing.v1'. */
50
- storageKey?: string;
51
- /** Opens a socket. Default: the global WebSocket. Pass one to run in Node or to test. */
52
- socket?: SocketFactory;
53
- /** Per-call timeout in ms. Default 120000. */
54
- callTimeoutMs?: number;
55
- }
56
- interface PairingOptions extends PairConnectionOptions {
57
- /** Show this link as a QR code, and as text to copy (web.bwalletx.com takes it pasted). */
58
- onLink: (link: string) => void;
59
- /** Show this 4-digit code. The wallet shows the same one; the user checks they match. */
60
- onCode: (code: string) => void;
61
- signal?: AbortSignal;
62
- /** Relay host. Default relay.bwallet.space. */
63
- relay?: string;
64
- /** This page's origin, as the relay will see it. Default location.origin. */
65
- origin?: string;
66
- }
67
- /** A BRC-100 wallet whose every call goes, end-to-end encrypted, to the paired phone or web wallet. */
68
- type PairedWallet = WalletInterface & {
69
- /** Close the relay connection. The pairing stays stored; the next call reconnects. */
70
- close(): void;
71
- /** Tell the wallet to unpair, close, and delete the stored pairing. */
72
- forget(): Promise<void>;
73
- };
74
- /**
75
- * Pair with bWalletX on a phone (scan the QR) or web.bwalletx.com (paste the link).
76
- * Resolves with a wallet once the user taps Connect. The pairing is stored (see `storage`) so
77
- * `restorePairing()` can reconnect after a reload without a new QR.
78
- */
79
- declare function pairBwalletX(opts: PairingOptions): Promise<PairedWallet>;
80
- /**
81
- * The wallet from a pairing stored by an earlier `pairBwalletX`, or null if there is none.
82
- * It connects on the first call. The wallet must still have this site paired.
83
- */
84
- declare function restorePairing(opts?: PairConnectionOptions): Promise<PairedWallet | null>;
85
- /** Delete the stored pairing without telling the wallet. */
86
- declare function clearPairing(opts?: Pick<PairConnectionOptions, 'storage' | 'storageKey'>): Promise<void>;
87
-
88
29
  /** Security level 2, a protocol name used for nothing else. */
89
30
  declare const LOGIN_PROTOCOL: WalletProtocol;
90
31
  /** What your server's challenge route returns (createChallenge from '@bwalletx/connect/server'). */
@@ -146,4 +87,24 @@ declare function renderButton(el: HTMLElement | string, opts?: ButtonOptions): H
146
87
  */
147
88
  declare function inOrder<T>(handle: (frame: T) => Promise<void> | void, onError?: (e: unknown) => void): (frame: T) => Promise<void>;
148
89
 
149
- export { BWALLETX_RDNS, type ButtonOptions, type Challenge, type FoundBy, type FoundWallet, LOGIN_PROTOCOL, LOGO_URL, type PairConnectionOptions, type PairStorage, type PairedWallet, type PairingOptions, RDNS_EXTENSION, RDNS_MOBILE, type SignInMethod, type SignInOptions, type SignInResult, type SocketFactory, type SocketLike, clearPairing, connectBwalletX, discoverBwalletX, findBwalletX, inOrder, pairBwalletX, renderButton, restorePairing, signInWithBwalletX };
90
+ /** An SVG QR code for `text` (error correction M). */
91
+ declare function qrSvg(text: string): string;
92
+ interface PairingModalOptions {
93
+ title?: string;
94
+ /** Called when the user closes the modal (the pairing is then aborted). */
95
+ onCancel?: () => void;
96
+ }
97
+ /**
98
+ * PairingOptions that show a QR modal. Pass to signInWithBwalletX({ pairing: pairingModal() }) or
99
+ * connectBwalletX. The modal opens when the link is ready and shows the match code. Call `close()`
100
+ * once pairing settles (useBwalletX does this for you); Cancel aborts the pairing.
101
+ */
102
+ declare function pairingModal(o?: PairingModalOptions): PairingOptions & {
103
+ close(): void;
104
+ };
105
+ /** Show the picker; resolves with the chosen option, or null if closed. */
106
+ declare function pickWallet(options: WalletOption[], o?: {
107
+ title?: string;
108
+ }): Promise<WalletOption | null>;
109
+
110
+ export { BWALLETX_RDNS, type ButtonOptions, type Challenge, type FoundBy, type FoundWallet, LOGIN_PROTOCOL, LOGO_URL, type PairingModalOptions, PairingOptions, RDNS_EXTENSION, RDNS_MOBILE, type SignInMethod, type SignInOptions, type SignInResult, WalletOption, connectBwalletX, discoverBwalletX, findBwalletX, inOrder, pairingModal, pickWallet, qrSvg, renderButton, signInWithBwalletX };