@bwalletx/connect 0.5.0 → 0.5.4
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 +18 -0
- package/README.md +10 -2
- package/dist/{access-Z6xQwKVF.d.cts → access-Dp0eKIOc.d.cts} +1 -1
- package/dist/{access-Z6xQwKVF.d.ts → access-Dp0eKIOc.d.ts} +1 -1
- package/dist/bwalletx-connect.global.js +11 -8
- package/dist/bwalletx-connect.global.js.map +1 -1
- package/dist/{chunk-CVLXFNAG.js → chunk-EXRQJTXF.js} +165 -26
- package/dist/chunk-EXRQJTXF.js.map +1 -0
- package/dist/{chunk-GF6GUDZL.js → chunk-RIOHG5JH.js} +67 -12
- package/dist/chunk-RIOHG5JH.js.map +1 -0
- package/dist/element.cjs +166 -31
- package/dist/element.cjs.map +1 -1
- package/dist/element.js +1 -1
- package/dist/index.cjs +250 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -9
- package/dist/index.d.ts +60 -9
- package/dist/index.js +14 -2
- package/dist/index.js.map +1 -1
- package/dist/next.d.cts +1 -1
- package/dist/next.d.ts +1 -1
- package/dist/react.cjs +887 -693
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +7 -2
- package/dist/react.d.ts +7 -2
- package/dist/react.js +11 -3
- package/dist/react.js.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/shell-react.cjs.map +1 -1
- package/dist/shell-react.js.map +1 -1
- package/dist/{wallets-VOKIKBbO.d.ts → wallets-CbzMtxrf.d.cts} +1 -1
- package/dist/{wallets-VOKIKBbO.d.cts → wallets-CbzMtxrf.d.ts} +1 -1
- package/package.json +11 -12
- package/dist/chunk-CVLXFNAG.js.map +0 -1
- package/dist/chunk-GF6GUDZL.js.map +0 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BWALLETX_RDNS,
|
|
3
3
|
RDNS_EXTENSION,
|
|
4
|
+
WEB_WALLET_URL,
|
|
4
5
|
pairBwalletX,
|
|
5
6
|
restorePairing
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EXRQJTXF.js";
|
|
7
8
|
|
|
8
9
|
// src/pay.ts
|
|
9
10
|
import { P2PKH, PublicKey, Transaction, Utils } from "@bsv/sdk";
|
|
@@ -235,7 +236,7 @@ async function probe(substrate, ms) {
|
|
|
235
236
|
}
|
|
236
237
|
async function discoverWallets(o = {}) {
|
|
237
238
|
const out = [];
|
|
238
|
-
const ms = o.ms ??
|
|
239
|
+
const ms = o.ms ?? 300;
|
|
239
240
|
if (typeof window !== "undefined") {
|
|
240
241
|
const seen = /* @__PURE__ */ new Map();
|
|
241
242
|
const onAnnounce = (e) => {
|
|
@@ -249,7 +250,7 @@ async function discoverWallets(o = {}) {
|
|
|
249
250
|
window.addEventListener("brc100:announceWallet", onAnnounce);
|
|
250
251
|
window.dispatchEvent(new Event("brc100:requestWallet"));
|
|
251
252
|
const local = o.probeLocal ? Promise.all([probe("json-api", ms), probe("Cicada", ms)]) : Promise.resolve([null, null]);
|
|
252
|
-
await new Promise((r) => setTimeout(r, ms));
|
|
253
|
+
await new Promise((r) => setTimeout(r, seen.size > 0 || window.CWI ? Math.min(ms, 50) : ms));
|
|
253
254
|
window.removeEventListener("brc100:announceWallet", onAnnounce);
|
|
254
255
|
out.push(...seen.values());
|
|
255
256
|
const cwi = window.CWI;
|
|
@@ -279,6 +280,9 @@ var CSS = `
|
|
|
279
280
|
.bwx-row{display:flex;gap:8px;margin-top:14px}
|
|
280
281
|
.bwx-btn{flex:1;border:1px solid #3a3220;background:#15130e;color:#f4f1e8;border-radius:10px;padding:10px 12px;font:inherit;cursor:pointer}
|
|
281
282
|
.bwx-btn:hover{border-color:#e8c766}
|
|
283
|
+
a.bwx-btn{display:block;text-align:center;text-decoration:none;box-sizing:border-box}
|
|
284
|
+
.bwx-primary{background:linear-gradient(180deg,#fcd34d,#f59e0b);color:#000;border:0;font-weight:700;min-height:48px;padding:13px 12px}
|
|
285
|
+
.bwx-stack{display:flex;flex-direction:column;gap:8px}
|
|
282
286
|
.bwx-list{display:flex;flex-direction:column;gap:8px}
|
|
283
287
|
.bwx-opt{display:flex;align-items:center;gap:10px;text-align:left}
|
|
284
288
|
.bwx-opt img{width:24px;height:24px;border-radius:6px}
|
|
@@ -309,6 +313,18 @@ function qrSvg(text) {
|
|
|
309
313
|
q.make();
|
|
310
314
|
return q.createSvgTag({ cellSize: 4, margin: 2, scalable: true });
|
|
311
315
|
}
|
|
316
|
+
function isTouchDevice(env = globalThis) {
|
|
317
|
+
const nav = env.navigator;
|
|
318
|
+
if (!nav) return false;
|
|
319
|
+
const ua = nav.userAgent ?? "";
|
|
320
|
+
if (/Android|iPhone|iPad|iPod|Mobile|Silk|Kindle/i.test(ua)) return true;
|
|
321
|
+
if (/Macintosh/.test(ua) && (nav.maxTouchPoints ?? 0) > 1) return true;
|
|
322
|
+
try {
|
|
323
|
+
return !!env.matchMedia?.("(pointer: coarse)").matches && !env.matchMedia?.("(hover: hover)").matches;
|
|
324
|
+
} catch {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
312
328
|
function pairingModal(o = {}) {
|
|
313
329
|
const ac = new AbortController();
|
|
314
330
|
let ui = null;
|
|
@@ -325,20 +341,37 @@ function pairingModal(o = {}) {
|
|
|
325
341
|
if (typeof document === "undefined") return;
|
|
326
342
|
close();
|
|
327
343
|
ui = mount();
|
|
344
|
+
const app = o.mode === "app" || (o.mode ?? "auto") === "auto" && isTouchDevice();
|
|
328
345
|
const h = el("h2", "", o.title ?? "Connect bWalletX");
|
|
346
|
+
const cancel = el("button", "bwx-btn", "Cancel");
|
|
347
|
+
cancel.onclick = () => {
|
|
348
|
+
o.onCancel?.();
|
|
349
|
+
ac.abort();
|
|
350
|
+
};
|
|
351
|
+
codeEl = el("div", "bwx-code", "");
|
|
352
|
+
codeEl.setAttribute("aria-live", "polite");
|
|
353
|
+
if (app) {
|
|
354
|
+
const p2 = el("p", "", "Open bWalletX, approve, then come back to this page.");
|
|
355
|
+
const stack = el("div", "bwx-stack");
|
|
356
|
+
const open = el("a", "bwx-btn bwx-primary", "Open bWalletX");
|
|
357
|
+
open.href = link;
|
|
358
|
+
open.rel = "noopener";
|
|
359
|
+
const web = el("button", "bwx-btn", "Use web.bwalletx.com instead");
|
|
360
|
+
web.onclick = () => {
|
|
361
|
+
void navigator.clipboard?.writeText(link).catch(() => void 0);
|
|
362
|
+
window.open(WEB_WALLET_URL, "_blank", "noopener");
|
|
363
|
+
p2.textContent = "Link copied. In web.bwalletx.com tap Connect and paste it, then come back here.";
|
|
364
|
+
};
|
|
365
|
+
stack.append(open, web, cancel);
|
|
366
|
+
ui.box.append(h, p2, codeEl, stack);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
329
369
|
const p = el("p", "", "Scan with bWalletX on your phone, or paste the link into web.bwalletx.com.");
|
|
330
370
|
const qr = el("div", "bwx-qr");
|
|
331
371
|
qr.innerHTML = qrSvg(link);
|
|
332
|
-
codeEl = el("div", "bwx-code", "");
|
|
333
|
-
codeEl.setAttribute("aria-live", "polite");
|
|
334
372
|
const row = el("div", "bwx-row");
|
|
335
373
|
const copy = el("button", "bwx-btn", "Copy link");
|
|
336
374
|
copy.onclick = () => void navigator.clipboard?.writeText(link).then(() => copy.textContent = "Copied");
|
|
337
|
-
const cancel = el("button", "bwx-btn", "Cancel");
|
|
338
|
-
cancel.onclick = () => {
|
|
339
|
-
o.onCancel?.();
|
|
340
|
-
ac.abort();
|
|
341
|
-
};
|
|
342
375
|
row.append(copy, cancel);
|
|
343
376
|
ui.box.append(h, p, qr, codeEl, row);
|
|
344
377
|
},
|
|
@@ -383,6 +416,25 @@ function pickWallet(options, o = {}) {
|
|
|
383
416
|
});
|
|
384
417
|
}
|
|
385
418
|
|
|
419
|
+
// src/theme.ts
|
|
420
|
+
var WALLET_THEME_META = "bwalletx-theme";
|
|
421
|
+
var ID = /^[a-z0-9-]{1,32}$/;
|
|
422
|
+
function declareWalletTheme(theme) {
|
|
423
|
+
if (typeof document === "undefined") return;
|
|
424
|
+
const id = (theme ?? "").trim().toLowerCase();
|
|
425
|
+
let meta = document.head.querySelector(`meta[name="${WALLET_THEME_META}"]`);
|
|
426
|
+
if (!id || !ID.test(id)) {
|
|
427
|
+
meta?.remove();
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
if (!meta) {
|
|
431
|
+
meta = document.createElement("meta");
|
|
432
|
+
meta.name = WALLET_THEME_META;
|
|
433
|
+
document.head.appendChild(meta);
|
|
434
|
+
}
|
|
435
|
+
if (meta.content !== id) meta.content = id;
|
|
436
|
+
}
|
|
437
|
+
|
|
386
438
|
export {
|
|
387
439
|
BRC29_PROTOCOL,
|
|
388
440
|
PaymentError,
|
|
@@ -398,7 +450,10 @@ export {
|
|
|
398
450
|
handcashAdapter,
|
|
399
451
|
discoverWallets,
|
|
400
452
|
qrSvg,
|
|
453
|
+
isTouchDevice,
|
|
401
454
|
pairingModal,
|
|
402
|
-
pickWallet
|
|
455
|
+
pickWallet,
|
|
456
|
+
WALLET_THEME_META,
|
|
457
|
+
declareWalletTheme
|
|
403
458
|
};
|
|
404
|
-
//# sourceMappingURL=chunk-
|
|
459
|
+
//# sourceMappingURL=chunk-RIOHG5JH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pay.ts","../src/wallets.ts","../src/modal.ts","../src/theme.ts"],"sourcesContent":["/**\n * Browser-side payment helpers on top of the BRC-100 wallet's createAction. Works with any\n * BRC-100 wallet. Each helper asks the wallet once; it never retries a spend. If a call fails\n * the error says whether the wallet may have sent anything (`maybeSent`).\n */\nimport { P2PKH, PublicKey, Transaction, Utils, type WalletInterface } from '@bsv/sdk';\n\n/** BRC-29 payment protocol id. */\nexport const BRC29_PROTOCOL: [2, string] = [2, '3241645161d8'];\n\nexport type PayTo = string; // paymail (name@domain), P2PKH address, or 66-hex identity key\n\nexport interface PayOutput {\n /** Locking script hex. */\n script: string;\n satoshis: number;\n description?: string;\n}\n\nexport interface PayRequest {\n to: PayTo;\n /** Amount in satoshis. Give this or `usd`. */\n sats?: number;\n /** Amount in US dollars, converted at `usdPerBsv` (or the live WhatsOnChain rate). */\n usd?: number;\n /** Shown in the wallet and, with `memoOnChain`, written in an OP_RETURN output. */\n memo?: string;\n memoOnChain?: boolean;\n /** Labels for the wallet's history. */\n labels?: string[];\n}\n\nexport interface PayOptions {\n /** Fixed rate for `usd`. Otherwise fetched from WhatsOnChain. */\n usdPerBsv?: number | (() => Promise<number>);\n /** Resolve a paymail to outputs. Default: bsvalias P2P payment destination (needs CORS on the paymail host). */\n resolvePaymail?: (paymail: string, sats: number) => Promise<{ outputs: PayOutput[]; reference?: string; submit?: (rawTxHex: string) => Promise<void> }>;\n fetch?: typeof fetch;\n}\n\nexport interface Brc29Remittance {\n senderIdentityKey: string;\n derivationPrefix: string;\n derivationSuffix: string;\n outputIndex: number;\n}\n\nexport interface PayResult {\n txid: string;\n /** Atomic BEEF (BRC-95) if the wallet returned it. Send it to your server's verifyPayment. */\n tx?: number[];\n sats: number;\n outputs: PayOutput[];\n /** For an identity-key payment: what the recipient needs to internalize the output (BRC-29). Deliver it to them. */\n remittance?: Brc29Remittance;\n}\n\nexport type PaymentErrorCode = 'BAD_REQUEST' | 'RESOLVE_FAILED' | 'RATE_FAILED' | 'WALLET_REJECTED' | 'WALLET_ERROR' | 'NOT_SUPPORTED';\n\nexport class PaymentError extends Error {\n constructor(\n readonly code: PaymentErrorCode,\n message: string,\n /** true when the wallet was asked to spend and the outcome is unknown. Check before trying again. */\n readonly maybeSent = false,\n readonly cause?: unknown,\n ) {\n super(message);\n this.name = 'PaymentError';\n }\n}\n\n/** A wallet that is not BRC-100 (the HandCash transitional adapter) can still pay through this. */\nexport interface LegacyPayer {\n pay(req: PayRequest & { sats: number }): Promise<PayResult>;\n}\nexport type PaySource = WalletInterface | LegacyPayer;\n\nconst isLegacy = (s: PaySource): s is LegacyPayer => typeof (s as LegacyPayer).pay === 'function' && typeof (s as WalletInterface).createAction !== 'function';\n\nexport const isIdentityKeyHex = (s: string) => /^0[23][0-9a-fA-F]{64}$/.test(s);\nexport const isPaymail = (s: string) => /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(s);\n\nfunction randomB64(n: number) {\n const b = new Uint8Array(n);\n globalThis.crypto.getRandomValues(b);\n return Utils.toBase64(Array.from(b));\n}\n\nfunction opReturn(text: string): string {\n const d = Utils.toArray(text, 'utf8');\n const len = d.length;\n const push = len < 0x4c ? [len] : len <= 0xff ? [0x4c, len] : [0x4d, len & 0xff, len >> 8];\n return Utils.toHex([0x00, 0x6a, ...push, ...d]);\n}\n\nconst clip = (s: string, n: number) => (s.length > n ? s.slice(0, n - 1) + '…' : s);\n/** createAction descriptions must be 5–50 bytes. */\nconst describe = (s: string) => clip(s.length < 5 ? `${s} payment`.trim() : s, 50);\n\nasync function usdRate(o: PayOptions): Promise<number> {\n if (typeof o.usdPerBsv === 'number') return o.usdPerBsv;\n try {\n if (typeof o.usdPerBsv === 'function') return await o.usdPerBsv();\n const r = await (o.fetch ?? fetch)('https://api.whatsonchain.com/v1/bsv/main/exchangerate');\n const j = (await r.json()) as { rate?: number };\n if (!r.ok || !(Number(j.rate) > 0)) throw new Error(`status ${r.status}`);\n return Number(j.rate);\n } catch (e) {\n throw new PaymentError('RATE_FAILED', `Could not get the BSV/USD rate: ${(e as Error).message}`, false, e);\n }\n}\n\n/** Satoshis for a request (sats as given, or usd converted, rounded up). */\nexport async function amountInSats(req: Pick<PayRequest, 'sats' | 'usd'>, o: PayOptions = {}): Promise<number> {\n if (req.sats != null) {\n if (!Number.isSafeInteger(req.sats) || req.sats <= 0) throw new PaymentError('BAD_REQUEST', 'sats must be a positive integer');\n return req.sats;\n }\n if (req.usd != null) {\n if (!(req.usd > 0)) throw new PaymentError('BAD_REQUEST', 'usd must be positive');\n return Math.max(1, Math.ceil((req.usd / (await usdRate(o))) * 1e8));\n }\n throw new PaymentError('BAD_REQUEST', 'Give sats or usd');\n}\n\n/** Default paymail resolver: bsvalias P2P Payment Destination (BRC-? / capability 2a40af698840). */\nexport async function resolvePaymailP2P(paymail: string, sats: number, f: typeof fetch = fetch) {\n const [alias, domain] = paymail.split('@');\n const fail = (m: string, e?: unknown) => new PaymentError('RESOLVE_FAILED', `Could not resolve ${paymail}: ${m}`, false, e);\n let caps: Record<string, string>;\n try {\n const r = await f(`https://${domain}/.well-known/bsvalias`);\n caps = ((await r.json()) as { capabilities: Record<string, string> }).capabilities;\n } catch (e) {\n throw fail('no bsvalias document (or CORS blocked it; resolve on your server and pass resolvePaymail)', e);\n }\n const fill = (u: string) => u.replace('{alias}', encodeURIComponent(alias)).replace('{domain.tld}', domain);\n const dest = caps?.['2a40af698840'];\n if (!dest) throw fail('it does not offer P2P payment destinations');\n let body: { outputs?: { script: string; satoshis: number }[]; reference?: string };\n try {\n const r = await f(fill(dest), { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ satoshis: sats }) });\n if (!r.ok) throw new Error(`status ${r.status}`);\n body = await r.json();\n } catch (e) {\n throw fail((e as Error).message, e);\n }\n if (!body.outputs?.length) throw fail('no outputs returned');\n const receive = caps['5f1323cddf31'];\n return {\n outputs: body.outputs.map((o) => ({ script: o.script, satoshis: o.satoshis })),\n reference: body.reference,\n submit: receive\n ? async (hex: string) => {\n await f(fill(receive), {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ hex, reference: body.reference, metadata: {} }),\n });\n }\n : undefined,\n };\n}\n\nasync function runAction(wallet: WalletInterface, description: string, outputs: PayOutput[], labels?: string[]) {\n try {\n return await wallet.createAction({\n description: describe(description),\n outputs: outputs.map((o) => ({ lockingScript: o.script, satoshis: o.satoshis, outputDescription: describe(o.description ?? 'payment') })),\n labels: labels?.length ? labels : undefined,\n options: { randomizeOutputs: false },\n });\n } catch (e) {\n const msg = (e as Error)?.message ?? String(e);\n const rejected = /denied|reject|cancel|abort|user/i.test(msg) || (e as { code?: unknown })?.code === 4001;\n // Not retried: a lost reply could mean the wallet already broadcast it.\n throw new PaymentError(rejected ? 'WALLET_REJECTED' : 'WALLET_ERROR', rejected ? 'The payment was declined in the wallet.' : `The wallet could not make the payment: ${msg}`, !rejected, e);\n }\n}\n\n/** Pay a paymail, address or identity key. One wallet prompt; never retried. */\nexport async function pay(source: PaySource, req: PayRequest, o: PayOptions = {}): Promise<PayResult> {\n const to = (req.to ?? '').trim();\n if (!to) throw new PaymentError('BAD_REQUEST', 'Give a recipient (to)');\n if (req.memo && req.memo.length > 1000) throw new PaymentError('BAD_REQUEST', 'memo is too long');\n const sats = await amountInSats(req, o);\n if (isLegacy(source)) return source.pay({ ...req, to, sats });\n\n let outputs: PayOutput[];\n let remittance: Brc29Remittance | undefined;\n let submit: ((hex: string) => Promise<void>) | undefined;\n if (isIdentityKeyHex(to)) {\n const derivationPrefix = randomB64(8);\n const derivationSuffix = randomB64(8);\n let pk: string;\n let me: string;\n try {\n ({ publicKey: pk } = await source.getPublicKey({ protocolID: BRC29_PROTOCOL, keyID: `${derivationPrefix} ${derivationSuffix}`, counterparty: to.toLowerCase() }));\n ({ publicKey: me } = await source.getPublicKey({ identityKey: true }));\n } catch (e) {\n throw new PaymentError('WALLET_ERROR', `The wallet could not derive the payment key: ${(e as Error).message}`, false, e);\n }\n outputs = [{ script: new P2PKH().lock(PublicKey.fromString(pk).toHash() as number[]).toHex(), satoshis: sats, description: 'payment' }];\n remittance = { senderIdentityKey: me, derivationPrefix, derivationSuffix, outputIndex: 0 };\n } else if (isPaymail(to)) {\n const r = await (o.resolvePaymail ?? ((p, s) => resolvePaymailP2P(p, s, o.fetch ?? fetch)))(to, sats);\n outputs = r.outputs;\n submit = r.submit;\n } else {\n try {\n outputs = [{ script: new P2PKH().lock(to).toHex(), satoshis: sats, description: 'payment' }];\n } catch {\n throw new PaymentError('BAD_REQUEST', `Not a paymail, address or identity key: ${to}`);\n }\n }\n if (req.memo && req.memoOnChain) outputs = [...outputs, { script: opReturn(req.memo), satoshis: 0, description: 'memo' }];\n\n const r = await runAction(source, req.memo || `Pay ${clip(to, 30)}`, outputs, req.labels);\n if (!r.txid) throw new PaymentError('WALLET_ERROR', 'The wallet did not return a txid', true);\n const tx = r.tx ? Array.from(r.tx) : undefined;\n if (submit && tx) {\n // Tell the paymail host about the tx. Best effort: the payment itself is already made.\n await submit(Transaction.fromAtomicBEEF(tx).toHex()).catch(() => {});\n }\n return { txid: r.txid, tx, sats, outputs, remittance };\n}\n\n/** pay() labelled as a tip. */\nexport function tip(source: PaySource, req: PayRequest, o: PayOptions = {}): Promise<PayResult> {\n return pay(source, { memo: 'Tip', ...req, labels: [...(req.labels ?? []), 'tip'] }, o);\n}\n\nexport interface TokenQuote {\n /** Outputs to fund, as your server priced them (e.g. payment to the seller + fee). */\n outputs: PayOutput[];\n description?: string;\n /** Called with the result after the wallet signs; e.g. POST txid + tx to your server for verifyPayment. */\n onPaid?: (r: PayResult) => Promise<void> | void;\n}\n\nexport interface BuyTokenRequest {\n token: string;\n amount: number | string;\n /** The hook point: return the outputs for this purchase (usually from your server). */\n quote: (req: { token: string; amount: number | string }) => Promise<TokenQuote>;\n labels?: string[];\n}\n\n/** Buy a token: your `quote` hook prices it, the wallet pays once, `onPaid` delivers it. */\nexport async function buyToken(source: PaySource, req: BuyTokenRequest): Promise<PayResult> {\n if (isLegacy(source)) throw new PaymentError('NOT_SUPPORTED', 'This wallet cannot buy tokens. Use a BRC-100 wallet such as bWalletX.');\n const q = await req.quote({ token: req.token, amount: req.amount });\n if (!q?.outputs?.length) throw new PaymentError('BAD_REQUEST', 'The quote returned no outputs');\n const sats = q.outputs.reduce((n, x) => n + x.satoshis, 0);\n const r = await runAction(source, q.description ?? `Buy ${clip(req.token, 30)}`, q.outputs, [...(req.labels ?? []), 'token-buy']);\n if (!r.txid) throw new PaymentError('WALLET_ERROR', 'The wallet did not return a txid', true);\n const res: PayResult = { txid: r.txid, tx: r.tx ? Array.from(r.tx) : undefined, sats, outputs: q.outputs };\n await q.onPaid?.(res);\n return res;\n}\n","/**\n * Every wallet the user could connect with, behind one interface. BRC-100 first: bWalletX, then any\n * other wallet that announces itself (Yours, Metanet, ...), the in-app browser, optional localhost\n * desktop wallets, phone pairing, and app-supplied adapters (e.g. the transitional HandCash one).\n */\nimport { WalletClient, type WalletInterface } from '@bsv/sdk';\nimport { BWALLETX_RDNS, RDNS_EXTENSION } from './discover.js';\nimport { pairBwalletX, restorePairing, type PairingOptions } from './pair.js';\nimport type { PaySource } from './pay.js';\n\nexport type WalletKind = 'brc100' | 'pairing' | 'handcash' | 'custom';\n\nexport interface ConnectedWallet {\n /** The BRC-100 wallet. null for a non-BRC-100 adapter (HandCash today). */\n wallet: WalletInterface | null;\n /** What pay/tip use: the BRC-100 wallet, or the adapter's own payer. */\n payer: PaySource | null;\n /** The identity public key (hex) when the wallet has one. */\n identityKey: string | null;\n handle?: string;\n paymail?: string;\n /** Which option connected. */\n optionId: string;\n kind: WalletKind;\n /** True for adapters kept only until the vendor ships BRC-100. */\n transitional?: boolean;\n}\n\nexport interface WalletOption {\n id: string;\n name: string;\n icon?: string;\n kind: WalletKind;\n rdns?: string;\n /** True for bWalletX (extension, in-app or paired). */\n isBwalletX: boolean;\n connect(): Promise<ConnectedWallet>;\n}\n\nasync function brc100Connected(wallet: WalletInterface, o: Pick<WalletOption, 'id' | 'kind'>): Promise<ConnectedWallet> {\n await wallet.waitForAuthentication({}).catch(() => {});\n const { publicKey } = await wallet.getPublicKey({ identityKey: true });\n return { wallet, payer: wallet, identityKey: publicKey, optionId: o.id, kind: o.kind };\n}\n\n/** Wrap any BRC-100 wallet as a picker option. */\nexport function brc100Option(wallet: WalletInterface, info: { id: string; name: string; icon?: string; rdns?: string; isBwalletX?: boolean }): WalletOption {\n const opt: WalletOption = {\n id: info.id,\n name: info.name,\n icon: info.icon,\n rdns: info.rdns,\n kind: 'brc100',\n isBwalletX: info.isBwalletX ?? false,\n connect: () => brc100Connected(wallet, opt),\n };\n return opt;\n}\n\n/** Phone / web.bwalletx.com pairing as an option (shows a QR through `pairing`). Reuses a stored pairing first. */\nexport function pairingOption(pairing: PairingOptions | (() => PairingOptions)): WalletOption {\n const opt: WalletOption = {\n id: 'bwalletx-pairing',\n name: 'bWalletX on your phone',\n kind: 'pairing',\n isBwalletX: true,\n async connect() {\n const p = typeof pairing === 'function' ? pairing() : pairing;\n const w = (await restorePairing(p)) ?? (await pairBwalletX(p));\n return brc100Connected(w, opt);\n },\n };\n return opt;\n}\n\nexport interface HandCashAdapterOptions {\n /**\n * Your existing HandCash Connect login (redirect/popup + your server route). Resolve with the\n * profile once the user is signed in. This package does not import any HandCash SDK.\n */\n login(): Promise<{ handle: string; paymail?: string; identityKey?: string }>;\n /** Your existing HandCash pay call (usually a server route using the auth token). Optional. */\n pay?: Extract<PaySource, { pay: unknown }>['pay'];\n icon?: string;\n}\n\n/**\n * TRANSITIONAL. Keeps existing HandCash users working behind the same picker until HandCash's\n * BRC-100 support ships; then remove this and HandCash appears as an ordinary BRC-100 wallet.\n */\nexport function handcashAdapter(o: HandCashAdapterOptions): WalletOption {\n const opt: WalletOption = {\n id: 'handcash',\n name: 'HandCash',\n icon: o.icon,\n kind: 'handcash',\n isBwalletX: false,\n async connect() {\n const p = await o.login();\n return {\n wallet: null,\n payer: o.pay ? { pay: o.pay } : null,\n identityKey: p.identityKey ?? null,\n handle: p.handle,\n paymail: p.paymail ?? `${p.handle.replace(/^\\$/, '')}@handcash.io`,\n optionId: opt.id,\n kind: 'handcash',\n transitional: true,\n };\n },\n };\n return opt;\n}\n\nexport interface DiscoverWalletsOptions {\n /** 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).\n * Off by default: some browsers prompt for local-network access.\n */\n probeLocal?: boolean;\n /** Add the phone pairing option (needs a way to show the QR, e.g. pairingModal()). */\n pairing?: PairingOptions | (() => PairingOptions);\n /** App-supplied options appended at the end (e.g. handcashAdapter(...)). */\n extra?: WalletOption[];\n}\n\nconst NAMES: Record<string, string> = { [RDNS_EXTENSION]: 'bWalletX', 'space.bwallet.mobile': 'bWalletX' };\n\nasync function probe(substrate: 'json-api' | 'Cicada', ms: number): Promise<WalletInterface | null> {\n try {\n const w = new WalletClient(substrate);\n const ok = await Promise.race([w.isAuthenticated({}).then(() => true), new Promise<boolean>((r) => setTimeout(() => r(false), ms))]);\n return ok ? w : null;\n } catch {\n return null;\n }\n}\n\n/** All wallets we can see, bWalletX first. SSR-safe: resolves [] (plus `extra`) outside a browser. */\nexport async function discoverWallets(o: DiscoverWalletsOptions = {}): Promise<WalletOption[]> {\n const out: WalletOption[] = [];\n const ms = o.ms ?? 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 seen.set(rdns, brc100Option(d.wallet, { id: rdns, rdns, name: NAMES[rdns] ?? d.info?.name ?? rdns, icon: d.info?.icon, isBwalletX: isB }));\n };\n window.addEventListener('brc100:announceWallet', onAnnounce);\n window.dispatchEvent(new Event('brc100:requestWallet'));\n const local = o.probeLocal ? Promise.all([probe('json-api', ms), probe('Cicada', ms)]) : Promise.resolve([null, null]);\n // 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 const cwi = (window as unknown as { CWI?: WalletInterface }).CWI;\n if (cwi && ![...seen.values()].some((x) => x.rdns === 'space.bwallet.mobile')) {\n out.push(brc100Option(cwi, { id: 'window.CWI', name: 'This app’s wallet', isBwalletX: false }));\n }\n const [json, cicada] = await local;\n if (json) out.push(brc100Option(json, { id: 'localhost:3321', name: 'Desktop wallet (localhost:3321)' }));\n if (cicada) out.push(brc100Option(cicada, { id: 'localhost:3301', name: 'Desktop wallet (localhost:3301)' }));\n }\n if (o.pairing) out.push(pairingOption(o.pairing));\n out.push(...(o.extra ?? []));\n // bWalletX first, transitional last; otherwise keep discovery order.\n const rank = (w: WalletOption) => (w.isBwalletX ? 0 : w.kind === 'handcash' ? 2 : 1);\n return out.map((w, i) => ({ w, i })).sort((a, b) => rank(a.w) - rank(b.w) || a.i - b.i).map((x) => x.w);\n}\n","/**\n * Built-in UI: the pairing QR modal and the wallet picker. Plain DOM, no framework, only created\n * when called in a browser.\n */\nimport qrcode from 'qrcode-generator';\nimport type { PairingOptions } from './pair.js';\nimport type { WalletOption } from './wallets.js';\nimport { WEB_WALLET_URL } from './element.js';\n\nconst CSS = `\n.bwx-ov{position:fixed;inset:0;z-index:2147483000;background:rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center;padding:16px;font:15px/1.4 system-ui,-apple-system,Segoe UI,Roboto,sans-serif}\n.bwx-box{background:#0b0b0b;color:#f4f1e8;border:1px solid #3a3220;border-radius:16px;width:min(360px,100%);padding:20px;box-shadow:0 20px 60px rgba(0,0,0,.5)}\n.bwx-box h2{margin:0 0 6px;font-size:18px;color:#e8c766}\n.bwx-box p{margin:0 0 14px;color:#bdb6a3;font-size:14px}\n.bwx-qr{background:#fff;border-radius:12px;padding:12px;display:flex;justify-content:center}\n.bwx-qr svg{width:100%;height:auto;max-width:260px}\n.bwx-code{margin:14px 0 0;text-align:center;font-size:28px;letter-spacing:.3em;color:#e8c766;font-variant-numeric:tabular-nums}\n.bwx-row{display:flex;gap:8px;margin-top:14px}\n.bwx-btn{flex:1;border:1px solid #3a3220;background:#15130e;color:#f4f1e8;border-radius:10px;padding:10px 12px;font:inherit;cursor:pointer}\n.bwx-btn:hover{border-color:#e8c766}\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}\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\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\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","/**\n * Site theme for the wallet. A site may ask bWalletX to wear one of the themes the wallet already bundles\n * (e.g. 'npgx') while the site is connected and is the active tab; the wallet puts the user's own theme back on\n * any other site or when this declaration is removed. Only an id is declared: the wallet decides whether this\n * origin may wear it (brand editions are locked to their own sites) and never loads colours, CSS or URLs from here.\n */\nexport const WALLET_THEME_META = 'bwalletx-theme';\n\nconst ID = /^[a-z0-9-]{1,32}$/;\n\n/** Declare (or with null, withdraw) the theme the wallet should wear for this page. No-op outside a browser. */\nexport function declareWalletTheme(theme: string | null | undefined): void {\n if (typeof document === 'undefined') return;\n const id = (theme ?? '').trim().toLowerCase();\n let meta = document.head.querySelector<HTMLMetaElement>(`meta[name=\"${WALLET_THEME_META}\"]`);\n if (!id || !ID.test(id)) {\n meta?.remove();\n return;\n }\n if (!meta) {\n meta = document.createElement('meta');\n meta.name = WALLET_THEME_META;\n document.head.appendChild(meta);\n }\n if (meta.content !== id) meta.content = id;\n}\n"],"mappings":"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","names":["r","p"]}
|
package/dist/element.cjs
CHANGED
|
@@ -32,16 +32,20 @@ __export(define_exports, {
|
|
|
32
32
|
module.exports = __toCommonJS(define_exports);
|
|
33
33
|
|
|
34
34
|
// src/discover.ts
|
|
35
|
+
var import_sdk = require("@bsv/sdk");
|
|
35
36
|
var RDNS_EXTENSION = "com.bwalletx.extension";
|
|
36
37
|
var RDNS_MOBILE = "space.bwallet.mobile";
|
|
37
38
|
var BWALLETX_RDNS = [RDNS_EXTENSION, RDNS_MOBILE];
|
|
38
|
-
|
|
39
|
+
var DEFAULT_DISCOVER_MS = 300;
|
|
40
|
+
function discoverBwalletX(ms = DEFAULT_DISCOVER_MS) {
|
|
39
41
|
if (typeof window === "undefined") return Promise.resolve(null);
|
|
40
42
|
return new Promise((resolve) => {
|
|
41
43
|
let done = false;
|
|
44
|
+
let timer;
|
|
42
45
|
const finish = (r) => {
|
|
43
46
|
if (done) return;
|
|
44
47
|
done = true;
|
|
48
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
45
49
|
window.removeEventListener("brc100:announceWallet", onAnnounce);
|
|
46
50
|
resolve(r);
|
|
47
51
|
};
|
|
@@ -52,17 +56,94 @@ function discoverBwalletX(ms = 1200) {
|
|
|
52
56
|
finish({ wallet: d.wallet, method: rdns === RDNS_EXTENSION ? "extension" : "in-app", rdns });
|
|
53
57
|
}
|
|
54
58
|
};
|
|
59
|
+
const cwiNow = () => {
|
|
60
|
+
const cwi = window.CWI;
|
|
61
|
+
if (cwi) finish({ wallet: cwi, method: "in-app", rdns: null });
|
|
62
|
+
return !!cwi;
|
|
63
|
+
};
|
|
55
64
|
window.addEventListener("brc100:announceWallet", onAnnounce);
|
|
56
65
|
window.dispatchEvent(new Event("brc100:requestWallet"));
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
finish(
|
|
66
|
+
if (done || cwiNow()) return;
|
|
67
|
+
if (isFramed()) {
|
|
68
|
+
void probeXdm(Math.max(ms, 1200)).then((w) => finish(w ? { wallet: w, method: "in-app", rdns: null } : null));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
timer = setTimeout(() => {
|
|
72
|
+
timer = void 0;
|
|
73
|
+
if (!cwiNow()) finish(null);
|
|
60
74
|
}, ms);
|
|
61
75
|
});
|
|
62
76
|
}
|
|
77
|
+
var isFramed = () => {
|
|
78
|
+
try {
|
|
79
|
+
return window.parent !== window;
|
|
80
|
+
} catch {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var BWALLETX_PARENT_ORIGINS = [
|
|
85
|
+
"https://web.bwalletx.com",
|
|
86
|
+
"https://desktop.bwalletx.com",
|
|
87
|
+
"https://bwalletx.com",
|
|
88
|
+
"https://www.bwallet.space",
|
|
89
|
+
"https://bwallet.space",
|
|
90
|
+
"capacitor://localhost",
|
|
91
|
+
// iOS app shell
|
|
92
|
+
"https://localhost",
|
|
93
|
+
// Android app shell
|
|
94
|
+
"tauri://localhost",
|
|
95
|
+
// bWalletX Desktop (macOS)
|
|
96
|
+
"https://tauri.localhost",
|
|
97
|
+
// bWalletX Desktop (Windows)
|
|
98
|
+
"chrome-extension://bombmmcjghjdlbmcclnhjodgcelnehgl"
|
|
99
|
+
// bWalletX for Chrome (fixed id)
|
|
100
|
+
];
|
|
101
|
+
var parentOrigin = () => {
|
|
102
|
+
try {
|
|
103
|
+
const anc = window.location.ancestorOrigins;
|
|
104
|
+
if (anc && anc.length > 0) return anc[0] ?? null;
|
|
105
|
+
if (!document.referrer) return null;
|
|
106
|
+
const u = new URL(document.referrer);
|
|
107
|
+
return `${u.protocol}//${u.host}`;
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
async function probeXdm(ms = 1200, allowed = BWALLETX_PARENT_ORIGINS) {
|
|
113
|
+
const origin = parentOrigin();
|
|
114
|
+
if (!origin || !allowed.includes(origin)) return null;
|
|
115
|
+
try {
|
|
116
|
+
const w = new import_sdk.WalletClient(new import_sdk.XDM(origin));
|
|
117
|
+
const ok = await Promise.race([
|
|
118
|
+
w.isAuthenticated({}).then(
|
|
119
|
+
() => true,
|
|
120
|
+
() => false
|
|
121
|
+
),
|
|
122
|
+
new Promise((r) => setTimeout(() => r(false), ms))
|
|
123
|
+
]);
|
|
124
|
+
return ok ? w : null;
|
|
125
|
+
} catch {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
var warmedAt = 0;
|
|
130
|
+
function prewarmBwalletX() {
|
|
131
|
+
if (typeof window === "undefined" || Date.now() - warmedAt < 2e4) return;
|
|
132
|
+
warmedAt = Date.now();
|
|
133
|
+
void discoverBwalletX(0).then((f) => {
|
|
134
|
+
if (f && f.method === "extension") void f.wallet.isAuthenticated({}).catch(() => {
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
function bindPrewarm(el) {
|
|
139
|
+
const on = () => prewarmBwalletX();
|
|
140
|
+
const evs = ["pointerenter", "focus", "touchstart"];
|
|
141
|
+
for (const e of evs) el.addEventListener(e, on, { passive: true });
|
|
142
|
+
return () => evs.forEach((e) => el.removeEventListener(e, on));
|
|
143
|
+
}
|
|
63
144
|
|
|
64
145
|
// src/pair.ts
|
|
65
|
-
var
|
|
146
|
+
var import_sdk3 = require("@bsv/sdk");
|
|
66
147
|
|
|
67
148
|
// src/in-order.ts
|
|
68
149
|
function inOrder(handle, onError) {
|
|
@@ -74,7 +155,7 @@ function inOrder(handle, onError) {
|
|
|
74
155
|
}
|
|
75
156
|
|
|
76
157
|
// src/protocol.ts
|
|
77
|
-
var
|
|
158
|
+
var import_sdk2 = require("@bsv/sdk");
|
|
78
159
|
var PAIR_VERSION = "1";
|
|
79
160
|
var PAIR_INFO = "bwallet-pair-v1";
|
|
80
161
|
var PAIR_HOST = "www.bwallet.space";
|
|
@@ -100,14 +181,26 @@ function pairUrl(link) {
|
|
|
100
181
|
const q = new URLSearchParams({ v: link.v, r: link.r, c: link.c, k: link.k, o: link.o, e: String(link.e) });
|
|
101
182
|
return `https://${PAIR_HOST}/pair?${q}`;
|
|
102
183
|
}
|
|
103
|
-
var
|
|
184
|
+
var newClaim = () => b64url(crypto.getRandomValues(new Uint8Array(16)));
|
|
185
|
+
var WALLET_CLAIM_INFO = "bwallet-pair-wallet-claim-v1";
|
|
186
|
+
var hex = (b) => Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
187
|
+
async function walletClaimFor(channel, sitePub) {
|
|
188
|
+
const d = await crypto.subtle.digest("SHA-256", enc.encode(`${WALLET_CLAIM_INFO}|${channel}|${sitePub}`));
|
|
189
|
+
return b64url(new Uint8Array(d));
|
|
190
|
+
}
|
|
191
|
+
async function claimDigest(claim) {
|
|
192
|
+
return hex(new Uint8Array(await crypto.subtle.digest("SHA-256", enc.encode(claim))));
|
|
193
|
+
}
|
|
194
|
+
var relaySocketUrl = (relay, channel, role, expiry, claim, walletClaimHash) => {
|
|
104
195
|
const local = /^(localhost|127\.0\.0\.1)(:\d+)?$/.test(relay);
|
|
105
196
|
const q = new URLSearchParams({ role });
|
|
106
197
|
if (expiry) q.set("e", String(expiry));
|
|
198
|
+
if (claim) q.set("claim", claim);
|
|
199
|
+
if (walletClaimHash && role === "site") q.set("wc", walletClaimHash);
|
|
107
200
|
return `${local ? "ws" : "wss"}://${relay}/v1/c/${channel}?${q}`;
|
|
108
201
|
};
|
|
109
202
|
async function deriveSession(mine, theirs, channel) {
|
|
110
|
-
const point = mine.deriveSharedSecret(
|
|
203
|
+
const point = mine.deriveSharedSecret(import_sdk2.PublicKey.fromString(theirs));
|
|
111
204
|
const ikm = new Uint8Array(point.encode(true));
|
|
112
205
|
const base = await crypto.subtle.importKey("raw", ikm, "HKDF", false, ["deriveBits"]);
|
|
113
206
|
const bits = new Uint8Array(
|
|
@@ -201,6 +294,7 @@ function parseStored(raw) {
|
|
|
201
294
|
if (typeof p.s !== "string" || !/^[0-9a-f]{64}$/i.test(p.s)) return null;
|
|
202
295
|
if (typeof p.k !== "string" || !/^0[23][0-9a-f]{64}$/i.test(p.k)) return null;
|
|
203
296
|
if (!n(p.sent) || !n(p.lastSeen) || !n(p.pairedAt)) return null;
|
|
297
|
+
if (p.sc !== void 0 && (typeof p.sc !== "string" || !/^[A-Za-z0-9_-]{22,64}$/.test(p.sc))) return null;
|
|
204
298
|
return p;
|
|
205
299
|
} catch {
|
|
206
300
|
return null;
|
|
@@ -258,7 +352,12 @@ var Link = class {
|
|
|
258
352
|
await this.opening;
|
|
259
353
|
}
|
|
260
354
|
reopen() {
|
|
261
|
-
|
|
355
|
+
if (!this.p.sc) {
|
|
356
|
+
this.p = { ...this.p, sc: newClaim() };
|
|
357
|
+
this.persist();
|
|
358
|
+
}
|
|
359
|
+
const e = Math.floor(Date.now() / 1e3) + QR_LIFETIME_S - 10;
|
|
360
|
+
const ws = this.socket(relaySocketUrl(this.p.r, this.p.c, "site", e, this.p.sc));
|
|
262
361
|
return new Promise((resolve, reject) => {
|
|
263
362
|
ws.onopen = () => {
|
|
264
363
|
this.ws = ws;
|
|
@@ -349,14 +448,16 @@ function pairBwalletX(opts) {
|
|
|
349
448
|
const relay = opts.relay ?? DEFAULT_RELAY;
|
|
350
449
|
const origin = opts.origin ?? (typeof location !== "undefined" ? location.origin : "");
|
|
351
450
|
if (!origin) return Promise.reject(new Error("pairBwalletX needs options.origin outside a browser"));
|
|
352
|
-
const siteKey =
|
|
451
|
+
const siteKey = import_sdk3.PrivateKey.fromRandom();
|
|
353
452
|
const channel = newChannel();
|
|
354
453
|
const expiry = Math.floor(Date.now() / 1e3) + QR_LIFETIME_S;
|
|
355
|
-
|
|
454
|
+
const siteClaim = newClaim();
|
|
455
|
+
const sitePub = siteKey.toPublicKey().toString();
|
|
456
|
+
return walletClaimFor(channel, sitePub).then(claimDigest).then((wc) => new Promise((resolve, reject) => {
|
|
356
457
|
if (opts.signal?.aborted) return reject(new Error("cancelled"));
|
|
357
458
|
let ws;
|
|
358
459
|
try {
|
|
359
|
-
ws = socket(relaySocketUrl(relay, channel, "site", expiry));
|
|
460
|
+
ws = socket(relaySocketUrl(relay, channel, "site", expiry, siteClaim, wc));
|
|
360
461
|
} catch (e) {
|
|
361
462
|
return reject(e);
|
|
362
463
|
}
|
|
@@ -395,7 +496,7 @@ function pairBwalletX(opts) {
|
|
|
395
496
|
if (msg.t === "ready") {
|
|
396
497
|
settled = true;
|
|
397
498
|
clearTimeout(timer);
|
|
398
|
-
const p = { v: 1, c: channel, r: relay, s: siteKey.toHex(), k: walletKey, ...sealer.counters, pairedAt: Date.now() };
|
|
499
|
+
const p = { v: 1, c: channel, r: relay, s: siteKey.toHex(), k: walletKey, ...sealer.counters, pairedAt: Date.now(), sc: siteClaim };
|
|
399
500
|
await Promise.resolve(storage.setItem(key, JSON.stringify(p))).catch(() => {
|
|
400
501
|
});
|
|
401
502
|
const link = new Link(p, sealer, storage, key, socket, opts.callTimeoutMs ?? 12e4);
|
|
@@ -405,15 +506,15 @@ function pairBwalletX(opts) {
|
|
|
405
506
|
fail(new Error("Pairing was declined in bWalletX"));
|
|
406
507
|
}
|
|
407
508
|
});
|
|
408
|
-
opts.onLink(pairUrl({ v: PAIR_VERSION, r: relay, c: channel, k:
|
|
409
|
-
});
|
|
509
|
+
opts.onLink(pairUrl({ v: PAIR_VERSION, r: relay, c: channel, k: sitePub, o: origin, e: expiry }));
|
|
510
|
+
}));
|
|
410
511
|
}
|
|
411
512
|
async function restorePairing(opts = {}) {
|
|
412
513
|
const storage = opts.storage === void 0 ? defaultStorage() : opts.storage ?? memoryStorage();
|
|
413
514
|
const key = opts.storageKey ?? DEFAULT_KEY;
|
|
414
515
|
const p = parseStored(await Promise.resolve(storage.getItem(key)).catch(() => null));
|
|
415
516
|
if (!p) return null;
|
|
416
|
-
const { key: aes } = await deriveSession(
|
|
517
|
+
const { key: aes } = await deriveSession(import_sdk3.PrivateKey.fromHex(p.s), p.k, p.c);
|
|
417
518
|
const sealer = new Sealer(aes, "site");
|
|
418
519
|
sealer.restore({ sent: p.sent, lastSeen: p.lastSeen });
|
|
419
520
|
return new Link(p, sealer, storage, key, opts.socket ?? defaultSocket(), opts.callTimeoutMs ?? 12e4).wallet();
|
|
@@ -422,35 +523,68 @@ async function restorePairing(opts = {}) {
|
|
|
422
523
|
// src/signin.ts
|
|
423
524
|
var LOGIN_PROTOCOL = [2, "bwallet sign in"];
|
|
424
525
|
async function connectBwalletX(opts = {}) {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
526
|
+
const status = (s) => {
|
|
527
|
+
try {
|
|
528
|
+
opts.onStatus?.(s);
|
|
529
|
+
} catch {
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
if (opts.wallet) {
|
|
533
|
+
status("opening");
|
|
534
|
+
return { wallet: opts.wallet, method: "wallet" };
|
|
535
|
+
}
|
|
536
|
+
status("finding");
|
|
537
|
+
const found = await discoverBwalletX(opts.discoverMs ?? DEFAULT_DISCOVER_MS);
|
|
538
|
+
if (found) {
|
|
539
|
+
status("opening");
|
|
540
|
+
return { wallet: found.wallet, method: found.method };
|
|
541
|
+
}
|
|
428
542
|
if (opts.reusePairing !== false) {
|
|
429
543
|
const restored = await restorePairing(opts.pairing ?? {});
|
|
430
|
-
if (restored)
|
|
544
|
+
if (restored) {
|
|
545
|
+
status("opening");
|
|
546
|
+
return { wallet: restored, method: "pairing" };
|
|
547
|
+
}
|
|
431
548
|
}
|
|
432
549
|
if (!opts.pairing) {
|
|
433
550
|
throw Object.assign(new Error("bWalletX was not found in this browser"), { code: "NOT_FOUND" });
|
|
434
551
|
}
|
|
552
|
+
status("pairing");
|
|
435
553
|
return { wallet: await pairBwalletX(opts.pairing), method: "pairing" };
|
|
436
554
|
}
|
|
437
555
|
async function signInWithBwalletX(opts) {
|
|
438
556
|
const { wallet, method } = await connectBwalletX(opts);
|
|
439
557
|
if (method !== "pairing") await wallet.waitForAuthentication({}).catch(() => {
|
|
440
558
|
});
|
|
441
|
-
const { publicKey: identityKey } = await wallet.getPublicKey({ identityKey: true });
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
559
|
+
const { publicKey: identityKey } = await atStage("identity", () => wallet.getPublicKey({ identityKey: true }));
|
|
560
|
+
try {
|
|
561
|
+
opts.onStatus?.("signing");
|
|
562
|
+
} catch {
|
|
563
|
+
}
|
|
564
|
+
const c = await atStage("challenge", () => opts.challenge(identityKey));
|
|
565
|
+
const { signature } = await atStage(
|
|
566
|
+
"signature",
|
|
567
|
+
() => wallet.createSignature({
|
|
568
|
+
protocolID: c.protocolID ?? LOGIN_PROTOCOL,
|
|
569
|
+
keyID: c.keyID,
|
|
570
|
+
counterparty: "anyone",
|
|
571
|
+
data: Array.from(new TextEncoder().encode(c.message))
|
|
572
|
+
})
|
|
573
|
+
);
|
|
449
574
|
return { identityKey, signature: Array.from(signature), nonce: c.nonce, method, wallet };
|
|
450
575
|
}
|
|
576
|
+
async function atStage(stage, run) {
|
|
577
|
+
try {
|
|
578
|
+
return await run();
|
|
579
|
+
} catch (e) {
|
|
580
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
581
|
+
if (!err.stage) Object.assign(err, { stage });
|
|
582
|
+
throw err;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
451
585
|
|
|
452
586
|
// src/access-client.ts
|
|
453
|
-
var
|
|
587
|
+
var import_sdk4 = require("@bsv/sdk");
|
|
454
588
|
|
|
455
589
|
// src/access.ts
|
|
456
590
|
var ACCESS_PROTOCOL = [2, "bwalletx access"];
|
|
@@ -588,7 +722,7 @@ async function proveHoldings(wallet, challenge, tokenId, basket = "bsv21") {
|
|
|
588
722
|
const counterparty = ci.counterparty ?? "self";
|
|
589
723
|
for (const protocolID of ci.protocolID ? [ci.protocolID] : [ONESAT, LEGACY_ONESAT]) {
|
|
590
724
|
const { publicKey } = await wallet.getPublicKey({ protocolID, keyID: ci.keyID, counterparty });
|
|
591
|
-
const h =
|
|
725
|
+
const h = import_sdk4.Utils.toHex(import_sdk4.Hash.hash160(import_sdk4.PublicKey.fromString(publicKey).encode(true)));
|
|
592
726
|
if (want && h !== want) continue;
|
|
593
727
|
const existing = byKey.get(publicKey);
|
|
594
728
|
if (existing) {
|
|
@@ -784,6 +918,7 @@ function createClass() {
|
|
|
784
918
|
const nf = this.#notFound ? `<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>` : "";
|
|
785
919
|
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\u2026</span>' : ""}${nf}`;
|
|
786
920
|
this.button.addEventListener("click", () => void this.#click());
|
|
921
|
+
bindPrewarm(this.button);
|
|
787
922
|
}
|
|
788
923
|
#emit(type, detail, cancelable = false) {
|
|
789
924
|
return this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable }));
|
|
@@ -810,7 +945,7 @@ function createClass() {
|
|
|
810
945
|
this.#notFound = false;
|
|
811
946
|
this.#setBusy(true);
|
|
812
947
|
try {
|
|
813
|
-
const ms = Number(this.#attr("discover-ms")) ||
|
|
948
|
+
const ms = Number(this.#attr("discover-ms")) || DEFAULT_DISCOVER_MS;
|
|
814
949
|
const found = await discoverBwalletX(ms);
|
|
815
950
|
if (!found) {
|
|
816
951
|
this.#notFound = true;
|