@bwalletx/connect 0.5.4 → 0.7.0
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.
- package/CHANGELOG.md +56 -0
- package/README.md +97 -9
- package/dist/bwalletx-connect.global.js +97 -25
- package/dist/bwalletx-connect.global.js.map +1 -1
- package/dist/choice-B97AjqF4.d.cts +442 -0
- package/dist/choice-B97AjqF4.d.ts +442 -0
- package/dist/chunk-6EFFOIHK.js +2441 -0
- package/dist/chunk-6EFFOIHK.js.map +1 -0
- package/dist/{chunk-QRXFL66W.js → chunk-A2WLGS25.js} +6 -4
- package/dist/chunk-A2WLGS25.js.map +1 -0
- package/dist/chunk-DIKJFKND.js +239 -0
- package/dist/chunk-DIKJFKND.js.map +1 -0
- package/dist/chunk-TNRI7ARM.js +206 -0
- package/dist/chunk-TNRI7ARM.js.map +1 -0
- package/dist/element-BXEoOdXY.d.cts +53 -0
- package/dist/element-BXEoOdXY.d.ts +53 -0
- package/dist/element.cjs +1576 -60
- package/dist/element.cjs.map +1 -1
- package/dist/element.d.cts +26 -26
- package/dist/element.d.ts +26 -26
- package/dist/element.js +35 -2
- package/dist/element.js.map +1 -1
- package/dist/index.cjs +2046 -454
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +323 -16
- package/dist/index.d.ts +323 -16
- package/dist/index.js +186 -12
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +5 -3
- package/dist/next.cjs.map +1 -1
- package/dist/next.js +1 -1
- package/dist/react.cjs +1601 -210
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +115 -9
- package/dist/react.d.ts +115 -9
- package/dist/react.js +262 -46
- package/dist/react.js.map +1 -1
- package/dist/server.cjs +5 -3
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +8 -3
- package/dist/server.d.ts +8 -3
- package/dist/server.js +1 -1
- package/package.json +10 -9
- package/dist/chunk-EXRQJTXF.js +0 -910
- package/dist/chunk-EXRQJTXF.js.map +0 -1
- package/dist/chunk-QRXFL66W.js.map +0 -1
- package/dist/chunk-RIOHG5JH.js +0 -459
- package/dist/chunk-RIOHG5JH.js.map +0 -1
- package/dist/wallets-CbzMtxrf.d.cts +0 -250
- package/dist/wallets-CbzMtxrf.d.ts +0 -250
package/dist/element.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/define.ts","../src/discover.ts","../src/pair.ts","../src/in-order.ts","../src/protocol.ts","../src/signin.ts","../src/access-client.ts","../src/access.ts","../src/element.ts"],"sourcesContent":["// `import '@bwalletx/connect/element'` registers <bwalletx-signin> as a side effect.\nimport { defineBwalletxSignin } from './element.js';\n\nexport * from './element.js';\ndefineBwalletxSignin();\n","import { WalletClient, XDM, 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 * Default wait for a wallet that has not answered yet, ms. bWalletX for Chrome answers `brc100:requestWallet`\n * synchronously and the in-app browser sets `window.CWI` before the page runs, so a found wallet resolves at once;\n * this is only how long \"nothing here\" takes before the pairing QR shows. Was 1200 (0.5.3 and earlier).\n */\nexport const DEFAULT_DISCOVER_MS = 300;\n\n/**\n * Like findBwalletX, but also says which bWalletX answered.\n * Order: a BRC-100 announcement with a bWalletX rdns (answered at once by the extension); then `window.CWI` (set by\n * the in-app browser, and by older builds that do not announce), taken straight away; then, only when framed, the\n * parent's XDM answer (probed in parallel with the wait). Otherwise null after `ms`.\n */\nexport function discoverBwalletX(ms = DEFAULT_DISCOVER_MS): Promise<FoundWallet | null> {\n if (typeof window === 'undefined') return Promise.resolve(null);\n return new Promise((resolve) => {\n let done = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const finish = (r: FoundWallet | null) => {\n if (done) return;\n done = true;\n if (timer !== undefined) clearTimeout(timer);\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 const cwiNow = (): boolean => {\n const cwi = (window as unknown as { CWI?: WalletInterface }).CWI;\n if (cwi) finish({ wallet: cwi, method: 'in-app', rdns: null });\n return !!cwi;\n };\n window.addEventListener('brc100:announceWallet', onAnnounce);\n window.dispatchEvent(new Event('brc100:requestWallet'));\n if (done || cwiNow()) return;\n // Inside bWalletX's in-wallet frame nothing is injected into the page: the wallet answers BRC-100 XDM\n // (postMessage to the parent) instead. Only tried when framed, and only kept if the parent answers.\n // The parent may take a moment to answer, so it gets at least the old 1200 ms; unframed pages never wait on it.\n if (isFramed()) {\n void probeXdm(Math.max(ms, 1200)).then((w) => finish(w ? { wallet: w, method: 'in-app', rdns: null } : null));\n return;\n }\n timer = setTimeout(() => {\n timer = undefined;\n if (!cwiNow()) finish(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 = DEFAULT_DISCOVER_MS): Promise<WalletInterface | null> {\n return (await discoverBwalletX(ms))?.wallet ?? null;\n}\n\nconst isFramed = (): boolean => {\n try {\n return window.parent !== window;\n } catch {\n return true;\n }\n};\n\n/**\n * The only parents that may answer as bWalletX over XDM (security audit 25 Oct 2026). Without this, any page that\n * framed a site using this package became \"the wallet\": it saw every call (payments, sign-in challenges) and could\n * answer with a fake txid. The wallet's own frames: the web wallet, bwallet.space, the iOS/Android app shells and\n * the Chrome extension. Payments must still be checked on your server (verifyPayment), never trusted from the page.\n */\nexport const BWALLETX_PARENT_ORIGINS: readonly string[] = [\n 'https://web.bwalletx.com',\n 'https://desktop.bwalletx.com',\n 'https://bwalletx.com',\n 'https://www.bwallet.space',\n 'https://bwallet.space',\n 'capacitor://localhost', // iOS app shell\n 'https://localhost', // Android app shell\n 'tauri://localhost', // bWalletX Desktop (macOS)\n 'https://tauri.localhost', // bWalletX Desktop (Windows)\n 'chrome-extension://bombmmcjghjdlbmcclnhjodgcelnehgl', // bWalletX for Chrome (fixed id)\n];\n\n/** The parent frame's origin, as the browser reports it (ancestorOrigins, else the referrer), or null. */\nexport const parentOrigin = (): string | null => {\n try {\n const anc = (window.location as Location & { ancestorOrigins?: DOMStringList }).ancestorOrigins;\n if (anc && anc.length > 0) return anc[0] ?? null;\n if (!document.referrer) return null;\n // Not URL.origin: it is \"null\" for non-special schemes (capacitor:, chrome-extension:) in some engines.\n const u = new URL(document.referrer);\n return `${u.protocol}//${u.host}`;\n } catch {\n return null;\n }\n};\n\n/**\n * The parent frame's wallet over BRC-100 XDM, or null when the parent is not bWalletX (BWALLETX_PARENT_ORIGINS) or\n * does not answer within `ms`. Messages go to that exact origin and only its answers are taken.\n */\nexport async function probeXdm(ms = 1200, allowed: readonly string[] = BWALLETX_PARENT_ORIGINS): Promise<WalletInterface | null> {\n const origin = parentOrigin();\n if (!origin || !allowed.includes(origin)) return null;\n try {\n const w = new WalletClient(new XDM(origin) as unknown as WalletInterface);\n const ok = await Promise.race([\n w.isAuthenticated({}).then(\n () => true,\n () => false,\n ),\n new Promise<boolean>((r) => setTimeout(() => r(false), ms)),\n ]);\n return ok ? w : null;\n } catch {\n return null;\n }\n}\n\nlet warmedAt = 0;\n\n/**\n * Wake the wallet before the click (call on pointerenter / focus / touchstart of your Connect button). Chrome stops an\n * idle extension worker after ~30 s, and a cold worker needs 1-3 s to reopen the wallet; this sends a liveness call\n * (isAuthenticated: never shows a prompt, never reveals a key) so that work starts while the pointer is on its way.\n * At most once every 20 s. Does nothing when no bWalletX is in the page.\n */\nexport function prewarmBwalletX(): void {\n if (typeof window === 'undefined' || Date.now() - warmedAt < 20_000) return;\n warmedAt = Date.now();\n void discoverBwalletX(0).then((f) => {\n if (f && f.method === 'extension') void f.wallet.isAuthenticated({}).catch(() => {});\n });\n}\n\n/** Prewarm on hover, keyboard focus and touch. Returns a function that removes the listeners. */\nexport function bindPrewarm(el: EventTarget): () => void {\n const on = () => prewarmBwalletX();\n const evs = ['pointerenter', 'focus', 'touchstart'];\n for (const e of evs) el.addEventListener(e, on, { passive: true });\n return () => evs.forEach((e) => el.removeEventListener(e, on));\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 claimDigest,\n newChannel,\n newClaim,\n pairUrl,\n relaySocketUrl,\n walletClaimFor,\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 sc?: string; // our relay site claim, sent on every connect. Pairings stored before 0.5.4 get one on reconnect.\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 if (p.sc !== undefined && (typeof p.sc !== 'string' || !/^[A-Za-z0-9_-]{22,64}$/.test(p.sc))) 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 // Pairings stored before site claims get one now; the relay binds it on this connect.\n if (!this.p.sc) {\n this.p = { ...this.p, sc: newClaim() };\n this.persist();\n }\n // A fresh expiry lets the relay recreate the channel if it was dropped; the wallet rejoins on its own.\n const e = Math.floor(Date.now() / 1000) + QR_LIFETIME_S - 10;\n const ws = this.socket(relaySocketUrl(this.p.r, this.p.c, 'site', e, this.p.sc));\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 // b-Aware 26 Oct 2026: our own role claim (N3-1), and the digest of the wallet claim only the QR can produce (N3-2).\n const siteClaim = newClaim();\n const sitePub = siteKey.toPublicKey().toString();\n\n return walletClaimFor(channel, sitePub).then(claimDigest).then((wc) => 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, siteClaim, wc));\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(), sc: siteClaim };\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: sitePub, 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\n/** A fresh relay role claim (16 random bytes): the relay then admits this role only with the same claim. */\nexport const newClaim = () => b64url(crypto.getRandomValues(new Uint8Array(16)));\n\nconst WALLET_CLAIM_INFO = 'bwallet-pair-wallet-claim-v1';\nconst hex = (b: Uint8Array) => Array.from(b, (x) => x.toString(16).padStart(2, '0')).join('');\n\n/**\n * The wallet's relay claim for a fresh QR: SHA-256 of the channel and the site's pairing key, both read from the QR.\n * The site sends its digest (`wc`) when it opens the channel; the relay sees only the channel ID, so a stranger who\n * learns that can't take the wallet role before the phone scans (b-Aware 26 Oct 2026, N3-2).\n */\nexport async function walletClaimFor(channel: string, sitePub: string): Promise<string> {\n const d = await crypto.subtle.digest('SHA-256', enc.encode(`${WALLET_CLAIM_INFO}|${channel}|${sitePub}`));\n return b64url(new Uint8Array(d));\n}\n\n/** SHA-256 (hex) of a claim: what the relay stores and what a site sends as `wc`. */\nexport async function claimDigest(claim: string): Promise<string> {\n return hex(new Uint8Array(await crypto.subtle.digest('SHA-256', enc.encode(claim))));\n}\n\n/**\n * The relay socket URL. `claim` binds the role to this client (N3-1: a site always sends one, on every reconnect).\n * A site opening a new channel also passes `walletClaimHash` so only the phone that scanned the QR gets the wallet role.\n */\nexport const relaySocketUrl = (relay: string, channel: string, role: Role, expiry?: number, claim?: string, walletClaimHash?: string) => {\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 if (claim) q.set('claim', claim);\n if (walletClaimHash && role === 'site') q.set('wc', walletClaimHash);\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, DEFAULT_DISCOVER_MS } 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\n/**\n * Progress for the button label. 'finding': looking for a wallet (sub-second); 'opening': a wallet was found and its\n * approval is on the way (\"Opening your wallet…\"); 'pairing': no wallet in this browser, the QR is showing;\n * 'signing': the identity key arrived, the sign-in signature is being asked for.\n */\nexport type SignInStatus = 'finding' | 'opening' | 'pairing' | 'signing';\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 a wallet that has not answered, in ms, before pairing. Default 300 (a present wallet answers at once). */\n discoverMs?: number;\n /** Called as the sign-in moves on, so the button can say \"Opening your wallet…\" straight away. */\n onStatus?: (status: SignInStatus) => void;\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' | 'onStatus'> = {},\n): Promise<{ wallet: WalletInterface; method: SignInMethod }> {\n const status = (s: SignInStatus) => {\n try {\n opts.onStatus?.(s);\n } catch {\n /* a UI callback must never break sign-in */\n }\n };\n if (opts.wallet) {\n status('opening');\n return { wallet: opts.wallet, method: 'wallet' };\n }\n status('finding');\n const found = await discoverBwalletX(opts.discoverMs ?? DEFAULT_DISCOVER_MS);\n if (found) {\n status('opening');\n return { wallet: found.wallet, method: found.method };\n }\n if (opts.reusePairing !== false) {\n const restored = await restorePairing(opts.pairing ?? {});\n if (restored) {\n status('opening');\n return { wallet: restored, method: 'pairing' };\n }\n }\n if (!opts.pairing) {\n throw Object.assign(new Error('bWalletX was not found in this browser'), { code: 'NOT_FOUND' });\n }\n status('pairing');\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 atStage('identity', () => wallet.getPublicKey({ identityKey: true }));\n try {\n opts.onStatus?.('signing');\n } catch {\n /* UI only */\n }\n const c = await atStage('challenge', () => opts.challenge(identityKey));\n const { signature } = await atStage('signature', () =>\n 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 );\n return { identityKey, signature: Array.from(signature), nonce: c.nonce, method, wallet };\n}\n\n/** Where a sign-in failed: the wallet's identity prompt, the site's challenge endpoint, or the wallet's signature. */\nexport type SignInStage = 'identity' | 'challenge' | 'signature' | 'verify';\n\n/** Tags a failure with its stage (err.stage), keeping the original message, so a site can say what actually failed. */\nexport async function atStage<T>(stage: SignInStage, run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n if (!(err as { stage?: string }).stage) Object.assign(err, { stage });\n throw err;\n }\n}\n","/**\n * Browser side of the access protocol: ask the wallet to sign the site's challenge and prove the\n * keys holding the required token, using standard BRC-100 calls only (so any BRC-100 wallet works).\n */\nimport { Hash, PublicKey, Utils, type WalletInterface, type WalletProtocol } from '@bsv/sdk';\nimport {\n ACCESS_PROTOCOL,\n AccessError,\n MAX_HOLDING_PROOFS,\n challengeBytes,\n parseAccessChallenge,\n type AccessErrorBody,\n type AccessResponse,\n type HoldingProof,\n} from './access.js';\nimport { connectBwalletX, type SignInOptions } from './signin.js';\n\n/** The challenge route's answer (createAccessChallenge). */\nexport interface AccessChallengeLike {\n challenge: string;\n}\n\nexport interface RequestAccessOptions {\n /** Ask your server for a challenge. Gets the wallet's identity key. */\n challenge: (identityKey: string) => Promise<AccessChallengeLike>;\n /** Post the signed response to your server. Throw AccessError (or return an error body) to refuse. */\n verify?: (response: AccessResponse) => Promise<unknown>;\n wallet?: WalletInterface;\n pairing?: SignInOptions['pairing'];\n discoverMs?: number;\n /** Basket holding BSV-21 outputs. Default 'bsv21' (bWalletX, 1Sat wallets). */\n tokenBasket?: string;\n}\n\nexport interface RequestAccessResult {\n response: AccessResponse;\n /** Whatever `verify` returned. */\n verified?: unknown;\n wallet: WalletInterface;\n}\n\nconst ONESAT: WalletProtocol = [0, 'onesat'];\nconst LEGACY_ONESAT: WalletProtocol = [0, 'p 1sat'];\n\n/** Map a wallet / fetch failure to a protocol error. */\nexport function toAccessError(e: unknown): AccessError {\n if (e instanceof AccessError) return e;\n const err = e as { code?: string; message?: string; status?: number } | null;\n const msg = String(err?.message ?? e ?? '');\n if (err?.code === 'NOT_FOUND') return new AccessError('not_installed', msg);\n if (/reject|denied|declin|cancel|user/i.test(msg) || err?.code === 'ERR_USER_REJECTED' || err?.status === 4001) {\n return new AccessError('user_rejected', msg);\n }\n return new AccessError('bad_request', msg || 'access failed');\n}\n\n/** Read an AccessErrorBody from a server answer and throw it as AccessError. */\nexport function throwIfAccessError(body: unknown): void {\n const b = body as Partial<AccessErrorBody> | null;\n if (b && typeof b.error === 'string') throw new AccessError(b.error as AccessError['code'], b.message, { have: b.have, need: b.need });\n}\n\nfunction hash160FromP2pkh(script: string): string | null {\n const m = /^76a914([0-9a-f]{40})88ac$/i.exec(script.slice(-50));\n return m ? m[1].toLowerCase() : null;\n}\n\n/**\n * Sign the challenge with every key that locks an output of `tokenId` in the wallet's token basket.\n * Outputs whose derivation can't be reproduced are skipped (the server counts only what is proven).\n */\nexport async function proveHoldings(wallet: WalletInterface, challenge: string, tokenId: string, basket = 'bsv21'): Promise<HoldingProof[]> {\n const bare = tokenId.replace(/^bsv21:/, '');\n const list = await wallet.listOutputs({ basket, include: 'locking scripts', includeCustomInstructions: true, limit: 10000 });\n const byKey = new Map<string, HoldingProof>();\n const data = challengeBytes(challenge);\n for (const out of list.outputs) {\n if (byKey.size >= MAX_HOLDING_PROOFS) break;\n let ci: { id?: string; keyID?: string; protocolID?: WalletProtocol; counterparty?: string } = {};\n try {\n ci = JSON.parse(out.customInstructions ?? '{}');\n } catch {\n continue;\n }\n if (ci.id !== bare || !ci.keyID) continue;\n const want = out.lockingScript ? hash160FromP2pkh(out.lockingScript) : null;\n const counterparty = ci.counterparty ?? 'self';\n for (const protocolID of ci.protocolID ? [ci.protocolID] : [ONESAT, LEGACY_ONESAT]) {\n const { publicKey } = await wallet.getPublicKey({ protocolID, keyID: ci.keyID, counterparty });\n const h = Utils.toHex(Hash.hash160(PublicKey.fromString(publicKey).encode(true) as number[]));\n if (want && h !== want) continue;\n const existing = byKey.get(publicKey);\n if (existing) {\n existing.outpoints!.push(out.outpoint.replace('.', '_'));\n break;\n }\n const { signature } = await wallet.createSignature({ protocolID, keyID: ci.keyID, counterparty, data });\n byKey.set(publicKey, { pubkey: publicKey, signature: Array.from(signature), outpoints: [out.outpoint.replace('.', '_')] });\n break;\n }\n }\n return [...byKey.values()];\n}\n\n/**\n * Run the whole flow: find the wallet, get a challenge, sign it, prove holdings, post to verify.\n * Throws AccessError with a protocol code on every failure.\n */\nexport async function requestAccess(o: RequestAccessOptions): Promise<RequestAccessResult> {\n let wallet: WalletInterface;\n try {\n ({ wallet } = await connectBwalletX({ wallet: o.wallet, pairing: o.pairing, discoverMs: o.discoverMs }));\n } catch (e) {\n throw (e as { code?: string })?.code === 'NOT_FOUND' ? new AccessError('not_installed') : toAccessError(e);\n }\n try {\n const { publicKey: identityKey } = await wallet.getPublicKey({ identityKey: true });\n const { challenge } = await o.challenge(identityKey);\n const c = parseAccessChallenge(challenge);\n if (c.sub && c.sub !== identityKey.toLowerCase()) throw new AccessError('wrong_account');\n if (Date.now() / 1000 >= c.exp) throw new AccessError('expired');\n const { signature } = await wallet.createSignature({\n protocolID: ACCESS_PROTOCOL,\n keyID: c.nonce,\n counterparty: 'anyone',\n data: challengeBytes(challenge),\n });\n const response: AccessResponse = { v: 1, challenge, identityKey, signature: Array.from(signature) };\n if (c.require.token) response.holdings = await proveHoldings(wallet, challenge, c.require.token.id, o.tokenBasket);\n let verified: unknown;\n if (o.verify) {\n verified = await o.verify(response);\n throwIfAccessError(verified);\n }\n return { response, verified, wallet };\n } catch (e) {\n throw toAccessError(e);\n }\n}\n","/**\n * $401 / $402 / $403 access protocol, version 1. Shared by sites (client + server) and wallets.\n * The full spec is docs/ACCESS-PROTOCOL.md. Pure: no I/O, @bsv/sdk types only.\n *\n * 401 identity \"prove who you are (at identity level N, or KYC'd)\"\n * 402 payment \"pay for this\" (the challenge format is reserved; payment itself uses pay())\n * 403 access \"prove you hold N of token X (or N basis points of its supply)\"\n */\nimport type { WalletProtocol } from '@bsv/sdk';\n\nexport const ACCESS_VERSION = 1 as const;\n/** Security level 2, a protocol name used for nothing else. Wallets recognise it and show the kind's video. */\nexport const ACCESS_PROTOCOL: WalletProtocol = [2, 'bwalletx access'];\n/** How long a challenge is valid. */\nexport const ACCESS_CHALLENGE_LIFETIME_S = 120;\n/** At most this many holding proofs are read from one response. */\nexport const MAX_HOLDING_PROOFS = 50;\n\nexport type AccessKind = '401' | '402' | '403';\n\nexport interface TokenRequirement {\n /** 'bsv21:<txid>_<vout>' */\n id: string;\n /** Minimum raw (unscaled, integer string) amount. */\n min?: string;\n /** Minimum in basis points of total supply (1 = 0.01%, 10000 = 100%). */\n minBps?: number;\n}\n\nexport interface AccessRequirement {\n token?: TokenRequirement;\n /** $401 identity level (bit-sign strands): 1 Basic, 2 Verified, 3 Strong, 4 Sovereign (Veriff). */\n identityLevel?: number;\n /** A live KYC credential is required. */\n kyc?: boolean;\n}\n\n/** What the wallet signs, as canonical JSON. Times are seconds since the epoch. */\nexport interface AccessChallenge {\n v: 1;\n kind: AccessKind;\n origin: string;\n nonce: string;\n iat: number;\n exp: number;\n /** The identity key the site expects. A different wallet account is `wrong_account`. */\n sub?: string;\n require: AccessRequirement;\n}\n\n/** A key that locks some of the required token, proving control by signing the same challenge bytes. */\nexport interface HoldingProof {\n /** Compressed public key hex of the key locking the outputs. */\n pubkey: string;\n /** DER signature by that key over SHA-256(challenge bytes), as BRC-100 createSignature returns. */\n signature: number[];\n /** Optional hint: outpoints ('txid_vout') this key holds. Servers must not trust it. */\n outpoints?: string[];\n}\n\n/** What the wallet (via requestAccess) posts back to the site. */\nexport interface AccessResponse {\n v: 1;\n /** The challenge string exactly as issued. */\n challenge: string;\n identityKey: string;\n /** DER signature: createSignature({ protocolID: ACCESS_PROTOCOL, keyID: nonce, counterparty: 'anyone', data: challenge bytes }). */\n signature: number[];\n holdings?: HoldingProof[];\n}\n\nexport type AccessErrorCode =\n | 'not_installed'\n | 'user_rejected'\n | 'wrong_account'\n | 'insufficient_tokens'\n | 'identity_level_too_low'\n | 'kyc_required'\n | 'indexer_unavailable'\n | 'expired'\n | 'replay'\n | 'invalid_signature'\n | 'bad_request';\n\n/** The HTTP status a site should answer each code with. */\nexport const ACCESS_ERROR_STATUS: Record<AccessErrorCode, number> = {\n not_installed: 424,\n user_rejected: 403,\n wrong_account: 409,\n insufficient_tokens: 403,\n identity_level_too_low: 403,\n kyc_required: 403,\n indexer_unavailable: 503,\n expired: 401,\n replay: 401,\n invalid_signature: 401,\n bad_request: 400,\n};\n\nexport interface AccessErrorBody {\n error: AccessErrorCode;\n message: string;\n /** insufficient_tokens: raw amounts; identity_level_too_low: levels. */\n have?: string | number;\n need?: string | number;\n}\n\nexport class AccessError extends Error {\n readonly code: AccessErrorCode;\n readonly have?: string | number;\n readonly need?: string | number;\n constructor(code: AccessErrorCode, message?: string, extra: { have?: string | number; need?: string | number } = {}) {\n super(message ?? code);\n this.name = 'AccessError';\n this.code = code;\n this.have = extra.have;\n this.need = extra.need;\n }\n toJSON(): AccessErrorBody {\n const b: AccessErrorBody = { error: this.code, message: this.message };\n if (this.have !== undefined) b.have = this.have;\n if (this.need !== undefined) b.need = this.need;\n return b;\n }\n}\n\n/** One video + poster + colour per kind, so wallets and sites show the same thing. Paths are inside the package. */\nexport const PROTOCOL_MEDIA: Record<AccessKind, { name: string; color: string; video: string; poster: string }> = {\n '401': { name: 'Identity', color: '#22c55e', video: 'assets/protocol/401.mp4', poster: 'assets/protocol/401.jpg' },\n '402': { name: 'Payment', color: '#3b82f6', video: 'assets/protocol/402.mp4', poster: 'assets/protocol/402.jpg' },\n '403': { name: 'Access', color: '#ef4444', video: 'assets/protocol/403.mp4', poster: 'assets/protocol/403.jpg' },\n};\n\n/** Media URLs on a CDN (unpkg) for a given package version. */\nexport function protocolMediaUrl(kind: AccessKind, which: 'video' | 'poster', version = 'latest'): string {\n return `https://unpkg.com/@bwalletx/connect@${version}/${PROTOCOL_MEDIA[kind][which]}`;\n}\n\n/**\n * Canonical JSON: object keys sorted by code unit, no whitespace, undefined members dropped.\n * Only strings, finite numbers, booleans, null, arrays and plain objects are allowed.\n */\nexport function canonicalJson(v: unknown): string {\n if (v === null) return 'null';\n if (typeof v === 'string' || typeof v === 'boolean') return JSON.stringify(v);\n if (typeof v === 'number') {\n if (!Number.isFinite(v)) throw new Error('canonicalJson: non-finite number');\n return JSON.stringify(v);\n }\n if (Array.isArray(v)) return `[${v.map((x) => canonicalJson(x)).join(',')}]`;\n if (typeof v === 'object') {\n const o = v as Record<string, unknown>;\n const keys = Object.keys(o).filter((k) => o[k] !== undefined).sort();\n return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(o[k])}`).join(',')}}`;\n }\n throw new Error(`canonicalJson: unsupported ${typeof v}`);\n}\n\n/** The bytes every signature in the protocol covers: UTF-8 of the challenge string. */\nexport function challengeBytes(challenge: string): number[] {\n return Array.from(new TextEncoder().encode(challenge));\n}\n\nconst TOKEN_ID = /^bsv21:[0-9a-f]{64}_\\d{1,6}$/;\nconst RAW = /^[1-9]\\d{0,38}$/;\n\n/** Throws AccessError('bad_request') if the requirement is malformed. Returns a normalised copy. */\nexport function normaliseRequirement(r: unknown): AccessRequirement {\n if (!r || typeof r !== 'object') throw new AccessError('bad_request', 'require must be an object');\n const req = r as Record<string, unknown>;\n const out: AccessRequirement = {};\n if (req.token !== undefined) {\n const t = req.token as Record<string, unknown>;\n if (!t || typeof t !== 'object' || typeof t.id !== 'string') throw new AccessError('bad_request', 'require.token.id is required');\n const id = t.id.trim().toLowerCase();\n if (!TOKEN_ID.test(id)) throw new AccessError('bad_request', \"require.token.id must be 'bsv21:<txid>_<vout>'\");\n const hasMin = t.min !== undefined;\n const hasBps = t.minBps !== undefined;\n if (hasMin === hasBps) throw new AccessError('bad_request', 'require.token needs exactly one of min or minBps');\n out.token = { id };\n if (hasMin) {\n if (typeof t.min !== 'string' || !RAW.test(t.min)) throw new AccessError('bad_request', 'require.token.min must be a positive integer string (raw units)');\n out.token.min = t.min;\n } else {\n if (!Number.isInteger(t.minBps) || (t.minBps as number) < 1 || (t.minBps as number) > 10000) {\n throw new AccessError('bad_request', 'require.token.minBps must be an integer 1..10000');\n }\n out.token.minBps = t.minBps as number;\n }\n }\n if (req.identityLevel !== undefined) {\n if (!Number.isInteger(req.identityLevel) || (req.identityLevel as number) < 1 || (req.identityLevel as number) > 10) {\n throw new AccessError('bad_request', 'require.identityLevel must be an integer 1..10');\n }\n out.identityLevel = req.identityLevel as number;\n }\n if (req.kyc !== undefined) {\n if (typeof req.kyc !== 'boolean') throw new AccessError('bad_request', 'require.kyc must be a boolean');\n if (req.kyc) out.kyc = true;\n }\n if (!out.token && !out.identityLevel && !out.kyc) throw new AccessError('bad_request', 'require is empty');\n return out;\n}\n\n/** The kind a requirement implies: any token → 403; otherwise 401. */\nexport function kindFor(r: AccessRequirement): AccessKind {\n return r.token ? '403' : '401';\n}\n\n/** Parse and validate a challenge string. Throws AccessError('bad_request'). Does not check expiry. */\nexport function parseAccessChallenge(s: unknown): AccessChallenge {\n if (typeof s !== 'string' || s.length > 4096) throw new AccessError('bad_request', 'challenge must be a string');\n let c: AccessChallenge;\n try {\n c = JSON.parse(s) as AccessChallenge;\n } catch {\n throw new AccessError('bad_request', 'challenge is not JSON');\n }\n if (!c || typeof c !== 'object' || c.v !== 1) throw new AccessError('bad_request', 'unsupported challenge version');\n if (c.kind !== '401' && c.kind !== '402' && c.kind !== '403') throw new AccessError('bad_request', 'bad kind');\n if (typeof c.origin !== 'string' || typeof c.nonce !== 'string' || !/^[A-Za-z0-9_-]{16,64}$/.test(c.nonce)) {\n throw new AccessError('bad_request', 'bad origin or nonce');\n }\n if (!Number.isInteger(c.iat) || !Number.isInteger(c.exp) || c.exp <= c.iat) throw new AccessError('bad_request', 'bad iat/exp');\n if (c.sub !== undefined && (typeof c.sub !== 'string' || !/^0[23][0-9a-f]{64}$/.test(c.sub))) throw new AccessError('bad_request', 'bad sub');\n c.require = normaliseRequirement(c.require);\n if (canonicalJson(c) !== s) throw new AccessError('bad_request', 'challenge is not canonical');\n return c;\n}\n\n/** Raw amount needed for a token requirement, given total supply (needed only for minBps). Rounds up. */\nexport function tokenNeedRaw(t: TokenRequirement, supplyRaw?: string): string {\n if (t.min) return t.min;\n if (supplyRaw === undefined || !/^\\d+$/.test(supplyRaw)) throw new AccessError('indexer_unavailable', 'token supply unknown');\n const n = BigInt(supplyRaw) * BigInt(t.minBps!);\n const need = (n + 9999n) / 10000n;\n return (need < 1n ? 1n : need).toString();\n}\n\n/** Compare unscaled integer strings. Fails closed on malformed input. */\nexport function atLeastRaw(have: string, need: string): boolean {\n try {\n return BigInt(have) >= BigInt(need);\n } catch {\n return false;\n }\n}\n\n/** A user-readable line for an error code. */\nexport function accessErrorMessage(code: AccessErrorCode, e: { have?: string | number; need?: string | number } = {}): string {\n switch (code) {\n case 'not_installed': return 'No bWalletX (or other BRC-100 wallet) was found.';\n case 'user_rejected': return 'The request was declined in the wallet.';\n case 'wrong_account': return 'The wallet is signed in to a different account than this site expects.';\n case 'insufficient_tokens': return `Not enough tokens: holding ${e.have ?? 0}, need ${e.need ?? '?'}.`;\n case 'identity_level_too_low': return `Identity level ${e.have ?? 0} is below the required level ${e.need ?? '?'}.`;\n case 'kyc_required': return 'A verified identity (KYC) is required.';\n case 'indexer_unavailable': return 'Holdings could not be checked right now. Try again shortly.';\n case 'expired': return 'The request expired. Try again.';\n case 'replay': return 'That request was already used. Try again.';\n case 'invalid_signature': return 'The wallet signature did not verify.';\n case 'bad_request': return 'The request was malformed.';\n }\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 * require-token / min / min-bps with challenge-url: run the $403 access flow instead; emits\n * bwalletx-access-granted or bwalletx-access-denied { code, have, need }\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 a wallet that has not answered. Default 300\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 { bindPrewarm, discoverBwalletX, DEFAULT_DISCOVER_MS } from './discover.js';\nimport { signInWithBwalletX, type Challenge } from './signin.js';\nimport { requestAccess, type AccessChallengeLike } from './access-client.js';\nimport { AccessError } from './access.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\n/** POST that returns the body even on 4xx, so access error codes reach requestAccess. */\nasync function postAccess(url: string, body: unknown): Promise<unknown> {\n const res = await fetch(url, { method: 'POST', credentials: 'include', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });\n return res.json().catch(() => ({ error: 'bad_request', message: `HTTP ${res.status}` }));\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) => ({ '&': '&', '<': '<', '>': '>', '\"': '"' })[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 bindPrewarm(this.button!);\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')) || DEFAULT_DISCOVER_MS;\n const found = await discoverBwalletX(ms);\n if (!found) {\n this.#notFound = true;\n this.#emit('bwalletx-not-found');\n if (this.#attr('require-token')) this.#emit('bwalletx-access-denied', { code: 'not_installed', message: 'No wallet found' });\n return;\n }\n const requireToken = this.#attr('require-token');\n if (requireToken) {\n // $403 gate. The server's own config is authoritative; these attributes are passed along as a hint.\n const verifyUrl = this.#attr('verify-url');\n const min = this.#attr('min');\n const minBps = this.#attr('min-bps');\n const hint = { token: { id: requireToken, ...(minBps ? { minBps: Number(minBps) } : { min: min ?? '1' }) } };\n try {\n const a = await requestAccess({\n wallet: found.wallet,\n challenge: (identityKey) => postJson<AccessChallengeLike>(challengeUrl, { identityKey, require: hint }),\n verify: verifyUrl ? (response) => postAccess(verifyUrl, response) : undefined,\n });\n this.#emit('bwalletx-access-granted', { identityKey: a.response.identityKey, response: a.verified });\n } catch (e) {\n const err = e instanceof AccessError ? e : new AccessError('bad_request', String(e));\n this.#emit('bwalletx-access-denied', { code: err.code, message: err.message, have: err.have, need: err.need });\n }\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","import_sdk","import_sdk","b64url","verifyUrl","response"]}
|
|
1
|
+
{"version":3,"sources":["../src/define.ts","../src/discover.ts","../src/wallets.ts","../src/pair.ts","../src/in-order.ts","../src/protocol.ts","../src/signin.ts","../src/account.ts","../src/metanet.ts","../src/device.ts","../src/choice.ts","../src/modal.ts","../src/access-client.ts","../src/access.ts","../src/connect-flow.ts","../src/element.ts","../src/wallet-button.ts"],"sourcesContent":["// `import '@bwalletx/connect/element'` registers <bwalletx-signin> and <bwalletx-button> as a side effect.\nimport { defineBwalletxSignin } from './element.js';\nimport { defineBwalletxButton } from './wallet-button.js';\n\nexport * from './element.js';\nexport * from './wallet-button.js';\ndefineBwalletxSignin();\ndefineBwalletxButton();\n","import { WalletClient, XDM, 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 * Default wait for a wallet that has not answered yet, ms. bWalletX for Chrome and the in-app browser both answer\n * `brc100:requestWallet` synchronously, so a found wallet resolves at once;\n * this is only how long \"nothing here\" takes before the pairing QR shows. Was 1200 (0.5.3 and earlier).\n */\nexport const DEFAULT_DISCOVER_MS = 300;\n\n/**\n * Like findBwalletX, but also says which bWalletX answered.\n *\n * bWalletX is recognised ONLY by its own markers: a BRC-100 announcement carrying a bWalletX rdns\n * (`com.bwalletx.extension` from the Chrome extension, `space.bwallet.mobile` from the in-app browser; both answer\n * `brc100:requestWallet` at once), or, only when framed, the XDM answer of a parent on BWALLETX_PARENT_ORIGINS.\n *\n * Never by `window.CWI` (0.5.6): another wallet (Metanet / BSV Desktop, Yours) can set or overwrite it, and treating\n * whoever holds it as bWalletX handed our sign-in to that wallet. Every bWalletX build since 3 Oct 2026 announces.\n * Resolves null after `ms` when no bWalletX announced (other wallets: discoverWallets).\n */\nexport function discoverBwalletX(ms = DEFAULT_DISCOVER_MS): Promise<FoundWallet | null> {\n if (typeof window === 'undefined') return Promise.resolve(null);\n return new Promise((resolve) => {\n let done = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const finish = (r: FoundWallet | null) => {\n if (done) return;\n done = true;\n if (timer !== undefined) clearTimeout(timer);\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 if (done) return;\n // Inside bWalletX's in-wallet frame nothing is injected into the page: the wallet answers BRC-100 XDM\n // (postMessage to the parent) instead. Only tried when framed, and only kept if the parent answers.\n // The parent may take a moment to answer, so it gets at least the old 1200 ms; unframed pages never wait on it.\n if (isFramed()) {\n void probeXdm(Math.max(ms, 1200)).then((w) => finish(w ? { wallet: w, method: 'in-app', rdns: null } : null));\n return;\n }\n // A late announcement (an extension frame cleared after the page ran) still counts until the wait ends.\n timer = setTimeout(() => {\n timer = undefined;\n finish(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 = DEFAULT_DISCOVER_MS): Promise<WalletInterface | null> {\n return (await discoverBwalletX(ms))?.wallet ?? null;\n}\n\n/** True inside a frame (or when the parent can't be read). */\nexport const isFramed = (): boolean => {\n try {\n return window.parent !== window;\n } catch {\n return true;\n }\n};\n\n/**\n * The only parents that may answer as bWalletX over XDM (security audit 25 Oct 2026). Without this, any page that\n * framed a site using this package became \"the wallet\": it saw every call (payments, sign-in challenges) and could\n * answer with a fake txid. The wallet's own frames: the web wallet, bwallet.space, the iOS/Android app shells and\n * the Chrome extension. Payments must still be checked on your server (verifyPayment), never trusted from the page.\n */\nexport const BWALLETX_PARENT_ORIGINS: readonly string[] = [\n 'https://web.bwalletx.com',\n 'https://desktop.bwalletx.com',\n 'https://bwalletx.com',\n 'https://www.bwallet.space',\n 'https://bwallet.space',\n 'capacitor://localhost', // iOS app shell\n 'https://localhost', // Android app shell\n 'tauri://localhost', // bWalletX Desktop (macOS)\n 'https://tauri.localhost', // bWalletX Desktop (Windows)\n 'chrome-extension://bombmmcjghjdlbmcclnhjodgcelnehgl', // bWalletX for Chrome (fixed id)\n];\n\n/** The parent frame's origin, as the browser reports it (ancestorOrigins, else the referrer), or null. */\nexport const parentOrigin = (): string | null => {\n try {\n const anc = (window.location as Location & { ancestorOrigins?: DOMStringList }).ancestorOrigins;\n if (anc && anc.length > 0) return anc[0] ?? null;\n if (!document.referrer) return null;\n // Not URL.origin: it is \"null\" for non-special schemes (capacitor:, chrome-extension:) in some engines.\n const u = new URL(document.referrer);\n return `${u.protocol}//${u.host}`;\n } catch {\n return null;\n }\n};\n\n/**\n * The parent frame's wallet over BRC-100 XDM, or null when the parent is not bWalletX (BWALLETX_PARENT_ORIGINS) or\n * does not answer within `ms`. Messages go to that exact origin and only its answers are taken.\n */\nexport async function probeXdm(ms = 1200, allowed: readonly string[] = BWALLETX_PARENT_ORIGINS): Promise<WalletInterface | null> {\n const origin = parentOrigin();\n if (!origin || !allowed.includes(origin)) return null;\n try {\n const w = new WalletClient(new XDM(origin) as unknown as WalletInterface);\n const ok = await Promise.race([\n w.isAuthenticated({}).then(\n () => true,\n () => false,\n ),\n new Promise<boolean>((r) => setTimeout(() => r(false), ms)),\n ]);\n return ok ? w : null;\n } catch {\n return null;\n }\n}\n\nlet warmedAt = 0;\n\n/**\n * Wake the wallet before the click (call on pointerenter / focus / touchstart of your Connect button). Chrome stops an\n * idle extension worker after ~30 s, and a cold worker needs 1-3 s to reopen the wallet; this sends a liveness call\n * (isAuthenticated: never shows a prompt, never reveals a key) so that work starts while the pointer is on its way.\n * At most once every 20 s. Does nothing when no bWalletX is in the page.\n */\nexport function prewarmBwalletX(): void {\n if (typeof window === 'undefined' || Date.now() - warmedAt < 20_000) return;\n warmedAt = Date.now();\n void discoverBwalletX(0).then((f) => {\n if (f && f.method === 'extension') void f.wallet.isAuthenticated({}).catch(() => {});\n });\n}\n\n/** Prewarm on hover, keyboard focus and touch. Returns a function that removes the listeners. */\nexport function bindPrewarm(el: EventTarget): () => void {\n const on = () => prewarmBwalletX();\n const evs = ['pointerenter', 'focus', 'touchstart'];\n for (const e of evs) el.addEventListener(e, on, { passive: true });\n return () => evs.forEach((e) => el.removeEventListener(e, on));\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, RDNS_MOBILE, isFramed, probeXdm } from './discover.js';\nimport { pairBwalletX, restorePairing, type PairingOptions } from './pair.js';\nimport type { PaySource } from './pay.js';\nimport { waitIfLocked } from './signin.js';\n\nexport type WalletKind = 'brc100' | 'pairing' | 'handcash' | 'custom';\n\n/**\n * How a wallet reaches the page. 'extension' / 'in-app': bWalletX announced itself (its own rdns); 'xdm': the bWalletX\n * app frame around the page; 'injected': another wallet that announced itself; 'window.CWI': something set window.CWI\n * without announcing (it can't be told apart from any other wallet); 'json-api' / 'cicada': a desktop wallet on\n * localhost (Metanet / BSV Desktop on 3321, Cicada on 3301); 'pairing': bWalletX on a phone over the relay;\n * 'adapter': an app-supplied option (HandCash today).\n */\nexport type Substrate = 'extension' | 'in-app' | 'xdm' | 'injected' | 'window.CWI' | 'json-api' | 'cicada' | 'pairing' | 'adapter';\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 /** How it reaches the page (0.5.6). Options built by this package always set it. */\n substrate?: Substrate;\n /** The BRC-100 wallet behind a detected option (brc100 kind), when known before connecting. */\n wallet?: WalletInterface;\n /**\n * Open the wallet. By default it also asks for the identity key (one wallet call). Pass `{ identity: false }` when\n * you sign in straight after (BwalletXProvider does): the key then comes with the sign-in signature, in ONE sheet,\n * and `identityKey` is null here.\n */\n connect(opts?: ConnectOptions): Promise<ConnectedWallet>;\n}\n\nexport interface ConnectOptions {\n /** Ask for the identity key now. Default true. */\n identity?: boolean;\n}\n\nasync function brc100Connected(wallet: WalletInterface, o: Pick<WalletOption, 'id' | 'kind'>, c: ConnectOptions = {}): Promise<ConnectedWallet> {\n if (c.identity === false) return { wallet, payer: wallet, identityKey: null, optionId: o.id, kind: o.kind };\n await waitIfLocked(wallet);\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(\n wallet: WalletInterface,\n info: { id: string; name: string; icon?: string; rdns?: string; isBwalletX?: boolean; substrate?: Substrate },\n): 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 substrate: info.substrate,\n wallet,\n connect: (c) => brc100Connected(wallet, opt, c),\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 substrate: 'pairing',\n async connect(c) {\n const p = typeof pairing === 'function' ? pairing() : pairing;\n const w = (await restorePairing(p)) ?? (await pairBwalletX(p));\n return brc100Connected(w, opt, c);\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 substrate: 'adapter',\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 /** Longest wait for BRC-100 announcements, ms. Default 300; ends early once a wallet has announced. */\n ms?: number;\n /**\n * Also probe desktop wallets on localhost (Metanet / json-api on 3321, Cicada on 3301) while listing.\n * Off by default, and best left off: Chrome asks for Local Network Access on the first probe. The chooser\n * (chooseWallet) offers \"Desktop wallet\" instead, which probes only when the user taps it (desktopOption).\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/**\n * True when window.CWI is a wallet that already announced itself, so the picker must not list it twice. bWalletX\n * (extension and in-app) sets window.CWI to the very object it announces; the in-app browser is matched by rdns too.\n */\nexport function cwiIsAnnounced(cwi: WalletInterface, announced: WalletOption[]): boolean {\n return announced.some((o) => o.wallet === cwi || o.rdns === RDNS_MOBILE);\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 ?? 300;\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 const substrate: Substrate = rdns === RDNS_EXTENSION ? 'extension' : rdns === RDNS_MOBILE ? 'in-app' : 'injected';\n seen.set(rdns, brc100Option(d.wallet, { id: rdns, rdns, name: NAMES[rdns] ?? d.info?.name ?? rdns, icon: d.info?.icon, isBwalletX: isB, substrate }));\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 // Wallets answer requestWallet synchronously; once one has, a short grace catches any slower sibling.\n await new Promise((r) => setTimeout(r, seen.size > 0 || (window as unknown as { CWI?: unknown }).CWI ? Math.min(ms, 50) : ms));\n window.removeEventListener('brc100:announceWallet', onAnnounce);\n out.push(...seen.values());\n // Inside the bWalletX app frame nothing is injected: bWalletX answers over XDM, only from its own origins.\n if (![...seen.values()].some((w) => w.isBwalletX) && isFramed()) {\n const x = await probeXdm(Math.max(ms, 1200));\n if (x) out.push(brc100Option(x, { id: 'bwalletx-xdm', name: 'bWalletX', isBwalletX: true, substrate: 'xdm' }));\n }\n // A window.CWI nobody announced is listed under a neutral name and is never taken for bWalletX.\n const cwi = (window as unknown as { CWI?: WalletInterface }).CWI;\n if (cwi && !cwiIsAnnounced(cwi, [...seen.values()])) {\n out.push(brc100Option(cwi, { id: 'window.CWI', name: seen.size ? 'Another browser wallet' : 'Browser wallet', isBwalletX: false, substrate: 'window.CWI' }));\n }\n const [json, cicada] = await local;\n if (json) out.push(brc100Option(json, { id: 'localhost:3321', name: 'Desktop wallet (localhost:3321)', substrate: 'json-api' }));\n if (cicada) out.push(brc100Option(cicada, { id: 'localhost:3301', name: 'Desktop wallet (localhost:3301)', substrate: 'cicada' }));\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/** Id of the \"Desktop wallet\" option (desktopOption). */\nexport const DESKTOP_OPTION_ID = 'desktop';\n\n/**\n * \"Desktop wallet\" (Metanet / BSV Desktop on localhost:3321, Cicada on 3301) as an option that looks for the wallet\n * only when connect() runs, i.e. after the user picked it. Nothing touches localhost before that: the first request\n * makes Chrome ask for Local Network Access, which must follow a tap, never a page load. connect() rejects with\n * code NOT_FOUND when neither port answers within `ms`.\n */\nexport function desktopOption(ms = 1500): WalletOption {\n const opt: WalletOption = {\n id: DESKTOP_OPTION_ID,\n name: 'Desktop wallet',\n kind: 'brc100',\n isBwalletX: false,\n substrate: 'json-api',\n async connect(c) {\n const [json, cicada] = await Promise.all([probe('json-api', ms), probe('Cicada', ms)]);\n const w = json ?? cicada;\n if (!w) throw Object.assign(new Error('No desktop wallet answered on this computer'), { code: 'NOT_FOUND' });\n opt.wallet = w;\n opt.substrate = json ? 'json-api' : 'cicada';\n return brc100Connected(w, opt, c);\n },\n };\n return opt;\n}\n\n/**\n * The 0.5.5 rule, kept for `fastPath: false` (0.5.6 sites use decideWallet, which never picks another wallet unasked).\n * Which option to use without showing the picker, or undefined when the user has a real choice.\n * - nothing found → null;\n * - one option → it;\n * - exactly one wallet detected in this browser and no app-supplied option (HandCash, custom) → that wallet, with no\n * picker: phone pairing is a fallback for \"no wallet here\", not a second choice;\n * - only phone pairing → pairing.\n * `force` (picker off): the first detected wallet, else the first non-pairing option, else pairing.\n */\nexport function autoChoice(list: WalletOption[], force = false): WalletOption | null | undefined {\n // 0.7.0: a desktop wallet on localhost (Metanet on 3321, Cicada on 3301, e.g. found with probeLocal) is never picked\n // without its own tap. It still counts as a choice, so its presence opens the picker instead.\n const auto = list.filter((w) => !isLocalDesktop(w));\n const detected = auto.filter((w) => w.kind === 'brc100');\n const others = auto.filter((w) => w.kind === 'handcash' || w.kind === 'custom');\n const hasLocal = auto.length !== list.length;\n if (force) return detected[0] ?? auto.find((w) => w.kind !== 'pairing') ?? auto[0] ?? null;\n if (!list.length) return null;\n if (list.length === 1) return hasLocal ? undefined : list[0]!;\n if (detected.length === 1 && others.length === 0 && !hasLocal) return detected[0]!;\n if (detected.length === 0 && others.length === 0) return auto[0] ?? undefined;\n return undefined;\n}\n\n/**\n * (0.7.0) A desktop wallet reached over localhost (json-api on 3321 = Metanet Desktop, Cicada on 3301): never picked\n * by the button, the fast path or a remembered choice; only by its own tap (\"Use Metanet Desktop…\").\n */\nexport function isLocalDesktop(w: Pick<WalletOption, 'id' | 'substrate'>): boolean {\n return w.substrate === 'json-api' || w.substrate === 'cicada' || w.id === 'localhost:3321' || w.id === 'localhost:3301' || w.id === DESKTOP_OPTION_ID;\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 claimDigest,\n newChannel,\n newClaim,\n pairUrl,\n relaySocketUrl,\n walletClaimFor,\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 sc?: string; // our relay site claim, sent on every connect. Pairings stored before 0.5.4 get one on reconnect.\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 if (p.sc !== undefined && (typeof p.sc !== 'string' || !/^[A-Za-z0-9_-]{22,64}$/.test(p.sc))) 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 // Pairings stored before site claims get one now; the relay binds it on this connect.\n if (!this.p.sc) {\n this.p = { ...this.p, sc: newClaim() };\n this.persist();\n }\n // A fresh expiry lets the relay recreate the channel if it was dropped; the wallet rejoins on its own.\n const e = Math.floor(Date.now() / 1000) + QR_LIFETIME_S - 10;\n const ws = this.socket(relaySocketUrl(this.p.r, this.p.c, 'site', e, this.p.sc));\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 // b-Aware 26 Oct 2026: our own role claim (N3-1), and the digest of the wallet claim only the QR can produce (N3-2).\n const siteClaim = newClaim();\n const sitePub = siteKey.toPublicKey().toString();\n\n return walletClaimFor(channel, sitePub).then(claimDigest).then((wc) => 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, siteClaim, wc));\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(), sc: siteClaim };\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: sitePub, 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\n/** A fresh relay role claim (16 random bytes): the relay then admits this role only with the same claim. */\nexport const newClaim = () => b64url(crypto.getRandomValues(new Uint8Array(16)));\n\nconst WALLET_CLAIM_INFO = 'bwallet-pair-wallet-claim-v1';\nconst hex = (b: Uint8Array) => Array.from(b, (x) => x.toString(16).padStart(2, '0')).join('');\n\n/**\n * The wallet's relay claim for a fresh QR: SHA-256 of the channel and the site's pairing key, both read from the QR.\n * The site sends its digest (`wc`) when it opens the channel; the relay sees only the channel ID, so a stranger who\n * learns that can't take the wallet role before the phone scans (b-Aware 26 Oct 2026, N3-2).\n */\nexport async function walletClaimFor(channel: string, sitePub: string): Promise<string> {\n const d = await crypto.subtle.digest('SHA-256', enc.encode(`${WALLET_CLAIM_INFO}|${channel}|${sitePub}`));\n return b64url(new Uint8Array(d));\n}\n\n/** SHA-256 (hex) of a claim: what the relay stores and what a site sends as `wc`. */\nexport async function claimDigest(claim: string): Promise<string> {\n return hex(new Uint8Array(await crypto.subtle.digest('SHA-256', enc.encode(claim))));\n}\n\n/**\n * The relay socket URL. `claim` binds the role to this client (N3-1: a site always sends one, on every reconnect).\n * A site opening a new channel also passes `walletClaimHash` so only the phone that scanned the QR gets the wallet role.\n */\nexport const relaySocketUrl = (relay: string, channel: string, role: Role, expiry?: number, claim?: string, walletClaimHash?: string) => {\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 if (claim) q.set('claim', claim);\n if (walletClaimHash && role === 'site') q.set('wc', walletClaimHash);\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, DEFAULT_DISCOVER_MS } 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\n/**\n * Progress for the button label. 'finding': looking for a wallet (sub-second); 'opening': a wallet was found and its\n * approval is on the way (\"Opening your wallet…\"); 'pairing': no wallet in this browser, the QR is showing;\n * 'signing': the challenge arrived, the wallet's sign-in approval is being asked for.\n */\nexport type SignInStatus = 'finding' | 'opening' | 'pairing' | 'signing';\n\nexport interface SignInOptions {\n /**\n * Ask your server for a challenge. Since 0.5.5 it is called BEFORE the wallet is asked anything, and gets an identity\n * key only when you pass `identityKey` (an identity you already connected) or set `challengeNeedsIdentityKey`;\n * otherwise undefined. The 0.5.5 server helpers (createChallenge) accept no key, and verifySignIn binds the key the\n * browser then claims to the signature. A pre-0.5.5 server that refuses a keyless challenge is detected and retried\n * in the old order automatically.\n */\n challenge(identityKey?: string): Promise<Challenge>;\n /**\n * The identity key you already have from an earlier connect (reuse the connected identity): the wallet is then asked\n * for the signature only. Without it, getPublicKey({ identityKey: true }) and createSignature go to the wallet\n * together (Promise.all), so the wallet shows ONE sheet, not three.\n */\n identityKey?: string;\n /**\n * Servers older than 0.5.5 refuse a challenge without an identity key. Set true to use the old order straight away\n * (identity key, then the challenge, then the signature: two wallet calls). Without it, the old order is used only\n * after such a server has refused a keyless challenge.\n */\n challengeNeedsIdentityKey?: boolean;\n /** Skip waitForAuthentication before signing (the provider already waited). Default false. */\n skipWaitForAuthentication?: boolean;\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 a wallet that has not answered, in ms, before pairing. Default 300 (a present wallet answers at once). */\n discoverMs?: number;\n /** Called as the sign-in moves on, so the button can say \"Opening your wallet…\" straight away. */\n onStatus?: (status: SignInStatus) => void;\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' | 'onStatus'> = {},\n): Promise<{ wallet: WalletInterface; method: SignInMethod }> {\n const status = (s: SignInStatus) => {\n try {\n opts.onStatus?.(s);\n } catch {\n /* a UI callback must never break sign-in */\n }\n };\n if (opts.wallet) {\n status('opening');\n return { wallet: opts.wallet, method: 'wallet' };\n }\n status('finding');\n const found = await discoverBwalletX(opts.discoverMs ?? DEFAULT_DISCOVER_MS);\n if (found) {\n status('opening');\n return { wallet: found.wallet, method: found.method };\n }\n if (opts.reusePairing !== false) {\n const restored = await restorePairing(opts.pairing ?? {});\n if (restored) {\n status('opening');\n return { wallet: restored, method: 'pairing' };\n }\n }\n if (!opts.pairing) {\n throw Object.assign(new Error('bWalletX was not found in this browser'), { code: 'NOT_FOUND' });\n }\n status('pairing');\n return { wallet: await pairBwalletX(opts.pairing), method: 'pairing' };\n}\n\n/**\n * Wait for the user to unlock only when the wallet says it is locked. isAuthenticated never shows anything; an\n * unconditional waitForAuthentication is not free: bWalletX answers it by fetching the site's manifest.json and, when\n * that asks for permissions, shows a separate sheet, once per call.\n */\nexport async function waitIfLocked(wallet: WalletInterface): Promise<void> {\n let ok = false;\n try {\n ok = !!(await wallet.isAuthenticated({}))?.authenticated;\n } catch {\n /* not supported or failed: wait below */\n }\n if (!ok) await Promise.resolve().then(() => wallet.waitForAuthentication({})).catch(() => {});\n}\n\n/**\n * True when a server refused a challenge because it wanted an identity key (createChallenge before 0.5.5 answers 400\n * \"identityKey must be a compressed public key (66 hex chars)\").\n */\nexport function challengeWantsIdentityKey(e: unknown): boolean {\n const msg = e instanceof Error ? e.message : String(e ?? '');\n return /identityKey/i.test(msg);\n}\n\n/**\n * Sign the server's challenge with the user's bWalletX identity key. Post the result's identityKey, nonce and\n * signature to your verify route.\n *\n * Wallet calls, in order:\n * 1. the challenge comes from your server first (no wallet call);\n * 2. getPublicKey({ identityKey: true }) and createSignature go to the wallet TOGETHER, so the wallet merges them\n * into one approval. With `identityKey` (already connected) only createSignature is asked for.\n */\nexport async function signInWithBwalletX(opts: SignInOptions): Promise<SignInResult> {\n const { wallet, method } = await connectBwalletX(opts);\n if (method !== 'pairing' && !opts.skipWaitForAuthentication) await waitIfLocked(wallet);\n const status = () => {\n try {\n opts.onStatus?.('signing');\n } catch {\n /* UI only */\n }\n };\n const sign = (c: Challenge) =>\n 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\n const keyFirst = async (): Promise<SignInResult> => {\n // Servers before 0.5.5: key first, then the challenge for it, then the signature.\n const { publicKey: identityKey } = await atStage('identity', () => wallet.getPublicKey({ identityKey: true }));\n status();\n const c = await atStage('challenge', () => opts.challenge(identityKey));\n const { signature } = await atStage('signature', () => sign(c));\n return { identityKey, signature: Array.from(signature), nonce: c.nonce, method, wallet };\n };\n\n if (opts.challengeNeedsIdentityKey && !opts.identityKey) return keyFirst();\n\n // One sheet: the challenge comes first (no wallet call), then the key and the signature are asked for together.\n let c: Challenge;\n try {\n c = await atStage('challenge', () => opts.challenge(opts.identityKey));\n } catch (e) {\n if (!opts.identityKey && challengeWantsIdentityKey(e)) return keyFirst();\n throw e;\n }\n status();\n const [{ publicKey: identityKey }, { signature }] = await Promise.all([\n opts.identityKey\n ? Promise.resolve({ publicKey: opts.identityKey })\n : atStage('identity', () => wallet.getPublicKey({ identityKey: true })),\n atStage('signature', () => sign(c)),\n ]);\n return { identityKey, signature: Array.from(signature), nonce: c.nonce, method, wallet };\n}\n\nexport interface SignInAndVerifyOptions extends SignInOptions {\n /** POST the result to your verify route; resolve with its JSON. A 401 (status on the error) means \"sign-in failed\". */\n verify: (r: SignInResult) => Promise<Record<string, unknown>>;\n /**\n * A remembered identity key (rememberedIdentity()). Used like `identityKey` (one wallet call: the signature only),\n * but if the server rejects the signature (another account is active now), it is dropped and the sign-in is retried\n * with the key asked for.\n */\n identityKeyHint?: string;\n}\n\n/** signInWithBwalletX + your verify route, with the identity-hint fallback. */\nexport async function signInAndVerify(opts: SignInAndVerifyOptions): Promise<{ result: SignInResult; verified: Record<string, unknown> }> {\n const hinted = !opts.identityKey && !!opts.identityKeyHint;\n const r = await signInWithBwalletX({ ...opts, identityKey: opts.identityKey ?? opts.identityKeyHint });\n try {\n return { result: r, verified: await atStage('verify', () => opts.verify(r)) };\n } catch (e) {\n const status = (e as { status?: number })?.status;\n if (!hinted || status !== 401) throw e;\n const again = await signInWithBwalletX({ ...opts, wallet: r.wallet, identityKey: undefined, skipWaitForAuthentication: true });\n return { result: again, verified: await atStage('verify', () => opts.verify(again)) };\n }\n}\n\n/** Where a sign-in failed: the wallet's identity prompt, the site's challenge endpoint, or the wallet's signature. */\nexport type SignInStage = 'identity' | 'challenge' | 'signature' | 'verify';\n\n/** Tags a failure with its stage (err.stage), keeping the original message, so a site can say what actually failed. */\nexport async function atStage<T>(stage: SignInStage, run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n if (!(err as { stage?: string }).stage) Object.assign(err, { stage });\n throw err;\n }\n}\n","/**\n * The signed-in account as the badge shows it: paymail (best-effort lookup by identity key), a $handle label, a short\n * key when there is no paymail, and the bAvatar picture (gold by default, generated for any key).\n */\n\nexport const PAYMAIL_LOOKUP_URL = 'https://pay.bwallet.space/api/paymail/lookup?key=';\nexport const BAVATAR_URL = 'https://chat.bwalletx.com/api/bavatar/';\n\n/** 0266c1…7c83 */\nexport function shortKey(key: string): string {\n return key.length > 12 ? `${key.slice(0, 6)}…${key.slice(-4)}` : key;\n}\n\n/** $alice for alice@bwalletx.com, a site handle as given, other paymails in full, else a short key. */\nexport function accountLabel(a: { identityKey?: string | null; paymail?: string | null; handle?: string | null }): string {\n if (a.paymail && /@bwalletx\\.com$/i.test(a.paymail)) return '$' + a.paymail.split('@')[0];\n if (a.handle) return a.handle;\n if (a.paymail) return a.paymail;\n return a.identityKey ? shortKey(a.identityKey) : '';\n}\n\n/** The bAvatar for an identity key (a generated gold avatar when the user has not set one). */\nexport function avatarUrlFor(identityKey: string | null | undefined): string | null {\n return identityKey && /^0[23][0-9a-fA-F]{64}$/.test(identityKey) ? `${BAVATAR_URL}${identityKey.toLowerCase()}.png` : null;\n}\n\nconst cache = new Map<string, Promise<string | null>>();\n\n/** The paymail for an identity key, or null. Best effort: never throws, one request per key per page. */\nexport function lookupPaymail(identityKey: string, url: string = PAYMAIL_LOOKUP_URL): Promise<string | null> {\n if (url === 'off' || typeof fetch === 'undefined') return Promise.resolve(null);\n const k = `${url}|${identityKey}`;\n let p = cache.get(k);\n if (!p) {\n p = fetch(url + encodeURIComponent(identityKey))\n .then((r) => (r.ok ? r.json() : null))\n .then((j: { paymail?: unknown } | null) => (j && typeof j.paymail === 'string' ? j.paymail : null))\n .catch(() => null);\n cache.set(k, p);\n }\n return p;\n}\n\n/** True when the user said no in the wallet (BRC-100 denial, or a picker / sheet closed). */\nexport function isUserRejection(e: unknown): boolean {\n const code = (e as { code?: unknown } | null)?.code;\n if (code === 'ERR_PERMISSION_DENIED' || code === 4001) return true;\n const msg = e instanceof Error ? e.message : String(e ?? '');\n return /denied|reject|cancel|declin|refused|not now|user closed/i.test(msg);\n}\n\n/** One plain line for an error: \"Sign-in cancelled\" for a no in the wallet, otherwise the gist. */\nexport function signInErrorText(e: unknown): string {\n if (isUserRejection(e)) return 'Sign-in cancelled';\n // 0.7.0: the Metanet option says the one thing to fix (\"Open it, then try again\").\n if ((e as { name?: unknown } | null)?.name === 'MetanetUnreachableError') return (e as Error).message;\n const code = (e as { code?: unknown } | null)?.code;\n if (code === 'NOT_FOUND') return 'bWalletX was not found in this browser';\n const msg = e instanceof Error ? e.message : String(e ?? '');\n if (/lock/i.test(msg)) return 'Your wallet is locked. Unlock it and try again';\n if (/timeout|timed out|expired/i.test(msg)) return 'The wallet did not answer in time';\n if (/origin/i.test(msg)) return 'This page is not on the site’s configured origin';\n return 'Sign-in failed';\n}\n\n/** Copy text to the clipboard; true on success. */\nexport async function copyText(text: string): Promise<boolean> {\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch {\n return false;\n }\n}\n\n/** localStorage key for the identity key that last signed in on this site (public data; a hint, never trusted). */\nexport const IDENTITY_HINT_KEY = 'bwx:identityKey';\n\n/**\n * The identity key that last signed in on this site, if any. Passing it to signInWithBwalletX makes a repeat sign-in\n * ONE wallet call (createSignature only). It is only a hint: the server still checks the signature against it, and a\n * wrong hint (another account) fails verification and is retried with the key asked for.\n */\nexport function rememberedIdentity(): string | undefined {\n try {\n const k = globalThis.localStorage?.getItem(IDENTITY_HINT_KEY) ?? '';\n return /^0[23][0-9a-f]{64}$/i.test(k) ? k : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function rememberIdentity(key: string | null): void {\n try {\n if (key) globalThis.localStorage?.setItem(IDENTITY_HINT_KEY, key);\n else globalThis.localStorage?.removeItem(IDENTITY_HINT_KEY);\n } catch {\n /* storage blocked */\n }\n}\n","/**\n * 0.7.0: \"Use Metanet Desktop or another BRC-100 wallet\" (owner, 6 Nov 2026: \"ship a new one now with the metanet\n * option\"). The same rules as the live bChatX door (bit-sign src/lib/metanet-door.ts):\n *\n * 1. bWalletX stays the default. It is found by its own announcement only, never by window.CWI, and the gold\n * button's discovery NEVER picks Metanet (matchRemembered returns null for it).\n * 2. A visible, explicit choice. PINNED to WalletClient('json-api') on localhost:3321, never 'auto': 'auto' races\n * the substrates starting with window.CWI, so the bWalletX extension would silently win and this would be a\n * label, not a choice. On a first visit it connects ONLY on its own tap; nothing calls :3321 on page load.\n * 3. After a successful connect: the wallet TYPE for this origin (bwx:wallet = { type: 'metanet', substrate:\n * 'json-api' }) plus the identity keys known on this origin (bwx:known-keys). Public keys only; never a secret.\n * 4. Back with Metanet remembered: at most ONE silent attempt per page load, a 2 s window, and it goes on only if the\n * identity key Metanet returns is already known here. Whatever answers on :3321 could be another profile, our own\n * `bwalletx serve` agent wallet or any local process; letting an unknown key sign in silently would land the\n * person in THAT key's account (login CSRF). Any failure is silent: no banner, no retry.\n * 5. \"Not you? Use another wallet\" and Disconnect forget the choice.\n * 6. Offered only on a computer and outside any frame (Metanet Desktop is a desktop app).\n * 7. The minimum asked: getVersion (is it running?), isAuthenticated (never prompts), the identity public key, then\n * whatever the site's own call needs (the sign-in signature). No protocol permission requests at connect, and the\n * calls go one at a time: two prompts at once is how Metanet Desktop froze on a \"Trust\" sheet (6 Nov 2026).\n */\nimport { WalletClient, type WalletInterface } from '@bsv/sdk';\nimport { rememberedIdentity } from './account.js';\nimport { isTouchDevice } from './device.js';\nimport { waitIfLocked } from './signin.js';\nimport type { ConnectedWallet, WalletOption } from './wallets.js';\n\n/** The wallet type remembered for Metanet Desktop (and any BRC-100 wallet serving the JSON API on :3321). */\nexport const METANET_TYPE = 'metanet';\n/** WalletOption.id of the Metanet option. */\nexport const METANET_OPTION_ID = METANET_TYPE;\n/** Where Metanet Desktop serves the BRC-100 JSON API. */\nexport const METANET_JSON_API = 'http://localhost:3321';\n\nexport const METANET_LABEL = 'Use Metanet Desktop or another BRC-100 wallet';\nexport const METANET_NOTE = 'Metanet Desktop must be running on this computer';\n/** Shown when Metanet is the wallet remembered on this site. */\nexport const METANET_REMEMBERED_NOTE = 'Signs in with Metanet Desktop on this computer.';\nexport const NOT_YOU_LABEL = 'Not you? Use another wallet';\nexport const METANET_UNREACHABLE = 'We couldn’t reach Metanet Desktop. Open it, then try again.';\n\n/** How long Metanet Desktop has to answer getVersion after a tap. */\nexport const METANET_ANSWER_MS = 4_000;\n/** The silent attempt's whole window (reachable, unlocked, identity key): short, since nobody asked for it. */\nexport const METANET_SILENT_MS = 2_000;\n\n/** Nothing answered on localhost:3321 in time. `code` is NOT_FOUND, like every \"no wallet here\". */\nexport class MetanetUnreachableError extends Error {\n readonly code = 'NOT_FOUND';\n constructor() {\n super(METANET_UNREACHABLE);\n this.name = 'MetanetUnreachableError';\n }\n}\n\n/** Inside any frame at all (bWalletX's or anyone's), or the top can't be read. */\n/** The two window fields the frame check reads. */\nexport type FrameWindow = { readonly self: unknown; readonly top: unknown };\n\nexport function inAnyFrame(win: FrameWindow | undefined = typeof window === 'undefined' ? undefined : window): boolean {\n if (!win) return false;\n try {\n return win.top !== win.self;\n } catch {\n return true;\n }\n}\n\n/** Where the Metanet option is offered at all: a browser on a computer (not a phone or tablet), outside any frame. */\nexport function metanetOffered(\n env: { navigator?: Navigator; matchMedia?: (q: string) => MediaQueryList; window?: FrameWindow } = {},\n): boolean {\n const win = env.window ?? (typeof window === 'undefined' ? undefined : window);\n if (!win) return false; // a server render: nothing to offer yet\n const nav = env.navigator ?? (typeof navigator === 'undefined' ? undefined : navigator);\n const mm = env.matchMedia ?? (typeof matchMedia === 'undefined' ? undefined : (q: string) => matchMedia(q));\n return !isTouchDevice({ navigator: nav, matchMedia: mm }) && !inAnyFrame(win);\n}\n\nexport interface MetanetOptions {\n /** This site's host, as WalletClient's originator (the browser sets the real Origin header). Default location.host. */\n originator?: string;\n /** How long Metanet has to answer getVersion. Default METANET_ANSWER_MS. */\n timeoutMs?: number;\n /** Tests and custom hosts: stands in for `new WalletClient('json-api', originator)`. */\n make?: () => WalletInterface;\n}\n\nfunction client(o: MetanetOptions): WalletInterface {\n if (o.make) return o.make();\n const originator = o.originator ?? (typeof location !== 'undefined' && location.host ? location.host : undefined);\n // Pinned: 'json-api' is HTTPWalletJSON on localhost:3321. It never falls back to an extension or window.CWI.\n return new WalletClient('json-api', originator);\n}\n\nasync function answers(wallet: WalletInterface): Promise<boolean> {\n return Promise.resolve()\n .then(() => wallet.getVersion({}))\n .then((v) => typeof v?.version === 'string', () => false);\n}\n\n/**\n * The wallet on localhost:3321 once it has answered getVersion; MetanetUnreachableError if nothing does in time.\n * ⚠ WalletClient builds a pinned substrate in its constructor, so connectToSubstrate proves nothing: this asks.\n */\nexport async function connectMetanetDesktop(o: MetanetOptions = {}): Promise<WalletInterface> {\n let wallet: WalletInterface;\n try {\n wallet = client(o);\n } catch {\n throw new MetanetUnreachableError();\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n const ok = await Promise.race([answers(wallet), new Promise<false>((r) => (timer = setTimeout(() => r(false), o.timeoutMs ?? METANET_ANSWER_MS)))]);\n clearTimeout(timer);\n if (!ok) throw new MetanetUnreachableError();\n return wallet;\n}\n\n/**\n * \"Use Metanet Desktop or another BRC-100 wallet\" as a WalletOption. Nothing touches localhost until connect() runs,\n * i.e. after the tap. connect() always asks for the identity key first, on its own (also with `{ identity: false }`):\n * the sign-in then asks for the signature alone, so Metanet never gets two requests at once.\n */\nexport function metanetOption(o: MetanetOptions = {}): WalletOption {\n const opt: WalletOption = {\n id: METANET_OPTION_ID,\n name: METANET_LABEL,\n kind: 'brc100',\n isBwalletX: false,\n substrate: 'json-api',\n async connect(): Promise<ConnectedWallet> {\n const wallet = await connectMetanetDesktop(o);\n opt.wallet = wallet;\n await waitIfLocked(wallet);\n const { publicKey } = await wallet.getPublicKey({ identityKey: true });\n return { wallet, payer: wallet, identityKey: publicKey, optionId: opt.id, kind: 'brc100' };\n },\n };\n return opt;\n}\n\n/* ---------------------------------------------------------------------------------------------------------------\n * Identity keys known on this origin (public keys, a hint for the silent attempt only).\n * ------------------------------------------------------------------------------------------------------------- */\n\n/** localStorage key (per origin) for the identity keys that connected or signed in here. Public keys only. */\nexport const KNOWN_KEYS_KEY = 'bwx:known-keys';\nconst KEY_RE = /^0[23][0-9a-f]{64}$/;\nconst MAX_KNOWN = 8;\n\n/** The identity keys known on this origin, newest first. */\nexport function knownIdentityKeys(): string[] {\n try {\n const v = JSON.parse(globalThis.localStorage?.getItem(KNOWN_KEYS_KEY) || '[]') as unknown;\n return Array.isArray(v) ? v.filter((k): k is string => typeof k === 'string' && KEY_RE.test(k)) : [];\n } catch {\n return [];\n }\n}\n\n/** True when this identity key connected or signed in on this origin before (or is the last sign-in's key). */\nexport function isKnownIdentityKey(key: string | null | undefined): boolean {\n if (!key) return false;\n const k = key.toLowerCase();\n if (!KEY_RE.test(k)) return false;\n return knownIdentityKeys().includes(k) || rememberedIdentity()?.toLowerCase() === k;\n}\n\n/** Add an identity key to this origin's known keys (after a successful connect or sign-in). */\nexport function rememberKnownIdentityKey(key: string | null | undefined): void {\n const k = (key ?? '').toLowerCase();\n if (!KEY_RE.test(k)) return;\n try {\n const list = [k, ...knownIdentityKeys().filter((x) => x !== k)].slice(0, MAX_KNOWN);\n globalThis.localStorage?.setItem(KNOWN_KEYS_KEY, JSON.stringify(list));\n } catch {\n /* storage blocked: the next visit just needs a tap */\n }\n}\n\n/* ---------------------------------------------------------------------------------------------------------------\n * The silent attempt (rule 4).\n * ------------------------------------------------------------------------------------------------------------- */\n\nlet triedThisLoad = false;\n\n/** True once this page load's one silent attempt has been used (however many buttons or providers mount). */\nexport function silentAttemptUsed(): boolean {\n return triedThisLoad;\n}\n\n/** Claim this page load's one silent attempt. False if it was already used. */\nexport function claimSilentAttempt(): boolean {\n if (triedThisLoad) return false;\n triedThisLoad = true;\n return true;\n}\n\n/** Tests only (and a single-page app that wants a fresh \"page load\"). */\nexport function resetSilentAttempt(): void {\n triedThisLoad = false;\n}\n\n/** Why a silent attempt stopped. Every one of them is silent: the normal choice stays on screen. */\nexport type SilentStop = 'used' | 'not-here' | 'unreachable' | 'locked' | 'slow' | 'unknown-key';\n\nexport type SilentMetanetResult = { ok: true; wallet: WalletInterface; identityKey: string } | { ok: false; stop: SilentStop };\n\n/**\n * The silent part of a return visit: claim the page load's one attempt, then, within `windowMs` (2 s) in all,\n * Metanet must answer getVersion, say it is unlocked (isAuthenticated, which never prompts) and return an identity\n * key already known on this origin. Never waits for an unlock, never asks for anything else, never throws.\n */\nexport async function trySilentMetanet(o: MetanetOptions & { windowMs?: number } = {}): Promise<SilentMetanetResult> {\n if (!metanetOffered()) return { ok: false, stop: 'not-here' };\n if (!claimSilentAttempt()) return { ok: false, stop: 'used' };\n const run = async (): Promise<SilentMetanetResult> => {\n let wallet: WalletInterface;\n try {\n wallet = client(o);\n } catch {\n return { ok: false, stop: 'unreachable' };\n }\n if (!(await answers(wallet))) return { ok: false, stop: 'unreachable' };\n const unlocked = await Promise.resolve()\n .then(() => wallet.isAuthenticated({}))\n .then((r) => r?.authenticated === true, () => false);\n if (!unlocked) return { ok: false, stop: 'locked' };\n const identityKey = await Promise.resolve()\n .then(() => wallet.getPublicKey({ identityKey: true }))\n .then((r) => r.publicKey, () => null);\n if (!identityKey) return { ok: false, stop: 'unreachable' };\n if (!isKnownIdentityKey(identityKey)) return { ok: false, stop: 'unknown-key' };\n return { ok: true, wallet, identityKey };\n };\n let timer: ReturnType<typeof setTimeout> | undefined;\n const r = await Promise.race([\n run().catch((): SilentMetanetResult => ({ ok: false, stop: 'unreachable' })),\n new Promise<SilentMetanetResult>((res) => (timer = setTimeout(() => res({ ok: false, stop: 'slow' }), o.windowMs ?? METANET_SILENT_MS))),\n ]);\n clearTimeout(timer);\n return r;\n}\n\n/* ---------------------------------------------------------------------------------------------------------------\n * logoutUrl is required with verifyUrl.\n * ------------------------------------------------------------------------------------------------------------- */\n\nlet warnedLogout = false;\n\nconst isProduction = (): boolean => {\n try {\n return (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env?.NODE_ENV === 'production';\n } catch {\n return false;\n }\n};\n\n/**\n * (0.7.0) A sign-in with a verify route and no logout route: \"Not you?\" (and Disconnect) cannot end a session the\n * verify route already set, so the person stays signed in as the key they just rejected. Warns once per page, in\n * development only. Returns true when it warned.\n */\nexport function warnIfNoLogout(o: { verifyUrl?: string | null; logoutUrl?: string | null; where: string }): boolean {\n if (!o.verifyUrl || o.logoutUrl || warnedLogout || isProduction() || typeof console === 'undefined') return false;\n warnedLogout = true;\n console.warn(\n `@bwalletx/connect: ${o.where} has a verify URL but no logout URL. Set it: \"Not you? Use another wallet\" and ` +\n 'Disconnect must be able to end a session the verify route created.',\n );\n return true;\n}\n\n/** Tests only. */\nexport function resetLogoutWarning(): void {\n warnedLogout = false;\n}\n","/** Device checks shared by the modal and the Metanet Desktop option (no DOM created here). */\n/**\n * True on a phone or tablet: a coarse pointer with no hover, or a mobile user agent (iPadOS reports\n * a Mac UA, so touch points count too). Scanning a QR shown on the same screen is impossible there.\n */\nexport function isTouchDevice(env: { navigator?: Navigator; matchMedia?: (q: string) => MediaQueryList } = globalThis as never): boolean {\n const nav = env.navigator;\n if (!nav) return false;\n const ua = nav.userAgent ?? '';\n if (/Android|iPhone|iPad|iPod|Mobile|Silk|Kindle/i.test(ua)) return true;\n if (/Macintosh/.test(ua) && (nav.maxTouchPoints ?? 0) > 1) return true;\n try {\n return !!env.matchMedia?.('(pointer: coarse)').matches && !env.matchMedia?.('(hover: hover)').matches;\n } catch {\n return false;\n }\n}\n","/**\n * Which wallet a sign-in uses (RB, 5 Nov 2026: bWalletX is the default on our sites; no other wallet may take the\n * sign-in flow).\n *\n * 1. bWalletX is recognised by its OWN marker only: its BRC-100 announcement (rdns com.bwalletx.extension or\n * space.bwallet.mobile) or the bWalletX app frame (XDM, allowlisted origins). Never by who holds window.CWI.\n * 2. bWalletX here → straight to its sheet. No site chooser; \"Other wallets\" is a small link beside the button.\n * 3. No bWalletX → the chooser, \"Get bWalletX\" first, then whatever was detected. Another wallet is never connected\n * without the user picking it.\n * 4. Nothing probes localhost until the user taps \"Desktop wallet\" (desktopOption).\n * 5. (0.6.0) A returning visitor goes straight to the wallet they explicitly picked on this origin before. Only the\n * wallet TYPE is remembered (localStorage, so per origin), never a key. Nothing that could prompt fires on load.\n * 6. (0.7.0) Metanet Desktop is never picked by the button's discovery, remembered or not: it is reached by its own\n * tap (\"Use Metanet Desktop or another BRC-100 wallet\") or by the one silent, known-key-only attempt (metanet.ts).\n *\n * Pure functions: the provider, runConnect and <bwalletx-signin> all decide with decideWallet().\n */\nimport { RDNS_EXTENSION, RDNS_MOBILE } from './discover.js';\nimport { isUserRejection } from './account.js';\nimport { autoChoice, discoverWallets, isLocalDesktop, DESKTOP_OPTION_ID, type Substrate, type WalletOption } from './wallets.js';\nimport { METANET_TYPE, metanetOffered } from './metanet.js';\n\n/** The wallet type every bWalletX (extension, in-app, app frame, phone) reports. */\nexport const BWALLETX_TYPE = 'bwalletx';\n\n/** How the option reaches the page (WalletOption.substrate, inferred for options built elsewhere). */\nexport function substrateOf(o: WalletOption): Substrate {\n if (o.substrate) return o.substrate;\n if (o.kind === 'pairing') return 'pairing';\n // An option the app built itself and marked as bWalletX (e.g. from findBwalletX()): its own assertion, not a guess\n // from window.CWI (discoverWallets never marks window.CWI as bWalletX).\n if (o.isBwalletX && o.kind === 'brc100') return o.rdns === RDNS_MOBILE ? 'in-app' : o.id === 'bwalletx-xdm' ? 'xdm' : 'extension';\n if (o.kind === 'handcash' || o.kind === 'custom') return 'adapter';\n if (o.rdns === RDNS_EXTENSION) return 'extension';\n if (o.rdns === RDNS_MOBILE) return 'in-app';\n if (o.id === 'window.CWI') return 'window.CWI';\n if (o.id === 'localhost:3321' || o.id === DESKTOP_OPTION_ID) return 'json-api';\n if (o.id === 'localhost:3301') return 'cicada';\n return 'injected';\n}\n\n/** 'bwalletx' for any bWalletX; otherwise the wallet's rdns, else its option id ('desktop', 'window.CWI', 'handcash'). */\nexport function walletTypeOf(o: WalletOption): string {\n return o.isBwalletX ? BWALLETX_TYPE : (o.rdns ?? o.id);\n}\n\nconst OWN_MARKERS: readonly Substrate[] = ['extension', 'in-app', 'xdm'];\n\n/**\n * bWalletX found in this browser by its own marker (announcement or app frame). A wallet that only sits on\n * window.CWI never counts, whatever it claims to be.\n */\nexport function isPresentBwalletX(o: WalletOption): boolean {\n return o.isBwalletX && o.kind === 'brc100' && !!o.wallet && OWN_MARKERS.includes(substrateOf(o));\n}\n\n/** True when bWalletX itself is in this browser (not just phone pairing). */\nexport function hasBwalletX(list: readonly WalletOption[]): boolean {\n return list.some(isPresentBwalletX);\n}\n\n/** Wallets other than bWalletX that are actually in this browser (announced, window.CWI, or a probed desktop wallet). */\nexport function otherDetected(list: readonly WalletOption[]): WalletOption[] {\n return list.filter((o) => !o.isBwalletX && o.kind === 'brc100' && !!o.wallet);\n}\n\n/** The chooser's order: bWalletX here, phone pairing, other detected wallets, app-supplied options last. */\nexport function chooserOrder(list: readonly WalletOption[]): WalletOption[] {\n const rank = (o: WalletOption) => (isPresentBwalletX(o) ? 0 : o.isBwalletX ? 1 : o.kind === 'brc100' ? 2 : o.kind === 'custom' ? 3 : 4);\n return list.map((o, i) => ({ o, i })).sort((a, b) => rank(a.o) - rank(b.o) || a.i - b.i).map((x) => x.o);\n}\n\n/**\n * Why decideWallet chose what it did. 'requested': walletId; 'bwalletx': bWalletX is here (fast path);\n * 'bwalletx-phone': picker off and no bWalletX here, so the phone; 'legacy': fastPath false (0.5.5 autoChoice);\n * 'chooser': show the chooser; 'none': nothing to offer.\n */\nexport type ChoiceReason = 'requested' | 'remembered' | 'bwalletx' | 'bwalletx-phone' | 'legacy' | 'chooser' | 'none';\n\nexport interface WalletChoice {\n option: WalletOption | null;\n reason: ChoiceReason;\n}\n\nexport interface DecideWalletOptions {\n /** Use this option (an explicit choice the site already has). */\n walletId?: string;\n /** \"Other wallets\": the user asked for the chooser, so show it even with bWalletX here. */\n chooser?: boolean;\n /** false: never show the chooser (bWalletX, else the phone, else nothing; never another wallet). */\n picker?: boolean;\n /** The bWalletX-first rule. Default true; false restores the 0.5.5 behaviour (autoChoice). */\n fastPath?: boolean;\n /** (0.6.0) The wallet the user picked on this origin before (rememberedWalletChoice()). Used when it is here. */\n remembered?: RememberedWallet | null;\n /** (0.6.0) \"Switch\" to bWalletX: ignore a remembered other wallet. */\n preferBwalletX?: boolean;\n}\n\n/** The wallet to connect now, or the chooser ({ option: null, reason: 'chooser' }). */\nexport function decideWallet(list: readonly WalletOption[], o: DecideWalletOptions = {}): WalletChoice {\n if (o.walletId) {\n const w = list.find((x) => x.id === o.walletId);\n if (w) return { option: w, reason: 'requested' };\n }\n if (o.chooser) return { option: null, reason: list.length || o.picker !== false ? 'chooser' : 'none' };\n if (o.fastPath === false) {\n const a = autoChoice([...list], o.picker === false);\n return a === undefined ? { option: null, reason: 'chooser' } : a === null ? { option: null, reason: 'none' } : { option: a, reason: 'legacy' };\n }\n if (o.remembered && !o.preferBwalletX) {\n const m = matchRemembered(list, o.remembered);\n if (m) return { option: m, reason: 'remembered' };\n }\n const b = list.find(isPresentBwalletX);\n if (b) return { option: b, reason: 'bwalletx' };\n if (o.picker === false) {\n const phone = list.find((x) => x.isBwalletX);\n return phone ? { option: phone, reason: 'bwalletx-phone' } : { option: null, reason: 'none' };\n }\n return list.length ? { option: null, reason: 'chooser' } : { option: null, reason: 'none' };\n}\n\n/** How a connect attempt ended. */\nexport type AttemptOutcome = 'signed-in' | 'connected' | 'cancelled' | 'rejected' | 'not-found' | 'error';\n\n/**\n * One connect attempt, for your metrics. Deliberately nothing else: no identity key, address, paymail, handle,\n * origin or error text. `walletType`/`substrate` are null when no wallet was chosen (chooser closed, nothing found).\n */\nexport interface ConnectAttempt {\n walletType: string | null;\n substrate: Substrate | null;\n outcome: AttemptOutcome;\n /** From the tap to the outcome, rounded to whole ms. */\n ms: number;\n}\n\nexport type AttemptHook = (attempt: ConnectAttempt) => void;\n\n/** The outcome for an error thrown by a connect attempt. */\nexport function outcomeOf(e: unknown): AttemptOutcome {\n const err = e as { code?: unknown; name?: unknown; message?: unknown } | null;\n if (err?.code === 'NOT_FOUND') return 'not-found';\n if (err?.name === 'AbortError' || err?.message === 'cancelled') return 'cancelled';\n if (isUserRejection(e)) return 'rejected';\n return 'error';\n}\n\n/** Build the attempt record for `option` (or none). */\nexport function attemptFor(option: WalletOption | null | undefined, outcome: AttemptOutcome, startedAt: number, now = Date.now()): ConnectAttempt {\n return {\n walletType: option ? walletTypeOf(option) : null,\n substrate: option ? substrateOf(option) : null,\n outcome,\n ms: Math.max(0, Math.round(now - startedAt)),\n };\n}\n\n/** Call the hook with exactly the four fields; a throwing hook never breaks sign-in. */\nexport function reportAttempt(hook: AttemptHook | undefined, a: ConnectAttempt): void {\n if (!hook) return;\n try {\n hook(Object.freeze({ walletType: a.walletType, substrate: a.substrate, outcome: a.outcome, ms: a.ms }));\n } catch {\n /* metrics must never break sign-in */\n }\n}\n\n/* ---------------------------------------------------------------------------------------------------------------\n * 0.6.0: the remembered choice and auto-connect.\n * ------------------------------------------------------------------------------------------------------------- */\n\n/** localStorage key (per origin, like all localStorage) for the wallet type picked here. Never holds a key. */\nexport const WALLET_CHOICE_KEY = 'bwx:wallet';\n\n/** What is remembered: the wallet type and how it reached the page. Nothing that identifies the user. */\nexport interface RememberedWallet {\n type: string;\n substrate: Substrate;\n}\n\nconst SUBSTRATES: readonly Substrate[] = ['extension', 'in-app', 'xdm', 'injected', 'window.CWI', 'json-api', 'cicada', 'pairing', 'adapter'];\nconst TYPE_RE = /^[A-Za-z0-9._:-]{1,64}$/;\nconst KEY_LIKE = /^(0[23][0-9a-f]{64}|04[0-9a-f]{128}|[13][1-9A-HJ-NP-Za-km-z]{25,34})$/i;\n\n/**\n * True when the same wallet can be found again next time: bWalletX, an announced wallet (by its rdns), a desktop\n * wallet, an app adapter. A bare window.CWI cannot (whoever holds it next time may be another wallet), so it is\n * never remembered.\n */\nexport function isRememberable(o: WalletOption): boolean {\n const t = walletTypeOf(o);\n return substrateOf(o) !== 'window.CWI' && TYPE_RE.test(t) && !KEY_LIKE.test(t);\n}\n\n/** Whether a successful connect counts as the user's explicit pick: bWalletX (they tapped its button), or chosen. */\nexport function isExplicitPick(o: WalletOption, reason: ChoiceReason): boolean {\n return o.isBwalletX || reason === 'chooser' || reason === 'requested' || reason === 'remembered';\n}\n\n/** Remember the wallet type picked on this origin (or forget with null). Silently skips what can't be remembered. */\nexport function rememberWalletChoice(o: WalletOption | null): void {\n try {\n if (!o) return void globalThis.localStorage?.removeItem(WALLET_CHOICE_KEY);\n if (!isRememberable(o)) return;\n const v: RememberedWallet & { v: 1 } = { type: walletTypeOf(o), substrate: substrateOf(o), v: 1 };\n globalThis.localStorage?.setItem(WALLET_CHOICE_KEY, JSON.stringify(v));\n } catch {\n /* storage blocked */\n }\n}\n\n/** The wallet type picked on this origin before, or null. Anything malformed or key-like is ignored. */\nexport function rememberedWalletChoice(): RememberedWallet | null {\n try {\n const raw = globalThis.localStorage?.getItem(WALLET_CHOICE_KEY);\n if (!raw) return null;\n const j = JSON.parse(raw) as Partial<RememberedWallet>;\n if (typeof j.type !== 'string' || !TYPE_RE.test(j.type) || KEY_LIKE.test(j.type)) return null;\n if (!SUBSTRATES.includes(j.substrate as Substrate) || j.substrate === 'window.CWI') return null;\n return { type: j.type, substrate: j.substrate as Substrate };\n } catch {\n return null;\n }\n}\n\n/** Forget the remembered wallet (Disconnect does this). */\nexport function forgetWalletChoice(): void {\n rememberWalletChoice(null);\n}\n\n/** True when this wallet type is not bWalletX: show \"Some features need bWalletX · Switch\". */\nexport function needsBwalletX(type: string | null | undefined): boolean {\n return !!type && type !== BWALLETX_TYPE;\n}\n\n/**\n * (0.7.0) True when the signed-out button's tap goes to this remembered wallet instead of bWalletX (\"Continue with your\n * wallet\", the Switch note). Never for Metanet: the button never picks it (it has its own link and \"Not you?\").\n */\nexport function tapGoesElsewhere(type: string | null | undefined): boolean {\n return needsBwalletX(type) && type !== METANET_TYPE && type !== DESKTOP_OPTION_ID;\n}\n\n/** (0.7.0) A remembered desktop wallet on localhost (Metanet, 'desktop', json-api, cicada): never the button's pick. */\nexport function isLocalDesktopType(r: RememberedWallet): boolean {\n return r.type === METANET_TYPE || r.type === DESKTOP_OPTION_ID || r.substrate === 'json-api' || r.substrate === 'cicada';\n}\n\n/**\n * The option in `list` for a remembered wallet, or null when it isn't here. bWalletX counts only by its own marker\n * (or the phone, when the phone was picked). A remembered desktop wallet on localhost (Metanet / 'desktop') gives null\n * (0.7.0): the button never picks it; its own link does.\n */\nexport function matchRemembered(list: readonly WalletOption[], r: RememberedWallet): WalletOption | null {\n // 0.7.0: the button's discovery NEVER picks Metanet (owner rule 1), nor any desktop wallet on localhost ('desktop',\n // json-api, cicada: that is Metanet on :3321 too). Its own tap, or the silent attempt, reaches it.\n if (isLocalDesktopType(r)) return null;\n if (r.type === BWALLETX_TYPE) {\n return (r.substrate === 'pairing' ? list.find((o) => o.kind === 'pairing') : list.find(isPresentBwalletX)) ?? null;\n }\n return list.find((o) => !o.isBwalletX && !isLocalDesktop(o) && isRememberable(o) && walletTypeOf(o) === r.type) ?? null;\n}\n\n/**\n * What to do on page load for a returning visitor (0.6.0).\n * 'attach' signed in already (a server session) and the remembered wallet is in the page: pick it up by\n * discovery alone (no wallet call, so no prompt) so pay/tip work without another tap;\n * 'wait-for-tap' anything else a wallet would have to answer (a key, a signature, a localhost probe, a relay\n * reconnect): nothing fires; the next tap goes straight to the remembered wallet;\n * 'silent-metanet' (0.7.0) Metanet Desktop remembered, on a computer outside any frame: ONE silent attempt this page\n * load (trySilentMetanet: 2 s, known identity keys only), else the normal choice;\n * 'none' nothing remembered, or auto-connect off (or Metanet remembered where it isn't offered).\n */\nexport type AutoConnectAction = 'attach' | 'wait-for-tap' | 'silent-metanet' | 'none';\n\nexport interface AutoConnectPlan {\n action: AutoConnectAction;\n remembered: RememberedWallet | null;\n /** The remembered wallet isn't bWalletX: show \"Some features need bWalletX · Switch\". */\n needsBwalletX: boolean;\n}\n\nconst ATTACHABLE: readonly Substrate[] = ['extension', 'in-app', 'xdm', 'injected'];\n\nexport function planAutoConnect(o: {\n remembered: RememberedWallet | null;\n signedIn: boolean;\n enabled?: boolean;\n /** (0.7.0) Metanet is offered here (a computer, outside any frame). Default metanetOffered(). */\n metanetHere?: boolean;\n}): AutoConnectPlan {\n const r = o.remembered;\n if (!r || o.enabled === false) return { action: 'none', remembered: r, needsBwalletX: false };\n if (r.type === METANET_TYPE) {\n return { action: (o.metanetHere ?? metanetOffered()) ? 'silent-metanet' : 'none', remembered: r, needsBwalletX: false };\n }\n // A remembered 0.6.0 \"Desktop wallet\" is Metanet on :3321 too: never picked by the button, never tried silently.\n if (isLocalDesktopType(r)) return { action: 'none', remembered: r, needsBwalletX: false };\n const action: AutoConnectAction = o.signedIn && ATTACHABLE.includes(r.substrate) ? 'attach' : 'wait-for-tap';\n return { action, remembered: r, needsBwalletX: needsBwalletX(r.type) };\n}\n\n/**\n * Find the remembered wallet in the page by discovery alone: no wallet method is called, nothing touches localhost,\n * no relay is opened. null when it isn't here (or it isn't something that can be attached silently).\n */\nexport async function attachRemembered(r: RememberedWallet, o: { ms?: number } = {}): Promise<WalletOption | null> {\n if (!ATTACHABLE.includes(r.substrate)) return null;\n const list = await discoverWallets({ ms: o.ms });\n const m = matchRemembered(list, r);\n return m && m.kind === 'brc100' && m.wallet && ATTACHABLE.includes(substrateOf(m)) ? m : null;\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';\nimport { metanetOffered, metanetOption, METANET_NOTE } from './metanet.js';\nimport { GET_URL, WEB_WALLET_URL, markSvg } from './element.js';\nimport { chooserOrder, hasBwalletX, isPresentBwalletX, otherDetected } from './choice.js';\nimport { isTouchDevice } from './device.js';\n\nexport { isTouchDevice };\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}\na.bwx-btn{display:block;text-align:center;text-decoration:none;box-sizing:border-box}\n.bwx-primary{background:linear-gradient(180deg,#fcd34d,#f59e0b);color:#000;border:0;font-weight:700;min-height:48px;padding:13px 12px}\n.bwx-stack{display:flex;flex-direction:column;gap:8px}\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;white-space:nowrap}\n.bwx-opt{min-height:48px;box-sizing:border-box}\na.bwx-btn.bwx-opt{display:flex;text-align:left}\n.bwx-btn:focus{outline:none}\n.bwx-btn:focus-visible{outline:2px solid #e8c766;outline-offset:2px}\n.bwx-mk{display:inline-flex;align-items:center;justify-content:center;flex:none;width:28px;height:28px;border-radius:50%;background:#000}\n.bwx-ico{display:inline-grid;place-items:center;flex:none;width:28px;height:28px;border-radius:8px;background:#2a2518;color:#e8c766;font-weight:700;font-size:13px}\n.bwx-opt img{width:28px;height:28px;border-radius:8px;flex:none}\n.bwx-txt{display:flex;flex-direction:column;min-width:0;gap:1px}\n.bwx-txt b{font-weight:600}\n.bwx-txt small{font-size:12px;color:#8d866f;font-weight:400}\n.bwx-primary .bwx-txt small{color:rgba(0,0,0,.68)}\n.bwx-primary .bwx-tag{color:rgba(0,0,0,.6)}\n.bwx-sep{font-size:12px;color:#8d866f;margin:6px 2px 0}\n.bwx-foot{font-size:12px;color:#8d866f;margin:12px 0 0}\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\n\nexport interface PairingModalOptions {\n title?: string;\n /**\n * 'qr' shows the pairing QR (desktop). 'app' hands off to the bWalletX app on this device: the\n * pairing link is a universal link / Android app link that opens the app, and the bwallet.space\n * page behind it explains what to do when the app is not installed. Default 'auto': 'app' on touch\n * devices, 'qr' elsewhere.\n */\n mode?: 'auto' | 'qr' | 'app';\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 app = o.mode === 'app' || ((o.mode ?? 'auto') === 'auto' && isTouchDevice());\n const h = el('h2', '', o.title ?? 'Connect bWalletX');\n const cancel = el('button', 'bwx-btn', 'Cancel');\n cancel.onclick = () => {\n o.onCancel?.();\n ac.abort();\n };\n codeEl = el('div', 'bwx-code', '');\n codeEl.setAttribute('aria-live', 'polite');\n if (app) {\n // Same device: no QR to scan. The link opens the bWalletX app (universal link); approve there,\n // then come back to this tab, which is still waiting on the pairing channel.\n const p = el('p', '', 'Open bWalletX, approve, then come back to this page.');\n const stack = el('div', 'bwx-stack');\n const open = el('a', 'bwx-btn bwx-primary', 'Open bWalletX');\n open.href = link;\n open.rel = 'noopener';\n const web = el('button', 'bwx-btn', 'Use web.bwalletx.com instead');\n web.onclick = () => {\n void navigator.clipboard?.writeText(link).catch(() => undefined);\n window.open(WEB_WALLET_URL, '_blank', 'noopener');\n p.textContent = 'Link copied. In web.bwalletx.com tap Connect and paste it, then come back here.';\n };\n stack.append(open, web, cancel);\n ui.box.append(h, p, codeEl, stack);\n return;\n }\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 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 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\nexport interface ChooseWalletOptions {\n /** Default \"Choose a wallet\". */\n title?: string;\n /** Where \"Get bWalletX\" points. Default https://bwalletx.com/get */\n getUrl?: string;\n /**\n * Offer \"Use Metanet Desktop or another BRC-100 wallet\" (0.7.0; was \"Desktop wallet\"). Default true. It calls\n * localhost:3321 only when tapped (metanetOption), never while the chooser opens, and is never shown on a phone or\n * inside a frame.\n */\n desktop?: boolean;\n}\n\nfunction optionRow(w: WalletOption, primary: boolean, sub?: string, tag?: string): HTMLButtonElement {\n const b = el('button', `bwx-btn bwx-opt${primary ? ' bwx-primary' : ''}`);\n b.type = 'button';\n b.dataset.wallet = w.id;\n if (w.isBwalletX) {\n const mk = el('span', 'bwx-mk');\n mk.innerHTML = markSvg(18);\n b.append(mk);\n } else if (w.icon) {\n const img = el('img');\n img.src = w.icon;\n img.alt = '';\n b.append(img);\n } else {\n b.append(el('span', 'bwx-ico', (w.name.trim().charAt(0) || 'W').toUpperCase()));\n }\n const t = el('span', 'bwx-txt');\n t.append(el('b', '', w.name));\n if (sub) t.append(el('small', '', sub));\n b.append(t);\n if (tag) b.append(el('span', 'bwx-tag', tag));\n return b;\n}\n\n/**\n * The wallet chooser (0.5.6). Without bWalletX in this browser, \"Get bWalletX\" comes first; then bWalletX on the\n * phone, the other wallets that were detected, \"Use Metanet Desktop or another BRC-100 wallet\" (0.7.0: localhost:3321\n * only when tapped; computers only) and app-supplied options. Opened from \"Other wallets\" while bWalletX is here, bWalletX is the first, gold row.\n * Resolves with the chosen option, or null when closed. \"Get bWalletX\" is a link and leaves the chooser open.\n */\nexport function chooseWallet(options: readonly WalletOption[], o: ChooseWalletOptions = {}): Promise<WalletOption | null> {\n if (typeof document === 'undefined') return Promise.resolve(null);\n return new Promise((resolve) => {\n const ui = mount();\n ui.root.dataset.bwxChooser = '';\n const done = (w: WalletOption | null) => {\n document.removeEventListener('keydown', onKey, true);\n ui.close();\n resolve(w);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n done(null);\n }\n };\n document.addEventListener('keydown', onKey, true);\n ui.box.append(el('h2', '', o.title ?? 'Choose a wallet'));\n const list = el('div', 'bwx-list');\n const here = hasBwalletX(options);\n if (!here) {\n const get = el('a', 'bwx-btn bwx-opt bwx-primary');\n get.href = o.getUrl ?? GET_URL;\n get.target = '_blank';\n get.rel = 'noopener';\n get.dataset.wallet = 'get-bwalletx';\n const mk = el('span', 'bwx-mk');\n mk.innerHTML = markSvg(18);\n const t = el('span', 'bwx-txt');\n t.append(el('b', '', 'Get bWalletX'), el('small', '', 'Free. Every feature on this site'));\n get.append(mk, t);\n list.append(get);\n }\n const ordered = chooserOrder(options);\n const touch = isTouchDevice();\n let sep = false;\n for (const w of ordered) {\n if (!here && !sep) {\n list.append(el('p', 'bwx-sep', 'Or use'));\n sep = true;\n }\n const sub = isPresentBwalletX(w)\n ? 'Recommended'\n : w.kind === 'pairing'\n ? touch\n ? 'Open the bWalletX app'\n : 'Scan a QR with your phone'\n : undefined;\n const tag = w.kind === 'handcash' ? 'until BRC-100' : !w.isBwalletX && w.kind === 'brc100' ? 'Fewer features' : undefined;\n const row = optionRow(w, isPresentBwalletX(w), sub, tag);\n row.onclick = () => done(w);\n list.append(row);\n }\n if (o.desktop !== false && metanetOffered() && !options.some((w) => w.substrate === 'json-api' || w.substrate === 'cicada')) {\n if (!here && !sep) list.append(el('p', 'bwx-sep', 'Or use'));\n const d = metanetOption();\n const row = optionRow(d, false, METANET_NOTE);\n row.title = 'Connects to Metanet Desktop on this computer, never to a browser extension.';\n row.onclick = () => done(d);\n list.append(row);\n }\n ui.box.append(list);\n if (otherDetected(options).length || !here) ui.box.append(el('p', 'bwx-foot', 'Some features need bWalletX.'));\n const row = el('div', 'bwx-row');\n const cancel = el('button', 'bwx-btn', 'Cancel');\n cancel.type = 'button';\n cancel.onclick = () => done(null);\n row.append(cancel);\n ui.box.append(row);\n ui.root.onclick = (e) => e.target === ui.root && done(null);\n (list.querySelector('a,button') as HTMLElement | null)?.focus();\n });\n}\n","/**\n * Browser side of the access protocol: ask the wallet to sign the site's challenge and prove the\n * keys holding the required token, using standard BRC-100 calls only (so any BRC-100 wallet works).\n */\nimport { Hash, PublicKey, Utils, type WalletInterface, type WalletProtocol } from '@bsv/sdk';\nimport {\n ACCESS_PROTOCOL,\n AccessError,\n MAX_HOLDING_PROOFS,\n challengeBytes,\n parseAccessChallenge,\n type AccessErrorBody,\n type AccessResponse,\n type HoldingProof,\n} from './access.js';\nimport { connectBwalletX, type SignInOptions } from './signin.js';\n\n/** The challenge route's answer (createAccessChallenge). */\nexport interface AccessChallengeLike {\n challenge: string;\n}\n\nexport interface RequestAccessOptions {\n /** Ask your server for a challenge. Gets the wallet's identity key. */\n challenge: (identityKey: string) => Promise<AccessChallengeLike>;\n /** Post the signed response to your server. Throw AccessError (or return an error body) to refuse. */\n verify?: (response: AccessResponse) => Promise<unknown>;\n wallet?: WalletInterface;\n pairing?: SignInOptions['pairing'];\n discoverMs?: number;\n /** Basket holding BSV-21 outputs. Default 'bsv21' (bWalletX, 1Sat wallets). */\n tokenBasket?: string;\n}\n\nexport interface RequestAccessResult {\n response: AccessResponse;\n /** Whatever `verify` returned. */\n verified?: unknown;\n wallet: WalletInterface;\n}\n\nconst ONESAT: WalletProtocol = [0, 'onesat'];\nconst LEGACY_ONESAT: WalletProtocol = [0, 'p 1sat'];\n\n/** Map a wallet / fetch failure to a protocol error. */\nexport function toAccessError(e: unknown): AccessError {\n if (e instanceof AccessError) return e;\n const err = e as { code?: string; message?: string; status?: number } | null;\n const msg = String(err?.message ?? e ?? '');\n if (err?.code === 'NOT_FOUND') return new AccessError('not_installed', msg);\n if (/reject|denied|declin|cancel|user/i.test(msg) || err?.code === 'ERR_USER_REJECTED' || err?.status === 4001) {\n return new AccessError('user_rejected', msg);\n }\n return new AccessError('bad_request', msg || 'access failed');\n}\n\n/** Read an AccessErrorBody from a server answer and throw it as AccessError. */\nexport function throwIfAccessError(body: unknown): void {\n const b = body as Partial<AccessErrorBody> | null;\n if (b && typeof b.error === 'string') throw new AccessError(b.error as AccessError['code'], b.message, { have: b.have, need: b.need });\n}\n\nfunction hash160FromP2pkh(script: string): string | null {\n const m = /^76a914([0-9a-f]{40})88ac$/i.exec(script.slice(-50));\n return m ? m[1].toLowerCase() : null;\n}\n\n/**\n * Sign the challenge with every key that locks an output of `tokenId` in the wallet's token basket.\n * Outputs whose derivation can't be reproduced are skipped (the server counts only what is proven).\n */\nexport async function proveHoldings(wallet: WalletInterface, challenge: string, tokenId: string, basket = 'bsv21'): Promise<HoldingProof[]> {\n const bare = tokenId.replace(/^bsv21:/, '');\n const list = await wallet.listOutputs({ basket, include: 'locking scripts', includeCustomInstructions: true, limit: 10000 });\n const byKey = new Map<string, HoldingProof>();\n const data = challengeBytes(challenge);\n for (const out of list.outputs) {\n if (byKey.size >= MAX_HOLDING_PROOFS) break;\n let ci: { id?: string; keyID?: string; protocolID?: WalletProtocol; counterparty?: string } = {};\n try {\n ci = JSON.parse(out.customInstructions ?? '{}');\n } catch {\n continue;\n }\n if (ci.id !== bare || !ci.keyID) continue;\n const want = out.lockingScript ? hash160FromP2pkh(out.lockingScript) : null;\n const counterparty = ci.counterparty ?? 'self';\n for (const protocolID of ci.protocolID ? [ci.protocolID] : [ONESAT, LEGACY_ONESAT]) {\n const { publicKey } = await wallet.getPublicKey({ protocolID, keyID: ci.keyID, counterparty });\n const h = Utils.toHex(Hash.hash160(PublicKey.fromString(publicKey).encode(true) as number[]));\n if (want && h !== want) continue;\n const existing = byKey.get(publicKey);\n if (existing) {\n existing.outpoints!.push(out.outpoint.replace('.', '_'));\n break;\n }\n const { signature } = await wallet.createSignature({ protocolID, keyID: ci.keyID, counterparty, data });\n byKey.set(publicKey, { pubkey: publicKey, signature: Array.from(signature), outpoints: [out.outpoint.replace('.', '_')] });\n break;\n }\n }\n return [...byKey.values()];\n}\n\n/**\n * Run the whole flow: find the wallet, get a challenge, sign it, prove holdings, post to verify.\n * Throws AccessError with a protocol code on every failure.\n */\nexport async function requestAccess(o: RequestAccessOptions): Promise<RequestAccessResult> {\n let wallet: WalletInterface;\n try {\n ({ wallet } = await connectBwalletX({ wallet: o.wallet, pairing: o.pairing, discoverMs: o.discoverMs }));\n } catch (e) {\n throw (e as { code?: string })?.code === 'NOT_FOUND' ? new AccessError('not_installed') : toAccessError(e);\n }\n try {\n const { publicKey: identityKey } = await wallet.getPublicKey({ identityKey: true });\n const { challenge } = await o.challenge(identityKey);\n const c = parseAccessChallenge(challenge);\n if (c.sub && c.sub !== identityKey.toLowerCase()) throw new AccessError('wrong_account');\n if (Date.now() / 1000 >= c.exp) throw new AccessError('expired');\n const { signature } = await wallet.createSignature({\n protocolID: ACCESS_PROTOCOL,\n keyID: c.nonce,\n counterparty: 'anyone',\n data: challengeBytes(challenge),\n });\n const response: AccessResponse = { v: 1, challenge, identityKey, signature: Array.from(signature) };\n if (c.require.token) response.holdings = await proveHoldings(wallet, challenge, c.require.token.id, o.tokenBasket);\n let verified: unknown;\n if (o.verify) {\n verified = await o.verify(response);\n throwIfAccessError(verified);\n }\n return { response, verified, wallet };\n } catch (e) {\n throw toAccessError(e);\n }\n}\n","/**\n * $401 / $402 / $403 access protocol, version 1. Shared by sites (client + server) and wallets.\n * The full spec is docs/ACCESS-PROTOCOL.md. Pure: no I/O, @bsv/sdk types only.\n *\n * 401 identity \"prove who you are (at identity level N, or KYC'd)\"\n * 402 payment \"pay for this\" (the challenge format is reserved; payment itself uses pay())\n * 403 access \"prove you hold N of token X (or N basis points of its supply)\"\n */\nimport type { WalletProtocol } from '@bsv/sdk';\n\nexport const ACCESS_VERSION = 1 as const;\n/** Security level 2, a protocol name used for nothing else. Wallets recognise it and show the kind's video. */\nexport const ACCESS_PROTOCOL: WalletProtocol = [2, 'bwalletx access'];\n/** How long a challenge is valid. */\nexport const ACCESS_CHALLENGE_LIFETIME_S = 120;\n/** At most this many holding proofs are read from one response. */\nexport const MAX_HOLDING_PROOFS = 50;\n\nexport type AccessKind = '401' | '402' | '403';\n\nexport interface TokenRequirement {\n /** 'bsv21:<txid>_<vout>' */\n id: string;\n /** Minimum raw (unscaled, integer string) amount. */\n min?: string;\n /** Minimum in basis points of total supply (1 = 0.01%, 10000 = 100%). */\n minBps?: number;\n}\n\nexport interface AccessRequirement {\n token?: TokenRequirement;\n /** $401 identity level (bit-sign strands): 1 Basic, 2 Verified, 3 Strong, 4 Sovereign (Veriff). */\n identityLevel?: number;\n /** A live KYC credential is required. */\n kyc?: boolean;\n}\n\n/** What the wallet signs, as canonical JSON. Times are seconds since the epoch. */\nexport interface AccessChallenge {\n v: 1;\n kind: AccessKind;\n origin: string;\n nonce: string;\n iat: number;\n exp: number;\n /** The identity key the site expects. A different wallet account is `wrong_account`. */\n sub?: string;\n require: AccessRequirement;\n}\n\n/** A key that locks some of the required token, proving control by signing the same challenge bytes. */\nexport interface HoldingProof {\n /** Compressed public key hex of the key locking the outputs. */\n pubkey: string;\n /** DER signature by that key over SHA-256(challenge bytes), as BRC-100 createSignature returns. */\n signature: number[];\n /** Optional hint: outpoints ('txid_vout') this key holds. Servers must not trust it. */\n outpoints?: string[];\n}\n\n/** What the wallet (via requestAccess) posts back to the site. */\nexport interface AccessResponse {\n v: 1;\n /** The challenge string exactly as issued. */\n challenge: string;\n identityKey: string;\n /** DER signature: createSignature({ protocolID: ACCESS_PROTOCOL, keyID: nonce, counterparty: 'anyone', data: challenge bytes }). */\n signature: number[];\n holdings?: HoldingProof[];\n}\n\nexport type AccessErrorCode =\n | 'not_installed'\n | 'user_rejected'\n | 'wrong_account'\n | 'insufficient_tokens'\n | 'identity_level_too_low'\n | 'kyc_required'\n | 'indexer_unavailable'\n | 'expired'\n | 'replay'\n | 'invalid_signature'\n | 'bad_request';\n\n/** The HTTP status a site should answer each code with. */\nexport const ACCESS_ERROR_STATUS: Record<AccessErrorCode, number> = {\n not_installed: 424,\n user_rejected: 403,\n wrong_account: 409,\n insufficient_tokens: 403,\n identity_level_too_low: 403,\n kyc_required: 403,\n indexer_unavailable: 503,\n expired: 401,\n replay: 401,\n invalid_signature: 401,\n bad_request: 400,\n};\n\nexport interface AccessErrorBody {\n error: AccessErrorCode;\n message: string;\n /** insufficient_tokens: raw amounts; identity_level_too_low: levels. */\n have?: string | number;\n need?: string | number;\n}\n\nexport class AccessError extends Error {\n readonly code: AccessErrorCode;\n readonly have?: string | number;\n readonly need?: string | number;\n constructor(code: AccessErrorCode, message?: string, extra: { have?: string | number; need?: string | number } = {}) {\n super(message ?? code);\n this.name = 'AccessError';\n this.code = code;\n this.have = extra.have;\n this.need = extra.need;\n }\n toJSON(): AccessErrorBody {\n const b: AccessErrorBody = { error: this.code, message: this.message };\n if (this.have !== undefined) b.have = this.have;\n if (this.need !== undefined) b.need = this.need;\n return b;\n }\n}\n\n/** One video + poster + colour per kind, so wallets and sites show the same thing. Paths are inside the package. */\nexport const PROTOCOL_MEDIA: Record<AccessKind, { name: string; color: string; video: string; poster: string }> = {\n '401': { name: 'Identity', color: '#22c55e', video: 'assets/protocol/401.mp4', poster: 'assets/protocol/401.jpg' },\n '402': { name: 'Payment', color: '#3b82f6', video: 'assets/protocol/402.mp4', poster: 'assets/protocol/402.jpg' },\n '403': { name: 'Access', color: '#ef4444', video: 'assets/protocol/403.mp4', poster: 'assets/protocol/403.jpg' },\n};\n\n/** Media URLs on a CDN (unpkg) for a given package version. */\nexport function protocolMediaUrl(kind: AccessKind, which: 'video' | 'poster', version = 'latest'): string {\n return `https://unpkg.com/@bwalletx/connect@${version}/${PROTOCOL_MEDIA[kind][which]}`;\n}\n\n/**\n * Canonical JSON: object keys sorted by code unit, no whitespace, undefined members dropped.\n * Only strings, finite numbers, booleans, null, arrays and plain objects are allowed.\n */\nexport function canonicalJson(v: unknown): string {\n if (v === null) return 'null';\n if (typeof v === 'string' || typeof v === 'boolean') return JSON.stringify(v);\n if (typeof v === 'number') {\n if (!Number.isFinite(v)) throw new Error('canonicalJson: non-finite number');\n return JSON.stringify(v);\n }\n if (Array.isArray(v)) return `[${v.map((x) => canonicalJson(x)).join(',')}]`;\n if (typeof v === 'object') {\n const o = v as Record<string, unknown>;\n const keys = Object.keys(o).filter((k) => o[k] !== undefined).sort();\n return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(o[k])}`).join(',')}}`;\n }\n throw new Error(`canonicalJson: unsupported ${typeof v}`);\n}\n\n/** The bytes every signature in the protocol covers: UTF-8 of the challenge string. */\nexport function challengeBytes(challenge: string): number[] {\n return Array.from(new TextEncoder().encode(challenge));\n}\n\nconst TOKEN_ID = /^bsv21:[0-9a-f]{64}_\\d{1,6}$/;\nconst RAW = /^[1-9]\\d{0,38}$/;\n\n/** Throws AccessError('bad_request') if the requirement is malformed. Returns a normalised copy. */\nexport function normaliseRequirement(r: unknown): AccessRequirement {\n if (!r || typeof r !== 'object') throw new AccessError('bad_request', 'require must be an object');\n const req = r as Record<string, unknown>;\n const out: AccessRequirement = {};\n if (req.token !== undefined) {\n const t = req.token as Record<string, unknown>;\n if (!t || typeof t !== 'object' || typeof t.id !== 'string') throw new AccessError('bad_request', 'require.token.id is required');\n const id = t.id.trim().toLowerCase();\n if (!TOKEN_ID.test(id)) throw new AccessError('bad_request', \"require.token.id must be 'bsv21:<txid>_<vout>'\");\n const hasMin = t.min !== undefined;\n const hasBps = t.minBps !== undefined;\n if (hasMin === hasBps) throw new AccessError('bad_request', 'require.token needs exactly one of min or minBps');\n out.token = { id };\n if (hasMin) {\n if (typeof t.min !== 'string' || !RAW.test(t.min)) throw new AccessError('bad_request', 'require.token.min must be a positive integer string (raw units)');\n out.token.min = t.min;\n } else {\n if (!Number.isInteger(t.minBps) || (t.minBps as number) < 1 || (t.minBps as number) > 10000) {\n throw new AccessError('bad_request', 'require.token.minBps must be an integer 1..10000');\n }\n out.token.minBps = t.minBps as number;\n }\n }\n if (req.identityLevel !== undefined) {\n if (!Number.isInteger(req.identityLevel) || (req.identityLevel as number) < 1 || (req.identityLevel as number) > 10) {\n throw new AccessError('bad_request', 'require.identityLevel must be an integer 1..10');\n }\n out.identityLevel = req.identityLevel as number;\n }\n if (req.kyc !== undefined) {\n if (typeof req.kyc !== 'boolean') throw new AccessError('bad_request', 'require.kyc must be a boolean');\n if (req.kyc) out.kyc = true;\n }\n if (!out.token && !out.identityLevel && !out.kyc) throw new AccessError('bad_request', 'require is empty');\n return out;\n}\n\n/** The kind a requirement implies: any token → 403; otherwise 401. */\nexport function kindFor(r: AccessRequirement): AccessKind {\n return r.token ? '403' : '401';\n}\n\n/** Parse and validate a challenge string. Throws AccessError('bad_request'). Does not check expiry. */\nexport function parseAccessChallenge(s: unknown): AccessChallenge {\n if (typeof s !== 'string' || s.length > 4096) throw new AccessError('bad_request', 'challenge must be a string');\n let c: AccessChallenge;\n try {\n c = JSON.parse(s) as AccessChallenge;\n } catch {\n throw new AccessError('bad_request', 'challenge is not JSON');\n }\n if (!c || typeof c !== 'object' || c.v !== 1) throw new AccessError('bad_request', 'unsupported challenge version');\n if (c.kind !== '401' && c.kind !== '402' && c.kind !== '403') throw new AccessError('bad_request', 'bad kind');\n if (typeof c.origin !== 'string' || typeof c.nonce !== 'string' || !/^[A-Za-z0-9_-]{16,64}$/.test(c.nonce)) {\n throw new AccessError('bad_request', 'bad origin or nonce');\n }\n if (!Number.isInteger(c.iat) || !Number.isInteger(c.exp) || c.exp <= c.iat) throw new AccessError('bad_request', 'bad iat/exp');\n if (c.sub !== undefined && (typeof c.sub !== 'string' || !/^0[23][0-9a-f]{64}$/.test(c.sub))) throw new AccessError('bad_request', 'bad sub');\n c.require = normaliseRequirement(c.require);\n if (canonicalJson(c) !== s) throw new AccessError('bad_request', 'challenge is not canonical');\n return c;\n}\n\n/** Raw amount needed for a token requirement, given total supply (needed only for minBps). Rounds up. */\nexport function tokenNeedRaw(t: TokenRequirement, supplyRaw?: string): string {\n if (t.min) return t.min;\n if (supplyRaw === undefined || !/^\\d+$/.test(supplyRaw)) throw new AccessError('indexer_unavailable', 'token supply unknown');\n const n = BigInt(supplyRaw) * BigInt(t.minBps!);\n const need = (n + 9999n) / 10000n;\n return (need < 1n ? 1n : need).toString();\n}\n\n/** Compare unscaled integer strings. Fails closed on malformed input. */\nexport function atLeastRaw(have: string, need: string): boolean {\n try {\n return BigInt(have) >= BigInt(need);\n } catch {\n return false;\n }\n}\n\n/** A user-readable line for an error code. */\nexport function accessErrorMessage(code: AccessErrorCode, e: { have?: string | number; need?: string | number } = {}): string {\n switch (code) {\n case 'not_installed': return 'No bWalletX (or other BRC-100 wallet) was found.';\n case 'user_rejected': return 'The request was declined in the wallet.';\n case 'wrong_account': return 'The wallet is signed in to a different account than this site expects.';\n case 'insufficient_tokens': return `Not enough tokens: holding ${e.have ?? 0}, need ${e.need ?? '?'}.`;\n case 'identity_level_too_low': return `Identity level ${e.have ?? 0} is below the required level ${e.need ?? '?'}.`;\n case 'kyc_required': return 'A verified identity (KYC) is required.';\n case 'indexer_unavailable': return 'Holdings could not be checked right now. Try again shortly.';\n case 'expired': return 'The request expired. Try again.';\n case 'replay': return 'That request was already used. Try again.';\n case 'invalid_signature': return 'The wallet signature did not verify.';\n case 'bad_request': return 'The request was malformed.';\n }\n}\n","/**\n * What BwalletXProvider.connect() does, without React: choose a wallet (bWalletX straight away when it is here; the\n * chooser otherwise, or when the user asked for \"Other wallets\"), open it, and sign in with ONE wallet sheet.\n */\nimport { rememberIdentity, rememberedIdentity } from './account.js';\nimport { signInAndVerify, type Challenge } from './signin.js';\nimport type { ConnectedWallet, Substrate, WalletOption } from './wallets.js';\nimport {\n isKnownIdentityKey, metanetOffered, metanetOption, rememberKnownIdentityKey, trySilentMetanet, METANET_OPTION_ID, type MetanetOptions,\n} from './metanet.js';\nimport {\n attemptFor, decideWallet, isExplicitPick, outcomeOf, rememberWalletChoice, reportAttempt, substrateOf, walletTypeOf,\n type AttemptHook, type ChoiceReason, type RememberedWallet,\n} from './choice.js';\n\nexport interface ConnectFlowOptions {\n /** The wallets found (discoverWallets). */\n list: WalletOption[];\n /** Connect this option without asking. */\n walletId?: string;\n /** false: never show the chooser (bWalletX, else the phone; never another wallet unasked). Default true. */\n picker?: boolean;\n /** \"Other wallets\": show the chooser even when bWalletX is here. */\n chooser?: boolean;\n /**\n * bWalletX first (0.5.6, default true): bWalletX in this browser is connected with no chooser; without it the\n * chooser opens (\"Get bWalletX\" first) and no other wallet is connected unless picked. false: the 0.5.5 rule.\n */\n fastPath?: boolean;\n /**\n * (0.6.0) The wallet picked on this origin before (rememberedWalletChoice()). When it is here, the tap goes straight\n * to it, with no chooser, even when it isn't bWalletX (the user chose it).\n */\n remembered?: RememberedWallet | null;\n /** (0.6.0) After a successful connect the user explicitly picked, remember the wallet type for this origin. */\n remember?: boolean;\n /** (0.6.0) \"Switch\" to bWalletX: ignore a remembered other wallet (bWalletX here, else the chooser). */\n preferBwalletX?: boolean;\n /**\n * (0.7.0) The user tapped \"Use Metanet Desktop or another BRC-100 wallet\": connect to localhost:3321 (pinned\n * 'json-api', never 'auto'), with no chooser. Rejects NOT_SUPPORTED on a phone or inside a frame.\n */\n metanet?: boolean | MetanetOptions;\n /** Show the chooser; resolves null when closed. chooseWallet (modal.ts) or your own UI. */\n pick: (list: WalletOption[]) => Promise<WalletOption | null>;\n /** With verifyUrl: sign in after connecting. */\n challengeUrl?: string;\n verifyUrl?: string;\n challengeNeedsIdentityKey?: boolean;\n /** POST JSON; throws with `status` on a non-2xx answer. */\n post: (url: string, body: unknown) => Promise<Record<string, unknown>>;\n /** Called once per attempt with { walletType, substrate, outcome, ms }. No keys, addresses or identity data. */\n onAttempt?: AttemptHook;\n}\n\nexport interface ConnectFlowResult {\n connected: ConnectedWallet;\n identityKey: string | null;\n handle: string | null;\n paymail: string | null;\n signedIn: boolean;\n /** 'bwalletx' for bWalletX, else the wallet's rdns / option id. */\n walletType: string;\n substrate: Substrate;\n /** Why this wallet: 'bwalletx' (fast path), 'chooser' (picked), 'requested' (walletId), … */\n reason: ChoiceReason;\n}\n\n/** Resolves null when the user closed the chooser. Throws NOT_FOUND when there is nothing to connect. */\nexport async function runConnect(o: ConnectFlowOptions): Promise<ConnectFlowResult | null> {\n const started = Date.now();\n const { list } = o;\n let choice: WalletOption | null = null;\n let reason: ChoiceReason = 'none';\n try {\n if (o.metanet) {\n if (!metanetOffered()) throw Object.assign(new Error('Metanet Desktop runs on a computer, outside any frame.'), { code: 'NOT_SUPPORTED' });\n choice = metanetOption(typeof o.metanet === 'object' ? o.metanet : {});\n reason = 'requested';\n return await finish(o, choice, reason, started);\n }\n const d = decideWallet(list, {\n walletId: o.walletId,\n chooser: o.chooser,\n picker: o.picker,\n fastPath: o.fastPath,\n remembered: o.remembered,\n preferBwalletX: o.preferBwalletX,\n });\n choice = d.option;\n reason = d.reason;\n if (!choice && d.reason === 'chooser') choice = await o.pick(list);\n if (!choice) {\n if (d.reason === 'none' || !list.length) throw Object.assign(new Error('No wallet found. Get bWalletX at bwalletx.com.'), { code: 'NOT_FOUND' });\n reportAttempt(o.onAttempt, attemptFor(null, 'cancelled', started));\n return null;\n }\n return await finish(o, choice, reason, started);\n } catch (e) {\n reportAttempt(o.onAttempt, attemptFor(choice, outcomeOf(e), started));\n throw e;\n }\n}\n\n/** Open the chosen wallet and sign in (one wallet sheet), remember the pick, report the attempt. */\nasync function finish(o: ConnectFlowOptions, choice: WalletOption, reason: ChoiceReason, started: number): Promise<ConnectFlowResult> {\n const signIn = !!(o.challengeUrl && o.verifyUrl) && choice.kind !== 'handcash';\n // Signing in: open the wallet WITHOUT asking for the key; the key comes with the signature, in one sheet.\n const cw = await choice.connect(signIn ? { identity: false } : undefined);\n let handle = cw.handle ?? null;\n let paymail = cw.paymail ?? null;\n let identityKey = cw.identityKey;\n let signedIn = false;\n if (cw.wallet && signIn) {\n const { result, verified } = await signInAndVerify({\n wallet: cw.wallet,\n identityKey: cw.identityKey ?? undefined,\n // Metanet's connect() just checked the lock: don't ask again (rule 7, the minimum).\n skipWaitForAuthentication: choice.id === METANET_OPTION_ID,\n // The key that signed in here last time: a repeat sign-in is then the signature alone.\n identityKeyHint: rememberedIdentity(),\n challengeNeedsIdentityKey: o.challengeNeedsIdentityKey,\n challenge: (key) => o.post(o.challengeUrl!, key ? { identityKey: key } : {}) as unknown as Promise<Challenge>,\n verify: (r) => o.post(o.verifyUrl!, { identityKey: r.identityKey, nonce: r.nonce, signature: r.signature }),\n });\n rememberIdentity(result.identityKey);\n identityKey = result.identityKey;\n handle = (verified.handle as string | undefined) ?? handle;\n paymail = (verified.paymail as string | undefined) ?? paymail;\n signedIn = true;\n } else if (cw.wallet && !identityKey) {\n identityKey = (await cw.wallet.getPublicKey({ identityKey: true })).publicKey;\n }\n if (o.remember && isExplicitPick(choice, reason)) rememberWalletChoice(choice);\n // 0.7.0: the identity keys known on this origin (public keys), for Metanet's known-key-only silent attempt. ONLY a\n // key that proved itself to the site's verify route: a plain connect (no sign-in) proves nothing about the person.\n if (o.remember && signedIn) rememberKnownIdentityKey(identityKey);\n reportAttempt(o.onAttempt, attemptFor(choice, signedIn ? 'signed-in' : 'connected', started));\n return { connected: cw, identityKey, handle, paymail, signedIn, walletType: walletTypeOf(choice), substrate: substrateOf(choice), reason };\n}\n\nexport interface SilentMetanetOptions extends MetanetOptions {\n /** With verifyUrl: sign in once the known key is confirmed (the signature alone; the key is already in hand). */\n challengeUrl?: string;\n verifyUrl?: string;\n post?: (url: string, body: unknown) => Promise<Record<string, unknown>>;\n /** A server session is already in place for this identity key: attach the wallet only if it is the same key. */\n sessionKey?: string | null;\n /** The silent window, ms. Default METANET_SILENT_MS (2 s). */\n windowMs?: number;\n /** Called when the known key is confirmed and the sign-in signature is about to be asked for. */\n onSignIn?: () => void;\n /** \"Not you?\" was pressed meanwhile: land nobody (and end a session the verify route already set, via `logout`). */\n isAbandoned?: () => boolean;\n logout?: () => Promise<unknown>;\n onAttempt?: AttemptHook;\n}\n\n/**\n * (0.7.0) The return visit with Metanet remembered: ONE silent attempt per page load (trySilentMetanet: 2 s, known\n * identity keys only), then, with a session already there, attach the wallet when it is the session's key; without\n * one, sign in with the signature alone. Resolves null on any stop or failure, and never throws: the caller shows\n * the normal choice and waits for a tap, with no error.\n */\nexport async function runSilentMetanet(o: SilentMetanetOptions = {}): Promise<ConnectFlowResult | null> {\n const s = await trySilentMetanet(o);\n if (!s.ok || o.isAbandoned?.()) return null;\n const started = Date.now();\n const opt = metanetOption(o);\n opt.wallet = s.wallet;\n const cw: ConnectedWallet = { wallet: s.wallet, payer: s.wallet, identityKey: s.identityKey, optionId: METANET_OPTION_ID, kind: 'brc100' };\n const done = (signedIn: boolean, handle: string | null = null, paymail: string | null = null): ConnectFlowResult => {\n rememberWalletChoice(opt);\n // Known only after a verified sign-in, or a match with the server session's key (both are signedIn here).\n if (signedIn) rememberKnownIdentityKey(s.identityKey);\n reportAttempt(o.onAttempt, attemptFor(opt, signedIn ? 'signed-in' : 'connected', started));\n return { connected: cw, identityKey: s.identityKey, handle, paymail, signedIn, walletType: walletTypeOf(opt), substrate: 'json-api', reason: 'remembered' };\n };\n if (o.sessionKey !== undefined && o.sessionKey !== null) {\n return o.sessionKey.toLowerCase() === s.identityKey.toLowerCase() ? done(true) : null;\n }\n if (!o.challengeUrl || !o.verifyUrl || !o.post) return done(false);\n if (!isKnownIdentityKey(s.identityKey)) return null;\n try {\n o.onSignIn?.();\n const post = o.post;\n const { result, verified } = await signInAndVerify({\n wallet: s.wallet,\n identityKey: s.identityKey,\n skipWaitForAuthentication: true, // trySilentMetanet just saw it unlocked\n challenge: (key) => post(o.challengeUrl!, key ? { identityKey: key } : {}) as unknown as Promise<Challenge>,\n verify: (r) => post(o.verifyUrl!, { identityKey: r.identityKey, nonce: r.nonce, signature: r.signature }),\n });\n if (o.isAbandoned?.()) {\n await Promise.resolve(o.logout?.()).catch(() => undefined);\n return null;\n }\n rememberIdentity(result.identityKey);\n return done(true, (verified.handle as string | undefined) ?? null, (verified.paymail as string | undefined) ?? null);\n } catch (e) {\n reportAttempt(o.onAttempt, attemptFor(opt, outcomeOf(e), started));\n return null;\n }\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 | get (\"Get bWalletX\") | play (\"Play with bWalletX\")\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 * require-token / min / min-bps with challenge-url: run the $403 access flow instead; emits\n * bwalletx-access-granted or bwalletx-access-denied { code, have, need }\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 a wallet that has not answered. Default 300\n * other-wallets auto (default) | on | off. A small \"Other wallets\" link under the button that opens the chooser\n * (phone QR, other browser wallets, desktop wallets). auto: shown at lg/md when the element runs the\n * sign-in (challenge-url) or follows a provider; always offered in the not-found row unless off\n * remember on (default) | off. (0.6.0) Remember the wallet TYPE picked on this origin (never a key): the next\n * tap goes straight to it. Disconnect forgets it. Nothing fires on load\n * switch-note auto (default) | on | off. (0.6.0) \"Some features need bWalletX · Switch\" under the button when the\n * remembered wallet isn't bWalletX (auto: lg/md), and in the signed-in menu\n * metanet auto (default) | on | off. (0.7.0) \"Use Metanet Desktop or another BRC-100 wallet · Metanet Desktop\n * must be running on this computer\": a link under the button that connects to localhost:3321 (pinned\n * json-api, never 'auto') on its own tap only. auto: lg/md when the element signs in or follows a\n * provider. Never on a phone or inside a frame. With Metanet remembered here, the element makes ONE\n * silent attempt per page load (2 s, identity keys already known here only) and shows \"Not you? Use\n * another wallet\", which forgets it\n * wallet-type (driven by a provider) the connected or remembered wallet type, for the Switch note\n * session-url GET → { identityKey, handle?, paymail? }: restores the signed-in badge on load, no wallet prompt\n * logout-url POST on Disconnect (clears the session cookie). REQUIRED with verify-url (0.7.0): \"Not you?\" and\n * Disconnect end a session the verify route created through it (a dev console.warn when missing)\n * lookup-url paymail lookup by key for the badge. Default pay.bwallet.space; \"off\" to skip\n * stateless keep the pre-0.5.5 behaviour: a plain button that never shows the signed-in badge\n * state drive it yourself (BwalletxSignin inside BwalletXProvider does): signed-out | restoring | pending |\n * signed-in | error, with identity-key, paymail, handle, avatar-url and error. The element then\n * only emits events; it never changes its own state.\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 * Wallet choice (0.5.6): bWalletX in this browser (its own announcement, never window.CWI) → straight to its sheet,\n * no chooser. Other wallets here but no bWalletX → the chooser, \"Get bWalletX\" first; another wallet is used only\n * when picked. Nothing here → the not-found row. Nothing probes localhost until \"Desktop wallet\" is tapped.\n *\n * Events (bubble, composed):\n * bwalletx-signin on every click, before anything else, detail { element, mode } (mode: 'signin',\n * 'chooser' from \"Other wallets\", 'bwalletx' from \"Switch\", 'metanet' from the Metanet link). Cancelable: preventDefault() stops the built-in behaviour so\n * you can run your own flow.\n * bwalletx-attempt once per attempt: { walletType, substrate, outcome, ms }. No keys or addresses.\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 * bwalletx-disconnect Disconnect chosen in the badge menu. Cancelable: preventDefault() and sign out yourself\n * (BwalletXProvider does). Otherwise logout-url is posted and the element shows signed out.\n * bwalletx-signed-out after the element signed out by itself\n * bwalletx-not-you \"Not you? Use another wallet\" (0.7.0). Cancelable: BwalletXProvider forgets the choice itself\n *\n * States (one element, the whole experience): signed out (the button) → pending (\"Approve in bWalletX…\" and one\n * plain line: what signing in shares) → signed in (a badge: bAvatar, $handle or short key, gold dot; its menu has\n * Copy paymail/key and Disconnect) or an error (one line plus Retry; a no in the wallet reads \"Sign-in cancelled\").\n */\nimport { bindPrewarm, discoverBwalletX, DEFAULT_DISCOVER_MS, RDNS_EXTENSION, RDNS_MOBILE } from './discover.js';\nimport { brc100Option, discoverWallets, type WalletOption } from './wallets.js';\nimport {\n attemptFor, forgetWalletChoice, hasBwalletX, isExplicitPick, matchRemembered, needsBwalletX, otherDetected, outcomeOf,\n rememberWalletChoice, rememberedWalletChoice, substrateOf, tapGoesElsewhere, walletTypeOf, BWALLETX_TYPE, type AttemptOutcome, type ChoiceReason,\n} from './choice.js';\nimport { chooseWallet, pairingModal } from './modal.js';\nimport { signInAndVerify, type Challenge } from './signin.js';\nimport { requestAccess, type AccessChallengeLike } from './access-client.js';\nimport { AccessError } from './access.js';\nimport { accountLabel, avatarUrlFor, copyText, lookupPaymail, rememberIdentity, rememberedIdentity, signInErrorText } from './account.js';\nimport { runSilentMetanet } from './connect-flow.js';\nimport {\n metanetOffered, metanetOption, rememberKnownIdentityKey, silentAttemptUsed, METANET_LABEL, METANET_NOTE, METANET_REMEMBERED_NOTE,\n METANET_OPTION_ID, METANET_TYPE, NOT_YOU_LABEL, warnIfNoLogout,\n} from './metanet.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' | 'get' | 'play';\nexport type SigninBrand = 'bWalletX' | 'bWallet';\n\nconst VERBS: Record<SigninLabel, string> = { signin: 'Sign in with', continue: 'Continue with', connect: 'Connect', get: 'Get', play: 'Play with' };\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/* pending: one plain line under the button */\n.note{margin:8px 0 0;width:0;min-width:100%;font-size:12px;line-height:1.4;color:#71717a;text-align:center;overflow-wrap:break-word}\n:host([theme=dark]) .note,:host-context(.dark) .note{color:#a1a1aa}\n/* \"Other wallets\" (0.5.6): one small link under the button */\n.ow{margin:8px 0 0;width:0;min-width:100%;font-size:12px;line-height:1.4;color:#71717a;text-align:center}\n:host([theme=dark]) .ow,:host-context(.dark) .ow{color:#a1a1aa}\n.sw{margin:8px 0 0;width:0;min-width:100%;font-size:12px;line-height:1.4;color:#a16207;text-align:center}\n:host([theme=dark]) .sw,:host-context(.dark) .sw{color:#fcd34d}\n.mn{margin:8px 0 0;width:0;min-width:100%;font-size:12px;line-height:1.4;color:#71717a;text-align:center}\n.mn small{display:block;font-size:11px;opacity:.85}\n:host([theme=dark]) .mn,:host-context(.dark) .mn{color:#a1a1aa}\n.lnk{all:unset;cursor:pointer;color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px}\n.lnk:focus-visible{outline:2px solid #b45309;outline-offset:2px;border-radius:2px}\n/* error: one line plus Retry */\n.err{margin:0 0 8px;width:0;min-width:100%;font-size:13px;font-weight:600;line-height:1.4;color:#b91c1c;text-align:center;overflow-wrap:anywhere}\n:host([theme=dark]) .err,:host-context(.dark) .err{color:#fca5a5}\n/* signed in: the badge */\nbutton.chip{display:inline-flex;align-items:center;justify-content:flex-start;gap:10px;width:auto;max-width:100%;padding:5px 14px 5px 5px;border-radius:999px;\n background:#0b0b0c;color:#ffd24d;border:1px solid rgba(255,210,77,.55);box-shadow:none;font-size:15px}\nbutton.chip:hover{background:#151517;border-color:#ffd24d}\nbutton.chip:active{background:#000;transform:none}\nbutton.chip:focus-visible{outline:2px solid #ffd24d;outline-offset:3px}\n:host([theme=light]) button.chip{background:#fff;color:#09090b;border-color:#f59e0b}\n:host([theme=light]) button.chip:hover{background:#fffbeb}\n:host([full-width]) button.chip{width:100%}\n.av{position:relative;flex:none;display:inline-grid;place-items:center;width:30px;height:30px;border-radius:50%;overflow:hidden;\n background:radial-gradient(circle at 30% 30%,#ffe27a,#f5b800 55%,#b88600);color:#000;font-weight:800;font-size:14px}\n.av img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}\n.name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:min(52vw,260px)}\n.dot{flex:none;width:8px;height:8px;border-radius:50%;background:#ffd24d;box-shadow:0 0 0 3px rgba(255,210,77,.22)}\n:host([size=sm]) button.chip{font-size:13px;padding:3px 12px 3px 3px;gap:8px}\n:host([size=sm]) .av{width:26px;height:26px}\n:host([size=icon]) button.chip{width:48px;height:48px;padding:0;justify-content:center}\n:host([size=icon]) .name,:host([size=icon]) .dot{display:none}\n:host([size=icon]) .av{width:40px;height:40px}\n`;\n\n/** The badge menu. Rendered in a body-level portal (position: fixed), so overflow:hidden parents never clip it. */\nexport const MENU_CSS = `\n:host{all:initial}\n.menu{position:fixed;z-index:2147483600;box-sizing:border-box;min-width:200px;padding:6px;border-radius:14px;background:#0b0b0c;color:#ffd24d;\n border:1px solid rgba(255,210,77,.55);box-shadow:0 12px 32px rgba(0,0,0,.45);font:600 14px/1.3 Inter,ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif}\n.who{padding:8px 10px 10px;font-size:12px;font-weight:500;color:#e7d9a8;overflow-wrap:anywhere;border-bottom:1px solid rgba(255,210,77,.3);margin-bottom:4px}\n.item{all:unset;box-sizing:border-box;display:block;width:100%;padding:11px 10px;border-radius:10px;cursor:pointer;color:#ffd24d}\n.item:hover,.item:focus-visible{background:#ffd24d;color:#000;outline:none}\n.tip{position:fixed;z-index:2147483600;box-sizing:border-box;padding:8px 12px;border-radius:10px;background:#0b0b0c;color:#e7d9a8;\n border:1px solid rgba(255,210,77,.4);box-shadow:0 8px 24px rgba(0,0,0,.35);font:500 12px/1.4 Inter,ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif}\n`;\n\nexport type SigninState = 'signed-out' | 'restoring' | 'pending' | 'signed-in' | 'error';\n\n/** The account the badge shows. */\nexport interface SigninAccount {\n identityKey: string;\n paymail?: string | null;\n handle?: string | null;\n avatarUrl?: string | null;\n}\n\n/** The one plain line shown while the wallet sheet is up. */\nexport const PENDING_NOTE = 'Sign in: shares only your public identity key, moves no money';\nexport const PENDING_LABEL = 'Approve in bWalletX…';\n/** The pending label when the user picked a wallet other than bWalletX. */\nexport const PENDING_LABEL_OTHER = 'Approve in your wallet…';\n\n/**\n * What started a sign-in: the button ('signin'), \"Other wallets\" ('chooser'), \"Switch\" ('bwalletx', 0.6.0) or \"Use\n * Metanet Desktop or another BRC-100 wallet\" ('metanet', 0.7.0).\n */\nexport type SigninMode = 'signin' | 'chooser' | 'bwalletx' | 'metanet';\n\n/** (0.6.0) The note shown when the remembered or connected wallet isn't bWalletX. */\nexport const SWITCH_NOTE = 'Some features need bWalletX';\n/** (0.6.0) The button's label when the tap goes to a remembered wallet that isn't bWalletX. */\nexport const CONTINUE_OTHER_LABEL = 'Continue with your wallet';\n\n/** A neutral wallet glyph: the button must not show bWalletX's \"b\" when the tap goes to another wallet. */\nfunction walletGlyph(px: number): string {\n return `<svg viewBox=\"0 0 24 24\" width=\"${px}\" height=\"${px}\" aria-hidden=\"true\" focusable=\"false\" fill=\"none\" stroke=\"#FFD24D\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M19 7V5a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2\"/><path d=\"M3 6v12a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-3\"/></svg>`;\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 Object.assign(new Error((data as { error?: string }).error ?? `HTTP ${res.status}`), { status: res.status });\n return data as T;\n}\n\n/** POST that returns the body even on 4xx, so access error codes reach requestAccess. */\nasync function postAccess(url: string, body: unknown): Promise<unknown> {\n const res = await fetch(url, { method: 'POST', credentials: 'include', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });\n return res.json().catch(() => ({ error: 'bad_request', message: `HTTP ${res.status}` }));\n}\n\nconst OBSERVED = ['size', 'theme', 'label', 'brand', 'subtitle', 'loading', 'disabled', 'full-width', 'aria-label', 'get-url', 'web-url', 'state', 'identity-key', 'paymail', 'handle', 'avatar-url', 'error', 'other-wallets', 'challenge-url', 'wallet-type', 'switch-note', 'remember', 'metanet'];\nconst STATES: readonly SigninState[] = ['signed-out', 'restoring', 'pending', 'signed-in', 'error'];\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 #phase: SigninState = 'signed-out';\n #account: SigninAccount | null = null;\n #error = '';\n #restored = false;\n #pendingLabel = PENDING_LABEL;\n /** The wallet type signed in with here (0.6.0), for the Switch note. */\n #signedType: string | null = null;\n #menu: { host: HTMLElement; close: (focusChip?: boolean) => void } | null = null;\n /** (0.7.0) A Metanet sign-in (tapped or silent) is in flight. */\n #viaMetanet = false;\n /** (0.7.0) Bumped by \"Not you?\": a Metanet sign-in started before it lands nobody. */\n #run = 0;\n\n constructor() {\n super();\n this.#root = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback() {\n if (!this.#controlled && this.#stateful) warnIfNoLogout({ verifyUrl: this.#attr('verify-url'), logoutUrl: this.#attr('logout-url'), where: '<bwalletx-signin>' });\n this.#render();\n void this.#restore().then(() => this.#silentMetanet());\n }\n disconnectedCallback() { this.#menu?.close(false); this.#hideTip(); }\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 /** The state shown now (the `state` attribute when set, else the element's own). */\n get state(): SigninState {\n const a = this.#attr('state') as SigninState | null;\n return a && STATES.includes(a) ? a : this.#phase;\n }\n /** The signed-in account, or null. */\n get account(): SigninAccount | null {\n if (!this.#controlled) return this.#account;\n const identityKey = this.#attr('identity-key');\n return identityKey ? { identityKey, paymail: this.#attr('paymail'), handle: this.#attr('handle'), avatarUrl: this.#attr('avatar-url') } : null;\n }\n /** True while the menu is open (tests). */\n get menuOpen(): boolean { return !!this.#menu; }\n\n focus(opts?: FocusOptions) { this.button?.focus(opts); }\n\n get #controlled() { return this.hasAttribute('state'); }\n get #stateful() { return !this.hasAttribute('stateless'); }\n\n #attr(name: string) { return this.getAttribute(name); }\n\n /** Restore the badge from session-url once, with no wallet call. */\n async #restore() {\n const url = this.#attr('session-url');\n if (this.#restored || !url || this.#controlled || !this.#stateful) return;\n this.#restored = true;\n this.#set('restoring');\n try {\n const r = await fetch(url, { credentials: 'include', headers: { accept: 'application/json' } });\n const j = (await r.json().catch(() => ({}))) as { identityKey?: string | null; handle?: string | null; paymail?: string | null };\n if (this.#phase !== 'restoring') return; // a click got there first\n if (j.identityKey) this.#signedIn({ identityKey: j.identityKey, handle: j.handle ?? null, paymail: j.paymail ?? null });\n else this.#set('signed-out');\n } catch {\n if (this.#phase === 'restoring') this.#set('signed-out');\n }\n }\n\n #set(p: SigninState) {\n this.#phase = p;\n if (p !== 'signed-in') this.#menu?.close(false);\n this.#render();\n }\n\n #signedIn(a: SigninAccount) {\n this.#account = a;\n this.#error = '';\n this.#set('signed-in');\n const lookup = this.#attr('lookup-url');\n if (!a.paymail && lookup !== 'off') {\n void lookupPaymail(a.identityKey, lookup ?? undefined).then((pm) => {\n if (pm && this.#account?.identityKey === a.identityKey && !this.#account.paymail) {\n this.#account = { ...this.#account, paymail: pm };\n this.#render();\n }\n });\n }\n }\n\n #render() {\n const size = (this.#attr('size') ?? 'lg') as SigninSize;\n const brand: SigninBrand = this.#attr('brand') === 'bWallet' ? 'bWallet' : 'bWalletX';\n const esc = (s: string) => s.replace(/[&<>\"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '\"': '"' })[c]!);\n const state = this.state;\n const acct = this.account;\n\n if (state === 'signed-in' && acct) {\n this.#hideTip();\n const name = accountLabel(acct);\n const avatar = acct.avatarUrl ?? avatarUrlFor(acct.identityKey);\n const initial = (name.replace(/^\\$/, '').charAt(0) || 'b').toUpperCase();\n this.#root.innerHTML = `<style>${SIGNIN_CSS}</style><button type=\"button\" class=\"chip\" part=\"button chip\" aria-haspopup=\"menu\" aria-expanded=\"${this.#menu ? 'true' : 'false'}\" aria-label=\"Signed in with bWalletX as ${esc(name)}. Account menu\" title=\"Signed in as ${esc(name)}\"><span class=\"av\" part=\"avatar\" aria-hidden=\"true\">${esc(initial)}${avatar ? `<img alt=\"\" src=\"${esc(avatar)}\" referrerpolicy=\"no-referrer\">` : ''}</span><span class=\"name\" part=\"label\">${esc(name)}</span><span class=\"dot\" part=\"dot\" aria-hidden=\"true\"></span></button>`;\n const img = this.#root.querySelector('img');\n if (img) img.addEventListener('error', () => img.remove(), { once: true });\n const chip = this.button!;\n chip.addEventListener('click', () => (this.#menu ? this.#menu.close(true) : this.#openMenu()));\n chip.addEventListener('keydown', (e) => {\n if ((e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') && !this.#menu) {\n e.preventDefault();\n this.#openMenu();\n }\n });\n return;\n }\n\n const pending = state === 'pending';\n const restoring = state === 'restoring';\n const error = state === 'error';\n const pendingLabel = this.#controlled ? PENDING_LABEL : this.#pendingLabel;\n // 0.6.0: the tap goes to a remembered wallet that isn't bWalletX, so the button says so (and drops the \"b\").\n const elsewhere = state === 'signed-out' && tapGoesElsewhere(this.#walletType());\n const text = pending ? pendingLabel : error ? 'Retry' : elsewhere ? CONTINUE_OTHER_LABEL : 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 = pending || error || elsewhere ? null : 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 || pending || restoring;\n const disabled = this.hasAttribute('disabled');\n const markPx = size === 'icon' ? 24 : size === 'sm' ? 15 : size === 'md' ? 17 : 20;\n const aria = pending ? pendingLabel : 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 const errText = error ? (this.#controlled ? this.#attr('error') : this.#error) || 'Sign-in failed' : '';\n\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>' : elsewhere ? walletGlyph(markPx - 4) : markSvg(markPx);\n const otherOff = this.#attr('other-wallets') === 'off';\n const otherLink = '<button type=\"button\" class=\"lnk\" data-act=\"other\" part=\"other-wallets-link\">Other wallets</button>';\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>.${otherOff ? '' : ` ${otherLink}`}</p>`\n : '';\n const ow = !this.#notFound && !pending && !restoring && this.#otherWalletsShown(size) ? `<p class=\"ow\" part=\"other-wallets\">${otherLink}</p>` : '';\n const sw = !pending && !restoring && this.#switchNoteShown(size)\n ? `<p class=\"sw\" part=\"switch-note\">${esc(SWITCH_NOTE)} · <button type=\"button\" class=\"lnk\" data-act=\"switch\" part=\"switch-link\">Switch</button></p>`\n : '';\n const err = error ? `<p class=\"err\" part=\"error\" role=\"alert\">${esc(errText)}</p>` : '';\n // 0.7.0: the Metanet link (its own tap only) and, when Metanet is remembered here, \"Not you? Use another wallet\".\n const mnHere = this.#metanetShown(size);\n const mnRemembered = mnHere && (pending ? this.#metanetPending() : !restoring && this.#walletType() === METANET_TYPE);\n const notYou = `<button type=\"button\" class=\"lnk\" data-act=\"not-you\" part=\"not-you-link\">${esc(NOT_YOU_LABEL)}</button>`;\n const mn = !mnHere\n ? ''\n : pending\n ? mnRemembered ? `<p class=\"mn\" part=\"metanet\">${esc(METANET_REMEMBERED_NOTE)} ${notYou}</p>` : ''\n : restoring\n ? ''\n : `<p class=\"mn\" part=\"metanet\"><button type=\"button\" class=\"lnk\" data-act=\"metanet\" part=\"metanet-link\" title=\"Connects to Metanet Desktop on this computer, never to a browser extension.\">${esc(METANET_LABEL)}</button><small>${esc(METANET_NOTE)}</small>${mnRemembered ? `<small>${esc(METANET_REMEMBERED_NOTE)} ${notYou}</small>` : ''}</p>`;\n const compact = size === 'sm' || size === 'icon';\n const note = pending && !compact ? `<p class=\"note\" part=\"note\">${esc(PENDING_NOTE)}</p>` : '';\n const status = pending ? `<span class=\"sr\" role=\"status\">${esc(pendingLabel)}</span>` : loading ? '<span class=\"sr\" role=\"status\">Connecting to bWalletX…</span>' : '';\n this.#root.innerHTML = `<style>${SIGNIN_CSS}</style>${err}<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>${status}${note}${sw}${mn}${ow}${nf}`;\n this.button!.addEventListener('click', () => void this.#click());\n for (const l of Array.from(this.#root.querySelectorAll<HTMLElement>('[data-act=other]'))) l.addEventListener('click', () => void this.otherWallets());\n this.#root.querySelector<HTMLElement>('[data-act=switch]')?.addEventListener('click', () => void this.switchToBwalletX());\n this.#root.querySelector<HTMLElement>('[data-act=metanet]')?.addEventListener('click', () => void this.useMetanet());\n this.#root.querySelector<HTMLElement>('[data-act=not-you]')?.addEventListener('click', () => this.notYou());\n bindPrewarm(this.button!);\n // A nav-sized button has no room for the line: it shows in a body-level tip under the button instead, so an\n // overflow:hidden header can't clip it and the header doesn't grow.\n if (pending && compact) this.#showTip(PENDING_NOTE);\n else this.#hideTip();\n }\n\n #tip: HTMLElement | null = null;\n\n #showTip(text: string) {\n const b = this.button;\n if (!b || typeof document === 'undefined') return;\n if (!this.#tip) {\n const host = document.createElement('div');\n host.setAttribute('data-bwalletx-tip', '');\n const root = host.attachShadow({ mode: 'open' });\n root.innerHTML = `<style>${MENU_CSS}</style><div class=\"tip\" role=\"note\"></div>`;\n document.body.appendChild(host);\n this.#tip = host;\n }\n const tip = this.#tip.shadowRoot!.querySelector<HTMLElement>('.tip')!;\n tip.textContent = text;\n const r = b.getBoundingClientRect();\n const vw = window.innerWidth || document.documentElement.clientWidth || 360;\n const width = Math.min(280, vw - 32);\n tip.style.width = `${width}px`;\n tip.style.left = `${Math.max(16, Math.min(r.right - width, vw - width - 16))}px`;\n tip.style.top = `${r.bottom + 8}px`;\n }\n\n #hideTip() {\n this.#tip?.remove();\n this.#tip = null;\n }\n\n #openMenu() {\n const acct = this.account;\n const chip = this.button;\n if (!acct || !chip || typeof document === 'undefined') return;\n const name = accountLabel(acct);\n const host = document.createElement('div');\n host.setAttribute('data-bwalletx-menu', '');\n const root = host.attachShadow({ mode: 'open' });\n const style = document.createElement('style');\n style.textContent = MENU_CSS;\n const menu = document.createElement('div');\n menu.className = 'menu';\n menu.setAttribute('role', 'menu');\n menu.setAttribute('aria-label', 'bWalletX account');\n const who = document.createElement('div');\n who.className = 'who';\n who.textContent = `Signed in as ${acct.paymail || name}`;\n const item = (text: string, run: (b: HTMLButtonElement) => void) => {\n const b = document.createElement('button');\n b.type = 'button';\n b.className = 'item';\n b.setAttribute('role', 'menuitem');\n b.tabIndex = -1;\n b.textContent = text;\n b.addEventListener('click', () => run(b));\n return b;\n };\n const copyWhat = acct.paymail ? 'paymail' : 'key';\n const copy = item(`Copy ${copyWhat}`, (b) => {\n void copyText(acct.paymail || acct.identityKey).then((ok) => {\n b.textContent = ok ? 'Copied' : `Copy ${copyWhat}`;\n setTimeout(() => close(true), ok ? 600 : 0);\n });\n });\n const out = item('Disconnect', () => {\n close(false);\n void this.signOut();\n });\n const items = [copy, out];\n menu.append(who);\n if (needsBwalletX(this.#walletType())) {\n // 0.6.0: signed in with another wallet. One line and a way to switch.\n const sw = item('Switch to bWalletX', () => {\n close(false);\n void this.switchToBwalletX();\n });\n const line = document.createElement('div');\n line.className = 'who';\n line.textContent = SWITCH_NOTE;\n menu.append(line, sw);\n items.unshift(sw);\n }\n menu.append(copy, out);\n root.append(style, menu);\n document.body.appendChild(host);\n\n // Fixed position under the chip (above when there is no room), clamped to the viewport: never clipped by an\n // overflow:hidden parent, never wider than a phone screen.\n const place = () => {\n const r = chip.getBoundingClientRect();\n const vw = window.innerWidth || document.documentElement.clientWidth || 360;\n const vh = window.innerHeight || document.documentElement.clientHeight || 640;\n const width = Math.min(260, vw - 32);\n menu.style.width = `${width}px`;\n const left = Math.max(16, Math.min(r.right - width, vw - width - 16));\n menu.style.left = `${left}px`;\n const h = menu.offsetHeight || 150;\n const below = r.bottom + 8;\n menu.style.top = `${below + h > vh && r.top - 8 - h > 0 ? r.top - 8 - h : below}px`;\n };\n place();\n const focusAt = (i: number) => items[(i + items.length) % items.length]!.focus();\n const onKey = (e: KeyboardEvent) => {\n const i = items.indexOf(root.activeElement as HTMLButtonElement);\n if (e.key === 'Escape') { e.preventDefault(); close(true); }\n else if (e.key === 'ArrowDown') { e.preventDefault(); focusAt(i + 1); }\n else if (e.key === 'ArrowUp') { e.preventDefault(); focusAt(i - 1); }\n else if (e.key === 'Home') { e.preventDefault(); focusAt(0); }\n else if (e.key === 'End') { e.preventDefault(); focusAt(items.length - 1); }\n else if (e.key === 'Tab') close(false);\n };\n const onDown = (e: Event) => {\n const path = (e as Event & { composedPath?: () => EventTarget[] }).composedPath?.() ?? [];\n if (!path.includes(host) && !path.includes(this)) close(false);\n };\n const onMove = () => close(false);\n menu.addEventListener('keydown', onKey);\n document.addEventListener('pointerdown', onDown, true);\n window.addEventListener('resize', onMove);\n window.addEventListener('scroll', place, true);\n const close = (focusChip = false) => {\n if (this.#menu?.host !== host) return;\n this.#menu = null;\n menu.removeEventListener('keydown', onKey);\n document.removeEventListener('pointerdown', onDown, true);\n window.removeEventListener('resize', onMove);\n window.removeEventListener('scroll', place, true);\n host.remove();\n this.button?.setAttribute('aria-expanded', 'false');\n if (focusChip) this.button?.focus();\n };\n this.#menu = { host, close };\n chip.setAttribute('aria-expanded', 'true');\n focusAt(0);\n }\n\n /**\n * Disconnect: emits bwalletx-disconnect (cancelable). Unless a listener cancels it (BwalletXProvider signs out\n * itself) or the element is driven by `state`, posts logout-url and shows signed out.\n */\n async signOut(): Promise<void> {\n this.#menu?.close(false);\n if (!this.#emit('bwalletx-disconnect', { element: this, account: this.account }, true)) return;\n if (this.#controlled) return;\n const url = this.#attr('logout-url');\n if (url) await fetch(url, { method: 'POST', credentials: 'include', headers: { 'content-type': 'application/json' }, body: '{}' }).catch(() => undefined);\n // A Disconnect means \"don't connect me automatically\": the remembered wallet goes too (0.6.0).\n if (this.#remember) forgetWalletChoice();\n this.#signedType = null;\n this.#account = null;\n this.#set('signed-out');\n this.#emit('bwalletx-signed-out');\n this.button?.focus();\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 /** \"Other wallets\" is offered under the button: other-wallets on, or auto at lg/md when this element signs in. */\n #otherWalletsShown(size: SigninSize): boolean {\n const a = this.#attr('other-wallets');\n if (a === 'off') return false;\n if (a === 'on') return true;\n return (size === 'lg' || size === 'md') && (this.#controlled || !!this.#attr('challenge-url'));\n }\n\n /** Open the wallet chooser (the \"Other wallets\" link): phone QR, other browser wallets, desktop wallets. */\n otherWallets(): Promise<void> {\n return this.#click('chooser');\n }\n\n /** (0.6.0) \"Switch\": sign in with bWalletX (its sheet when here, else the chooser with Get bWalletX first). */\n switchToBwalletX(): Promise<void> {\n return this.#click('bwalletx');\n }\n\n get #remember() { return this.#attr('remember') !== 'off'; }\n\n /**\n * (0.7.0) \"Use Metanet Desktop or another BRC-100 wallet\" is offered: metanet on, or auto at lg/md when this\n * element signs in or follows a provider. Never on a phone or inside a frame.\n */\n #metanetShown(size: SigninSize): boolean {\n const a = this.#attr('metanet');\n if (a === 'off' || !metanetOffered()) return false;\n if (a === 'on') return true;\n return (size === 'lg' || size === 'md') && (this.#controlled || !!this.#attr('challenge-url'));\n }\n\n /** A Metanet sign-in is on screen: our own, or (driven) the provider's with Metanet remembered. */\n #metanetPending(): boolean {\n return this.#controlled ? this.#attr('wallet-type') === METANET_TYPE : this.#viaMetanet;\n }\n\n /** (0.7.0) The Metanet link: connect to Metanet Desktop on localhost:3321 (after this tap, never before). */\n useMetanet(): Promise<void> {\n return this.#click('metanet');\n }\n\n /**\n * (0.7.0) \"Not you? Use another wallet\": forget the remembered wallet here, and drop a Metanet sign-in in flight\n * (if its verify already set a session, logout-url ends it). Emits bwalletx-not-you (cancelable).\n */\n notYou(): void {\n if (!this.#emit('bwalletx-not-you', { element: this }, true)) return;\n this.#run++;\n if (this.#remember) forgetWalletChoice();\n this.#signedType = null;\n if (this.#viaMetanet && !this.#controlled) {\n this.#viaMetanet = false;\n this.#busy = false;\n if (this.#phase === 'pending') this.#phase = 'signed-out';\n }\n this.#render();\n }\n\n /**\n * (0.7.0) Rule 4: back with Metanet remembered and no session, ONE silent attempt per page load (2 s, a known\n * identity key only), then the signature alone. Any stop or failure is silent: the normal button stays.\n */\n async #silentMetanet() {\n if (this.#controlled || !this.#stateful || !this.#remember || this.#attr('require-token')) return;\n // Only where the Metanet line (and so \"Not you?\") is on screen: not a nav-size button, not metanet=\"off\".\n if (!this.#metanetShown((this.#attr('size') ?? 'lg') as SigninSize)) return;\n const challengeUrl = this.#attr('challenge-url');\n const verifyUrl = this.#attr('verify-url');\n if (!challengeUrl || !verifyUrl || this.#phase !== 'signed-out' || this.#busy || silentAttemptUsed()) return;\n if (rememberedWalletChoice()?.type !== METANET_TYPE || !metanetOffered()) return;\n const run = ++this.#run;\n const live = () => run === this.#run;\n const started = Date.now();\n const r = await runSilentMetanet({\n challengeUrl,\n verifyUrl,\n post: (url, body) => postJson<Record<string, unknown>>(url, body),\n isAbandoned: () => !live(),\n logout: async () => {\n const out = this.#attr('logout-url');\n if (out) await fetch(out, { method: 'POST', credentials: 'include', headers: { 'content-type': 'application/json' }, body: '{}' }).catch(() => undefined);\n },\n onSignIn: () => {\n if (!live() || this.#phase !== 'signed-out' || this.#busy) return;\n this.#viaMetanet = true;\n this.#busy = true;\n this.#pendingLabel = PENDING_LABEL_OTHER;\n this.#set('pending');\n },\n onAttempt: (a) => this.#emit('bwalletx-attempt', a),\n });\n if (!live()) return;\n this.#viaMetanet = false;\n this.#busy = false;\n if (!r) {\n if ((this.#phase as SigninState) === 'pending') this.#set('signed-out');\n return;\n }\n this.#signedType = r.walletType;\n this.#signedIn({ identityKey: r.identityKey!, handle: r.handle, paymail: r.paymail });\n this.#emit('bwalletx-signed-in', { identityKey: r.identityKey, method: 'wallet', nonce: null, signature: null, response: { handle: r.handle, paymail: r.paymail }, silent: true, ms: Date.now() - started });\n }\n\n /** The wallet type the Switch note judges: the provider's, else what signed in here, else the remembered one. */\n #walletType(): string | null {\n if (this.#controlled) return this.#attr('wallet-type');\n return this.#signedType ?? (this.#remember ? (rememberedWalletChoice()?.type ?? null) : null);\n }\n\n #switchNoteShown(size: SigninSize): boolean {\n const a = this.#attr('switch-note');\n if (a === 'off' || !tapGoesElsewhere(this.#walletType())) return false;\n return a === 'on' || size === 'lg' || size === 'md';\n }\n\n /**\n * Signed in: note the wallet type, and remember it for this origin when the user picked it (0.6.0), plus the\n * identity key as known here (0.7.0, public keys only: Metanet's silent attempt goes on only for these). Pass a key\n * only after the site's verify route accepted it.\n */\n #picked(option: WalletOption, reason: ChoiceReason, identityKey?: string | null) {\n this.#signedType = walletTypeOf(option);\n if (this.#remember && isExplicitPick(option, reason)) rememberWalletChoice(option);\n if (this.#remember) rememberKnownIdentityKey(identityKey);\n }\n\n #attempt(option: WalletOption | null, outcome: AttemptOutcome, started: number) {\n this.#emit('bwalletx-attempt', attemptFor(option, outcome, started));\n }\n\n /**\n * Which wallet: bWalletX by its own marker goes straight to its sheet; otherwise the chooser (\"Get bWalletX\" first)\n * when another wallet is here or the user asked; otherwise 'not-found'. null: the chooser was closed.\n */\n async #choose(mode: SigninMode, ms: number, pairing: ReturnType<typeof pairingModal>): Promise<{ option: WalletOption; reason: ChoiceReason } | 'not-found' | null> {\n // 0.6.0: the wallet picked here before goes first when it is here (no chooser), unless this is \"Switch\".\n // 0.7.0: the Metanet link goes to Metanet Desktop, and only there (pinned json-api, after this tap).\n if (mode === 'metanet') return { option: metanetOption(), reason: 'requested' };\n const r = mode === 'signin' && this.#remember ? rememberedWalletChoice() : null;\n // A remembered Metanet is never the button's pick (it has its own link and the silent attempt).\n if (r && r.type !== METANET_TYPE && !(r.type === BWALLETX_TYPE && r.substrate !== 'pairing')) {\n const m = matchRemembered(await discoverWallets({ ms, pairing: () => pairing }), r);\n if (m) return { option: m, reason: 'remembered' };\n }\n if (mode !== 'chooser') {\n const f = await discoverBwalletX(ms);\n if (f) {\n const substrate = f.rdns === RDNS_EXTENSION ? 'extension' : f.rdns === RDNS_MOBILE ? 'in-app' : 'xdm';\n const option = brc100Option(f.wallet, { id: f.rdns ?? 'bwalletx-xdm', rdns: f.rdns ?? undefined, name: 'bWalletX', isBwalletX: true, substrate });\n return { option, reason: 'bwalletx' };\n }\n }\n // Already waited above: a short pass for other wallets (no localhost probe), plus bWalletX on the phone.\n const list = await discoverWallets({ ms: 50, pairing: () => pairing });\n if (mode !== 'chooser' && !hasBwalletX(list) && !otherDetected(list).length) return 'not-found';\n const picked = await chooseWallet(list, { getUrl: this.#attr('get-url') ?? undefined });\n return picked ? { option: picked, reason: 'chooser' } : null;\n }\n\n async #click(mode: SigninMode = 'signin') {\n if (this.hasAttribute('disabled') || this.hasAttribute('loading') || this.#busy || this.state === 'pending') return;\n if (!this.#emit('bwalletx-signin', { element: this, mode }, true)) return;\n\n if (mode === 'signin') {\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\n const challengeUrl = this.#attr('challenge-url');\n if (!challengeUrl) return; // event-only mode: the page runs its own flow\n\n const own = this.#stateful && !this.#controlled;\n const prev = this.#phase === 'signed-in' ? 'signed-in' : 'signed-out';\n const started = Date.now();\n const pairing = pairingModal();\n let option: WalletOption | null = null;\n const run = ++this.#run;\n const live = () => run === this.#run;\n this.#notFound = false;\n this.#busy = true;\n this.#viaMetanet = mode === 'metanet';\n this.#pendingLabel = mode === 'metanet' ? PENDING_LABEL_OTHER : PENDING_LABEL;\n if (own) this.#set('pending');\n else this.#render();\n try {\n const ms = Number(this.#attr('discover-ms')) || DEFAULT_DISCOVER_MS;\n const picked = await this.#choose(mode, ms, pairing);\n if (picked === 'not-found') {\n this.#notFound = true;\n if (own) this.#phase = 'signed-out';\n this.#attempt(null, 'not-found', started);\n this.#emit('bwalletx-not-found');\n if (this.#attr('require-token')) this.#emit('bwalletx-access-denied', { code: 'not_installed', message: 'No wallet found' });\n return;\n }\n if (!picked) {\n if (own) this.#phase = prev;\n this.#attempt(null, 'cancelled', started);\n return;\n }\n option = picked.option;\n const reason = picked.reason;\n if (!option.isBwalletX) {\n this.#pendingLabel = PENDING_LABEL_OTHER;\n if (own) this.#render();\n }\n // Pairing shows the QR here; \"Desktop wallet\" looks on localhost here (after the tap). No key asked yet.\n const cw = await option.connect({ identity: false });\n if (!live()) return; // \"Not you?\" while Metanet was opening\n const wallet = cw.wallet;\n if (!wallet) throw Object.assign(new Error('This wallet cannot sign in here'), { code: 'NOT_SUPPORTED' });\n const sub = substrateOf(option);\n const method = sub === 'extension' ? 'extension' : sub === 'in-app' || sub === 'xdm' ? 'in-app' : sub === 'pairing' ? 'pairing' : 'wallet';\n\n const requireToken = this.#attr('require-token');\n if (requireToken) {\n if (own) this.#phase = 'signed-out'; // the access flow reports through its own events\n // $403 gate. The server's own config is authoritative; these attributes are passed along as a hint.\n const verifyUrl = this.#attr('verify-url');\n const min = this.#attr('min');\n const minBps = this.#attr('min-bps');\n const hint = { token: { id: requireToken, ...(minBps ? { minBps: Number(minBps) } : { min: min ?? '1' }) } };\n try {\n const a = await requestAccess({\n wallet,\n challenge: (identityKey) => postJson<AccessChallengeLike>(challengeUrl, { identityKey, require: hint }),\n verify: verifyUrl ? (response) => postAccess(verifyUrl, response) : undefined,\n });\n // Known only when the site's verify route checked the proof (verify-url).\n this.#picked(option, reason, verifyUrl ? a.response.identityKey : null);\n this.#attempt(option, 'signed-in', started);\n this.#emit('bwalletx-access-granted', { identityKey: a.response.identityKey, response: a.verified });\n } catch (e) {\n const err = e instanceof AccessError ? e : new AccessError('bad_request', String(e));\n this.#attempt(option, outcomeOf(e), started);\n this.#emit('bwalletx-access-denied', { code: err.code, message: err.message, have: err.have, need: err.need });\n }\n return;\n }\n // One wallet sheet: the challenge first (no key), then the key and the signature together; a repeat sign-in\n // reuses the key that signed in here last time, so it is the signature alone.\n const verifyUrl = this.#attr('verify-url');\n const { result: r, verified } = await signInAndVerify({\n wallet,\n // Metanet hands over its key on connect (one request at a time), so its sign-in is the signature alone.\n identityKey: cw.identityKey ?? undefined,\n skipWaitForAuthentication: option.id === METANET_OPTION_ID, // its connect() just checked the lock\n identityKeyHint: verifyUrl ? rememberedIdentity() : undefined,\n challenge: (identityKey) => postJson<Challenge>(challengeUrl, identityKey ? { identityKey } : {}),\n verify: async (res) => (verifyUrl ? await postJson<Record<string, unknown>>(verifyUrl, { identityKey: res.identityKey, nonce: res.nonce, signature: res.signature }) : {}),\n });\n if (!live()) {\n // \"Not you?\" after the wallet signed: land nobody, and end the session the verify route may have set.\n const out = this.#attr('logout-url');\n if (verifyUrl && out) await fetch(out, { method: 'POST', credentials: 'include', headers: { 'content-type': 'application/json' }, body: '{}' }).catch(() => undefined);\n return;\n }\n if (verifyUrl) rememberIdentity(r.identityKey);\n const response = verifyUrl ? (verified as { handle?: string; paymail?: string }) : null;\n // Known only when the site's verify route accepted the signature (verify-url); without it nothing was proved.\n this.#picked(option, reason, verifyUrl ? r.identityKey : null);\n if (own) this.#signedIn({ identityKey: r.identityKey, handle: response?.handle ?? null, paymail: response?.paymail ?? null });\n this.#attempt(option, 'signed-in', started);\n this.#emit('bwalletx-signed-in', { identityKey: r.identityKey, method, nonce: r.nonce, signature: r.signature, response });\n } catch (error) {\n const outcome = outcomeOf(error);\n this.#attempt(option, outcome, started);\n if (!live()) return; // dropped by \"Not you?\": no error to show\n // Closing the phone QR is not an error: back to where we were. Anything else shows as before.\n const closedQr = outcome === 'cancelled' && option?.kind === 'pairing';\n if (own) {\n if (closedQr) this.#phase = prev;\n else {\n this.#error = signInErrorText(error);\n this.#phase = 'error';\n }\n }\n if (!closedQr) this.#emit('bwalletx-error', { error });\n } finally {\n try { pairing.close(); } catch { /* closed */ }\n if (live()) {\n this.#busy = false;\n this.#viaMetanet = false;\n this.#render();\n }\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 * <bwalletx-button>: THE one wallet control for a site's nav (owner, 28 Oct 2026: no more duplicate Connect / Get\n * bWalletX / handle badges side by side). It renders exactly one thing, by state:\n *\n * no wallet in this browser → \"Get bWalletX\" (a link: extension / iphone / android / get, by platform)\n * a wallet here, not connected → \"Connect bWalletX\" (the extension, the in-app browser, or a QR to the phone)\n * connected → the $handle chip (gold b + handle); click to disconnect\n *\n * Phones can't be told apart from \"not installed\" (the app is a separate browser), so they get Connect: it pairs.\n * The look is the official button (SIGNIN_CSS + the gold b mark from <bwalletx-signin>).\n *\n * GUARD: one per page. A second <bwalletx-button> hides itself, and legacy controls inside the same header/nav\n * (`[data-bwx-connect]`, `.nav-connect`, `.nav-acct`, links to bwalletx.com/get) are hidden, each with a\n * console warning. Use only this element; don't add your own Get or Connect links.\n *\n * ON LOAD: discovery only (0.5.6). No wallet call, so no key leaves the wallet and no wallet shows a prompt without a\n * tap. A reload shows Connect again unless `session-url` reports a live session from your server (no wallet call);\n * one tap reconnects (bWalletX answers an approved site without a sheet). Nothing is stored: the old `bwx:connected`\n * entry held the identity key and is deleted on load. 0.6.0 keeps the wallet TYPE instead (`bwx:wallet`, shared with\n * <bwalletx-signin>): a 0.5.5 entry becomes { type: 'bwalletx' } and its key is deleted; Disconnect forgets it.\n *\n * Attributes: size (sm | md | lg, default sm), get-url (overrides the platform link), discover-ms (default 800),\n * lookup-url (handle lookup, default pay.bwallet.space; \"off\" to skip), session-url (GET → { identityKey, paymail? }\n * from your server: shows the chip on load with no wallet call).\n * Events (bubble, composed): bwalletx-connected { identityKey }, bwalletx-disconnected.\n */\nimport { discoverBwalletX } from './discover.js';\nimport { clearPairing } from './pair.js';\nimport { connectBwalletX } from './signin.js';\nimport { pairingModal } from './modal.js';\nimport { markSvg, SIGNIN_CSS } from './element.js';\nimport { BWALLETX_TYPE, forgetWalletChoice, rememberWalletChoice, rememberedWalletChoice } from './choice.js';\nimport type { Substrate } from './wallets.js';\n\nexport const BUTTON_TAG = 'bwalletx-button';\n/** Legacy (0.5.5) localStorage key that held the identity key. Deleted on load since 0.5.6; never written. */\nexport const CONNECTED_KEY = 'bwx:connected';\n\n/**\n * (0.6.0) Migrate the 0.5.5 `bwx:connected` entry to the type-only record: the user had connected bWalletX here, so\n * remember { type: 'bwalletx' } (unless a choice is already remembered) and delete the key. True when one was there.\n */\nexport function migrateConnectedKey(): boolean {\n const had = dropLegacyConnectedKey();\n if (had && !rememberedWalletChoice()) rememberBwalletX('extension');\n return had;\n}\n\nfunction rememberBwalletX(substrate: Substrate) {\n rememberWalletChoice({ id: 'bwalletx', name: 'bWalletX', kind: substrate === 'pairing' ? 'pairing' : 'brc100', isBwalletX: true, substrate, connect: async () => { throw new Error('unused'); } });\n}\n\n/** Delete the 0.5.5 `bwx:connected` entry (it held the identity key). True when one was there. */\nexport function dropLegacyConnectedKey(): boolean {\n try {\n const had = globalThis.localStorage?.getItem(CONNECTED_KEY) != null;\n if (had) globalThis.localStorage?.removeItem(CONNECTED_KEY);\n return had;\n } catch {\n return false;\n }\n}\nconst LOOKUP = 'https://pay.bwallet.space/api/paymail/lookup?key=';\nconst LEGACY = '[data-bwx-connect], .nav-connect, .nav-acct, a[href^=\"https://bwalletx.com/get\"], a[href^=\"https://www.bwalletx.com/get\"]';\n\nexport type ButtonState = 'checking' | 'none' | 'available' | 'connecting' | 'connected';\n\n/** Where \"Get bWalletX\" goes for this user agent. */\nexport function getUrlFor(ua: string, touchMac = false): string {\n if (/iPhone|iPad|iPod/i.test(ua) || (touchMac && /Macintosh/.test(ua))) return 'https://bwalletx.com/iphone';\n if (/Android/i.test(ua)) return 'https://bwalletx.com/android';\n if (/Chrome\\//.test(ua) && !/Edg\\/|OPR\\//.test(ua)) return 'https://bwalletx.com/extension';\n return 'https://bwalletx.com/get';\n}\n\n/** What a signed-out button should say before/after discovery. */\nexport function stateFor(o: { connected: boolean; found: boolean | null; phone: boolean }): ButtonState {\n if (o.connected) return 'connected';\n if (o.found === null) return o.phone ? 'available' : 'checking';\n return o.found || o.phone ? 'available' : 'none';\n}\n\n/** $alice for alice@bwalletx.com, other paymails in full, else a short key. */\nexport function handleLabel(key: string, paymail: string | null): string {\n if (paymail && /@bwalletx\\.com$/i.test(paymail)) return '$' + paymail.split('@')[0];\n if (paymail) return paymail;\n return key.slice(0, 6) + '…' + key.slice(-4);\n}\n\nconst CHIP_CSS = `\na.b,button.b{all:unset;box-sizing:border-box}\n.chip{background:#0b0b0c;color:#ffd24d;border:1px solid rgba(255,210,77,.45);box-shadow:none}\n.chip:hover{background:#151517;border-color:#ffd24d}\n.chip .dot{width:8px;height:8px;border-radius:50%;background:#34d399;flex:none}\n.txt b{overflow:hidden;text-overflow:ellipsis;max-width:min(40vw,220px)}\n:host(:not([size])) button,:host(:not([size])) a.btn,:host([size=sm]) a.btn{padding:6px 12px 6px 6px;border-radius:8px;font-size:13px;gap:8px;min-height:36px}\n:host(:not([size])) .mark,:host([size=sm]) a.btn .mark{width:22px;height:22px}\na.btn{all:unset;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:12px;cursor:pointer;\n padding:16px 20px;border-radius:12px;font-size:16px;font-weight:700;line-height:1.2;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)}\na.btn:hover{background:linear-gradient(180deg,#fde68a,#fbbf24)}\na.btn:focus-visible{outline:2px solid #b45309;outline-offset:3px}\n:host([size=md]) a.btn{padding:10px 16px;border-radius:10px;font-size:15px;gap:10px}\n`;\n\nconst live = new Set<HTMLElement>();\n\nfunction createClass(): CustomElementConstructor {\n return class BwalletxButtonElement extends HTMLElement {\n #root: ShadowRoot;\n #state: ButtonState = 'checking';\n #key: string | null = null;\n #paymail: string | null = null;\n #duplicate = false;\n\n constructor() {\n super();\n this.#root = this.attachShadow({ mode: 'open' });\n }\n\n get state(): ButtonState { return this.#state; }\n get identityKey(): string | null { return this.#key; }\n\n connectedCallback() {\n if (live.size && ![...live].includes(this)) {\n this.#duplicate = true;\n this.hidden = true;\n console.warn('[bwalletx] A second <bwalletx-button> is on this page; it is hidden. Use one per page.');\n return;\n }\n live.add(this);\n this.#hideLegacy();\n migrateConnectedKey();\n const phone = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);\n this.#set(stateFor({ connected: false, found: null, phone }));\n const ms = Number(this.getAttribute('discover-ms')) || 800;\n // Discovery only: no wallet call on load (no key leaves the wallet, no prompt without a tap).\n void discoverBwalletX(ms).then((f) => {\n if (!this.isConnected) return;\n if (this.#state !== 'connected' && this.#state !== 'connecting') this.#set(stateFor({ connected: false, found: !!f, phone }));\n }).catch(() => { if (this.#state === 'checking') this.#set('none'); });\n void this.#restoreSession();\n }\n\n /** A live session your server reports (session-url): the chip, with no wallet call. */\n async #restoreSession() {\n const url = this.getAttribute('session-url');\n if (!url) return;\n try {\n const r = await fetch(url, { credentials: 'include', headers: { accept: 'application/json' } });\n const j = (await r.json().catch(() => ({}))) as { identityKey?: string | null; paymail?: string | null };\n if (j.identityKey && this.isConnected && this.#state !== 'connected' && this.#state !== 'connecting') {\n this.#connected(j.identityKey);\n if (j.paymail) { this.#paymail = j.paymail; this.#render(); }\n }\n } catch { /* no session */ }\n }\n\n disconnectedCallback() { if (!this.#duplicate) live.delete(this); }\n\n\n #hideLegacy() {\n const scope = this.closest('header, nav') ?? document;\n for (const el of Array.from(scope.querySelectorAll<HTMLElement>(LEGACY))) {\n if (el === this || el.contains(this)) continue;\n el.hidden = true;\n el.style.setProperty('display', 'none', 'important');\n console.warn('[bwalletx] Hid a second wallet control next to <bwalletx-button>:', el, '. Use only <bwalletx-button>; don\\'t add your own Get or Connect links.');\n }\n }\n\n #emit(type: string, detail?: unknown) { this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true })); }\n\n #set(s: ButtonState) { this.#state = s; this.setAttribute('state', s); this.#render(); }\n\n #connected(key: string) {\n this.#key = key; this.#set('connected');\n this.#emit('bwalletx-connected', { identityKey: key });\n const lookup = this.getAttribute('lookup-url');\n if (lookup === 'off') return;\n void fetch((lookup ?? LOOKUP) + encodeURIComponent(key)).then((r) => (r.ok ? r.json() : null)).then((j: { paymail?: unknown } | null) => {\n if (j && typeof j.paymail === 'string' && this.#key === key) { this.#paymail = j.paymail; this.#render(); }\n }).catch(() => undefined);\n }\n\n async connect() {\n if (this.#state === 'connecting' || this.#state === 'connected') return;\n const modal = pairingModal({ title: 'Connect bWalletX' });\n this.#set('connecting');\n try {\n const { wallet, method } = await connectBwalletX({ pairing: modal });\n const { publicKey } = await wallet.getPublicKey({ identityKey: true });\n // The user tapped Connect bWalletX: remember the TYPE for this origin (never the key).\n rememberBwalletX(method === 'pairing' ? 'pairing' : method === 'in-app' ? 'in-app' : 'extension');\n this.#connected(publicKey);\n } catch (e) {\n if ((e as { code?: string })?.code === 'NOT_FOUND') this.#set('none');\n else { this.#set('available'); if ((e as { name?: string })?.name !== 'AbortError') console.warn('[bwalletx] connect:', e); }\n } finally {\n try { modal.close(); } catch { /* closed */ }\n }\n }\n\n disconnect() {\n try { clearPairing(); } catch { /* none */ }\n try { window.postMessage({ type: 'bwallet:disconnect' }, location.origin); } catch { /* no window */ }\n this.#key = null; this.#paymail = null; dropLegacyConnectedKey();\n if (rememberedWalletChoice()?.type === BWALLETX_TYPE) forgetWalletChoice();\n this.#set('available');\n this.#emit('bwalletx-disconnected');\n }\n\n #render() {\n const esc = (s: string) => s.replace(/[&<>\"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '\"': '"' })[c]!);\n const size = this.getAttribute('size') ?? 'sm';\n const px = size === 'lg' ? 20 : size === 'md' ? 17 : 15;\n const mark = `<span class=\"mark\" part=\"mark\">${markSvg(px)}</span>`;\n const css = `<style>${SIGNIN_CSS}${CHIP_CSS}</style>`;\n const s = this.#state;\n if (s === 'none') {\n const href = this.getAttribute('get-url') ?? getUrlFor(navigator.userAgent, (navigator.maxTouchPoints ?? 0) > 1);\n this.#root.innerHTML = `${css}<a class=\"btn\" part=\"button\" href=\"${esc(href)}\" target=\"_blank\" rel=\"noopener\">${mark}<span class=\"txt\" part=\"text\"><b part=\"label\">Get bWalletX</b></span></a>`;\n return;\n }\n if (s === 'connected' && this.#key) {\n const name = handleLabel(this.#key, this.#paymail);\n this.#root.innerHTML = `${css}<button type=\"button\" class=\"chip\" part=\"button chip\" title=\"Connected to bWalletX. Click to disconnect.\" aria-label=\"Connected as ${esc(name)}. Disconnect\">${mark}<span class=\"txt\" part=\"text\"><b part=\"label\">${esc(name)}</b></span><span class=\"dot\" aria-hidden=\"true\"></span></button>`;\n this.#root.querySelector('button')!.onclick = () => this.disconnect();\n return;\n }\n const busy = s === 'connecting' || s === 'checking';\n this.#root.innerHTML = `${css}<button type=\"button\" part=\"button\"${busy ? ' aria-busy=\"true\"' : ''}>${busy ? '<span class=\"mark\" part=\"mark\"><span class=\"spin\" aria-hidden=\"true\"></span></span>' : mark}<span class=\"txt\" part=\"text\"><b part=\"label\">${s === 'connecting' ? 'Connecting…' : 'Connect bWalletX'}</b></span></button>`;\n this.#root.querySelector('button')!.onclick = () => void this.connect();\n }\n };\n}\n\n/** Register <bwalletx-button> (idempotent; no-op on a server). */\nexport function defineBwalletxButton(tag = BUTTON_TAG): void {\n if (typeof customElements === 'undefined' || customElements.get(tag)) return;\n customElements.define(tag, createClass());\n}\n\n/** Test hook: forget which button owns the page. */\nexport function _resetBwalletxButtons() { live.clear(); }\n"],"mappings":"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","names":["el","import_sdk","import_sdk","import_sdk","c","identityKey","signature","import_sdk","r","qrcode","p","row","import_sdk","b64url","live","verifyUrl","response","createClass","el","s"]}
|