@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
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,7 @@ __export(src_exports, {
|
|
|
36
36
|
AccessError: () => AccessError,
|
|
37
37
|
BRC29_PROTOCOL: () => BRC29_PROTOCOL,
|
|
38
38
|
BWALLETX_RDNS: () => BWALLETX_RDNS,
|
|
39
|
+
DEFAULT_DISCOVER_MS: () => DEFAULT_DISCOVER_MS,
|
|
39
40
|
GET_URL: () => GET_URL,
|
|
40
41
|
LOGIN_PROTOCOL: () => LOGIN_PROTOCOL,
|
|
41
42
|
LOGO_URL: () => LOGO_URL,
|
|
@@ -45,15 +46,18 @@ __export(src_exports, {
|
|
|
45
46
|
RDNS_MOBILE: () => RDNS_MOBILE,
|
|
46
47
|
SIGNIN_CSS: () => SIGNIN_CSS,
|
|
47
48
|
SIGNIN_TAG: () => SIGNIN_TAG,
|
|
49
|
+
WALLET_THEME_META: () => WALLET_THEME_META,
|
|
48
50
|
WEB_WALLET_URL: () => WEB_WALLET_URL,
|
|
49
51
|
accessErrorMessage: () => accessErrorMessage,
|
|
50
52
|
amountInSats: () => amountInSats,
|
|
53
|
+
bindPrewarm: () => bindPrewarm,
|
|
51
54
|
brc100Option: () => brc100Option,
|
|
52
55
|
buildAuthorizeUrl: () => buildAuthorizeUrl,
|
|
53
56
|
buyToken: () => buyToken,
|
|
54
57
|
canonicalJson: () => canonicalJson,
|
|
55
58
|
clearPairing: () => clearPairing,
|
|
56
59
|
connectBwalletX: () => connectBwalletX,
|
|
60
|
+
declareWalletTheme: () => declareWalletTheme,
|
|
57
61
|
defineBwalletxSignin: () => defineBwalletxSignin,
|
|
58
62
|
discoverBwalletX: () => discoverBwalletX,
|
|
59
63
|
discoverWallets: () => discoverWallets,
|
|
@@ -62,12 +66,14 @@ __export(src_exports, {
|
|
|
62
66
|
inOrder: () => inOrder,
|
|
63
67
|
isIdentityKeyHex: () => isIdentityKeyHex,
|
|
64
68
|
isPaymail: () => isPaymail,
|
|
69
|
+
isTouchDevice: () => isTouchDevice,
|
|
65
70
|
markSvg: () => markSvg,
|
|
66
71
|
pairBwalletX: () => pairBwalletX,
|
|
67
72
|
pairingModal: () => pairingModal,
|
|
68
73
|
pairingOption: () => pairingOption,
|
|
69
74
|
pay: () => pay,
|
|
70
75
|
pickWallet: () => pickWallet,
|
|
76
|
+
prewarmBwalletX: () => prewarmBwalletX,
|
|
71
77
|
protocolMediaUrl: () => protocolMediaUrl,
|
|
72
78
|
proveHoldings: () => proveHoldings,
|
|
73
79
|
qrSvg: () => qrSvg,
|
|
@@ -84,16 +90,20 @@ __export(src_exports, {
|
|
|
84
90
|
module.exports = __toCommonJS(src_exports);
|
|
85
91
|
|
|
86
92
|
// src/discover.ts
|
|
93
|
+
var import_sdk = require("@bsv/sdk");
|
|
87
94
|
var RDNS_EXTENSION = "com.bwalletx.extension";
|
|
88
95
|
var RDNS_MOBILE = "space.bwallet.mobile";
|
|
89
96
|
var BWALLETX_RDNS = [RDNS_EXTENSION, RDNS_MOBILE];
|
|
90
|
-
|
|
97
|
+
var DEFAULT_DISCOVER_MS = 300;
|
|
98
|
+
function discoverBwalletX(ms = DEFAULT_DISCOVER_MS) {
|
|
91
99
|
if (typeof window === "undefined") return Promise.resolve(null);
|
|
92
100
|
return new Promise((resolve) => {
|
|
93
101
|
let done = false;
|
|
102
|
+
let timer;
|
|
94
103
|
const finish = (r) => {
|
|
95
104
|
if (done) return;
|
|
96
105
|
done = true;
|
|
106
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
97
107
|
window.removeEventListener("brc100:announceWallet", onAnnounce);
|
|
98
108
|
resolve(r);
|
|
99
109
|
};
|
|
@@ -104,20 +114,97 @@ function discoverBwalletX(ms = 1200) {
|
|
|
104
114
|
finish({ wallet: d.wallet, method: rdns === RDNS_EXTENSION ? "extension" : "in-app", rdns });
|
|
105
115
|
}
|
|
106
116
|
};
|
|
117
|
+
const cwiNow = () => {
|
|
118
|
+
const cwi = window.CWI;
|
|
119
|
+
if (cwi) finish({ wallet: cwi, method: "in-app", rdns: null });
|
|
120
|
+
return !!cwi;
|
|
121
|
+
};
|
|
107
122
|
window.addEventListener("brc100:announceWallet", onAnnounce);
|
|
108
123
|
window.dispatchEvent(new Event("brc100:requestWallet"));
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
finish(
|
|
124
|
+
if (done || cwiNow()) return;
|
|
125
|
+
if (isFramed()) {
|
|
126
|
+
void probeXdm(Math.max(ms, 1200)).then((w) => finish(w ? { wallet: w, method: "in-app", rdns: null } : null));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
timer = setTimeout(() => {
|
|
130
|
+
timer = void 0;
|
|
131
|
+
if (!cwiNow()) finish(null);
|
|
112
132
|
}, ms);
|
|
113
133
|
});
|
|
114
134
|
}
|
|
115
|
-
async function findBwalletX(ms =
|
|
135
|
+
async function findBwalletX(ms = DEFAULT_DISCOVER_MS) {
|
|
116
136
|
return (await discoverBwalletX(ms))?.wallet ?? null;
|
|
117
137
|
}
|
|
138
|
+
var isFramed = () => {
|
|
139
|
+
try {
|
|
140
|
+
return window.parent !== window;
|
|
141
|
+
} catch {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
var BWALLETX_PARENT_ORIGINS = [
|
|
146
|
+
"https://web.bwalletx.com",
|
|
147
|
+
"https://desktop.bwalletx.com",
|
|
148
|
+
"https://bwalletx.com",
|
|
149
|
+
"https://www.bwallet.space",
|
|
150
|
+
"https://bwallet.space",
|
|
151
|
+
"capacitor://localhost",
|
|
152
|
+
// iOS app shell
|
|
153
|
+
"https://localhost",
|
|
154
|
+
// Android app shell
|
|
155
|
+
"tauri://localhost",
|
|
156
|
+
// bWalletX Desktop (macOS)
|
|
157
|
+
"https://tauri.localhost",
|
|
158
|
+
// bWalletX Desktop (Windows)
|
|
159
|
+
"chrome-extension://bombmmcjghjdlbmcclnhjodgcelnehgl"
|
|
160
|
+
// bWalletX for Chrome (fixed id)
|
|
161
|
+
];
|
|
162
|
+
var parentOrigin = () => {
|
|
163
|
+
try {
|
|
164
|
+
const anc = window.location.ancestorOrigins;
|
|
165
|
+
if (anc && anc.length > 0) return anc[0] ?? null;
|
|
166
|
+
if (!document.referrer) return null;
|
|
167
|
+
const u = new URL(document.referrer);
|
|
168
|
+
return `${u.protocol}//${u.host}`;
|
|
169
|
+
} catch {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
async function probeXdm(ms = 1200, allowed = BWALLETX_PARENT_ORIGINS) {
|
|
174
|
+
const origin = parentOrigin();
|
|
175
|
+
if (!origin || !allowed.includes(origin)) return null;
|
|
176
|
+
try {
|
|
177
|
+
const w = new import_sdk.WalletClient(new import_sdk.XDM(origin));
|
|
178
|
+
const ok = await Promise.race([
|
|
179
|
+
w.isAuthenticated({}).then(
|
|
180
|
+
() => true,
|
|
181
|
+
() => false
|
|
182
|
+
),
|
|
183
|
+
new Promise((r) => setTimeout(() => r(false), ms))
|
|
184
|
+
]);
|
|
185
|
+
return ok ? w : null;
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
var warmedAt = 0;
|
|
191
|
+
function prewarmBwalletX() {
|
|
192
|
+
if (typeof window === "undefined" || Date.now() - warmedAt < 2e4) return;
|
|
193
|
+
warmedAt = Date.now();
|
|
194
|
+
void discoverBwalletX(0).then((f) => {
|
|
195
|
+
if (f && f.method === "extension") void f.wallet.isAuthenticated({}).catch(() => {
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function bindPrewarm(el2) {
|
|
200
|
+
const on = () => prewarmBwalletX();
|
|
201
|
+
const evs = ["pointerenter", "focus", "touchstart"];
|
|
202
|
+
for (const e of evs) el2.addEventListener(e, on, { passive: true });
|
|
203
|
+
return () => evs.forEach((e) => el2.removeEventListener(e, on));
|
|
204
|
+
}
|
|
118
205
|
|
|
119
206
|
// src/pair.ts
|
|
120
|
-
var
|
|
207
|
+
var import_sdk3 = require("@bsv/sdk");
|
|
121
208
|
|
|
122
209
|
// src/in-order.ts
|
|
123
210
|
function inOrder(handle, onError) {
|
|
@@ -129,7 +216,7 @@ function inOrder(handle, onError) {
|
|
|
129
216
|
}
|
|
130
217
|
|
|
131
218
|
// src/protocol.ts
|
|
132
|
-
var
|
|
219
|
+
var import_sdk2 = require("@bsv/sdk");
|
|
133
220
|
var PAIR_VERSION = "1";
|
|
134
221
|
var PAIR_INFO = "bwallet-pair-v1";
|
|
135
222
|
var PAIR_HOST = "www.bwallet.space";
|
|
@@ -155,14 +242,26 @@ function pairUrl(link) {
|
|
|
155
242
|
const q = new URLSearchParams({ v: link.v, r: link.r, c: link.c, k: link.k, o: link.o, e: String(link.e) });
|
|
156
243
|
return `https://${PAIR_HOST}/pair?${q}`;
|
|
157
244
|
}
|
|
158
|
-
var
|
|
245
|
+
var newClaim = () => b64url(crypto.getRandomValues(new Uint8Array(16)));
|
|
246
|
+
var WALLET_CLAIM_INFO = "bwallet-pair-wallet-claim-v1";
|
|
247
|
+
var hex = (b) => Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
248
|
+
async function walletClaimFor(channel, sitePub) {
|
|
249
|
+
const d = await crypto.subtle.digest("SHA-256", enc.encode(`${WALLET_CLAIM_INFO}|${channel}|${sitePub}`));
|
|
250
|
+
return b64url(new Uint8Array(d));
|
|
251
|
+
}
|
|
252
|
+
async function claimDigest(claim) {
|
|
253
|
+
return hex(new Uint8Array(await crypto.subtle.digest("SHA-256", enc.encode(claim))));
|
|
254
|
+
}
|
|
255
|
+
var relaySocketUrl = (relay, channel, role, expiry, claim, walletClaimHash) => {
|
|
159
256
|
const local = /^(localhost|127\.0\.0\.1)(:\d+)?$/.test(relay);
|
|
160
257
|
const q = new URLSearchParams({ role });
|
|
161
258
|
if (expiry) q.set("e", String(expiry));
|
|
259
|
+
if (claim) q.set("claim", claim);
|
|
260
|
+
if (walletClaimHash && role === "site") q.set("wc", walletClaimHash);
|
|
162
261
|
return `${local ? "ws" : "wss"}://${relay}/v1/c/${channel}?${q}`;
|
|
163
262
|
};
|
|
164
263
|
async function deriveSession(mine, theirs, channel) {
|
|
165
|
-
const point = mine.deriveSharedSecret(
|
|
264
|
+
const point = mine.deriveSharedSecret(import_sdk2.PublicKey.fromString(theirs));
|
|
166
265
|
const ikm = new Uint8Array(point.encode(true));
|
|
167
266
|
const base = await crypto.subtle.importKey("raw", ikm, "HKDF", false, ["deriveBits"]);
|
|
168
267
|
const bits = new Uint8Array(
|
|
@@ -256,6 +355,7 @@ function parseStored(raw) {
|
|
|
256
355
|
if (typeof p.s !== "string" || !/^[0-9a-f]{64}$/i.test(p.s)) return null;
|
|
257
356
|
if (typeof p.k !== "string" || !/^0[23][0-9a-f]{64}$/i.test(p.k)) return null;
|
|
258
357
|
if (!n(p.sent) || !n(p.lastSeen) || !n(p.pairedAt)) return null;
|
|
358
|
+
if (p.sc !== void 0 && (typeof p.sc !== "string" || !/^[A-Za-z0-9_-]{22,64}$/.test(p.sc))) return null;
|
|
259
359
|
return p;
|
|
260
360
|
} catch {
|
|
261
361
|
return null;
|
|
@@ -313,7 +413,12 @@ var Link = class {
|
|
|
313
413
|
await this.opening;
|
|
314
414
|
}
|
|
315
415
|
reopen() {
|
|
316
|
-
|
|
416
|
+
if (!this.p.sc) {
|
|
417
|
+
this.p = { ...this.p, sc: newClaim() };
|
|
418
|
+
this.persist();
|
|
419
|
+
}
|
|
420
|
+
const e = Math.floor(Date.now() / 1e3) + QR_LIFETIME_S - 10;
|
|
421
|
+
const ws = this.socket(relaySocketUrl(this.p.r, this.p.c, "site", e, this.p.sc));
|
|
317
422
|
return new Promise((resolve, reject) => {
|
|
318
423
|
ws.onopen = () => {
|
|
319
424
|
this.ws = ws;
|
|
@@ -404,14 +509,16 @@ function pairBwalletX(opts) {
|
|
|
404
509
|
const relay = opts.relay ?? DEFAULT_RELAY;
|
|
405
510
|
const origin = opts.origin ?? (typeof location !== "undefined" ? location.origin : "");
|
|
406
511
|
if (!origin) return Promise.reject(new Error("pairBwalletX needs options.origin outside a browser"));
|
|
407
|
-
const siteKey =
|
|
512
|
+
const siteKey = import_sdk3.PrivateKey.fromRandom();
|
|
408
513
|
const channel = newChannel();
|
|
409
514
|
const expiry = Math.floor(Date.now() / 1e3) + QR_LIFETIME_S;
|
|
410
|
-
|
|
515
|
+
const siteClaim = newClaim();
|
|
516
|
+
const sitePub = siteKey.toPublicKey().toString();
|
|
517
|
+
return walletClaimFor(channel, sitePub).then(claimDigest).then((wc) => new Promise((resolve, reject) => {
|
|
411
518
|
if (opts.signal?.aborted) return reject(new Error("cancelled"));
|
|
412
519
|
let ws;
|
|
413
520
|
try {
|
|
414
|
-
ws = socket(relaySocketUrl(relay, channel, "site", expiry));
|
|
521
|
+
ws = socket(relaySocketUrl(relay, channel, "site", expiry, siteClaim, wc));
|
|
415
522
|
} catch (e) {
|
|
416
523
|
return reject(e);
|
|
417
524
|
}
|
|
@@ -450,7 +557,7 @@ function pairBwalletX(opts) {
|
|
|
450
557
|
if (msg.t === "ready") {
|
|
451
558
|
settled = true;
|
|
452
559
|
clearTimeout(timer);
|
|
453
|
-
const p = { v: 1, c: channel, r: relay, s: siteKey.toHex(), k: walletKey, ...sealer.counters, pairedAt: Date.now() };
|
|
560
|
+
const p = { v: 1, c: channel, r: relay, s: siteKey.toHex(), k: walletKey, ...sealer.counters, pairedAt: Date.now(), sc: siteClaim };
|
|
454
561
|
await Promise.resolve(storage.setItem(key, JSON.stringify(p))).catch(() => {
|
|
455
562
|
});
|
|
456
563
|
const link = new Link(p, sealer, storage, key, socket, opts.callTimeoutMs ?? 12e4);
|
|
@@ -460,15 +567,15 @@ function pairBwalletX(opts) {
|
|
|
460
567
|
fail(new Error("Pairing was declined in bWalletX"));
|
|
461
568
|
}
|
|
462
569
|
});
|
|
463
|
-
opts.onLink(pairUrl({ v: PAIR_VERSION, r: relay, c: channel, k:
|
|
464
|
-
});
|
|
570
|
+
opts.onLink(pairUrl({ v: PAIR_VERSION, r: relay, c: channel, k: sitePub, o: origin, e: expiry }));
|
|
571
|
+
}));
|
|
465
572
|
}
|
|
466
573
|
async function restorePairing(opts = {}) {
|
|
467
574
|
const storage = opts.storage === void 0 ? defaultStorage() : opts.storage ?? memoryStorage();
|
|
468
575
|
const key = opts.storageKey ?? DEFAULT_KEY;
|
|
469
576
|
const p = parseStored(await Promise.resolve(storage.getItem(key)).catch(() => null));
|
|
470
577
|
if (!p) return null;
|
|
471
|
-
const { key: aes } = await deriveSession(
|
|
578
|
+
const { key: aes } = await deriveSession(import_sdk3.PrivateKey.fromHex(p.s), p.k, p.c);
|
|
472
579
|
const sealer = new Sealer(aes, "site");
|
|
473
580
|
sealer.restore({ sent: p.sent, lastSeen: p.lastSeen });
|
|
474
581
|
return new Link(p, sealer, storage, key, opts.socket ?? defaultSocket(), opts.callTimeoutMs ?? 12e4).wallet();
|
|
@@ -482,32 +589,65 @@ async function clearPairing(opts = {}) {
|
|
|
482
589
|
// src/signin.ts
|
|
483
590
|
var LOGIN_PROTOCOL = [2, "bwallet sign in"];
|
|
484
591
|
async function connectBwalletX(opts = {}) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
592
|
+
const status = (s) => {
|
|
593
|
+
try {
|
|
594
|
+
opts.onStatus?.(s);
|
|
595
|
+
} catch {
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
if (opts.wallet) {
|
|
599
|
+
status("opening");
|
|
600
|
+
return { wallet: opts.wallet, method: "wallet" };
|
|
601
|
+
}
|
|
602
|
+
status("finding");
|
|
603
|
+
const found = await discoverBwalletX(opts.discoverMs ?? DEFAULT_DISCOVER_MS);
|
|
604
|
+
if (found) {
|
|
605
|
+
status("opening");
|
|
606
|
+
return { wallet: found.wallet, method: found.method };
|
|
607
|
+
}
|
|
488
608
|
if (opts.reusePairing !== false) {
|
|
489
609
|
const restored = await restorePairing(opts.pairing ?? {});
|
|
490
|
-
if (restored)
|
|
610
|
+
if (restored) {
|
|
611
|
+
status("opening");
|
|
612
|
+
return { wallet: restored, method: "pairing" };
|
|
613
|
+
}
|
|
491
614
|
}
|
|
492
615
|
if (!opts.pairing) {
|
|
493
616
|
throw Object.assign(new Error("bWalletX was not found in this browser"), { code: "NOT_FOUND" });
|
|
494
617
|
}
|
|
618
|
+
status("pairing");
|
|
495
619
|
return { wallet: await pairBwalletX(opts.pairing), method: "pairing" };
|
|
496
620
|
}
|
|
497
621
|
async function signInWithBwalletX(opts) {
|
|
498
622
|
const { wallet, method } = await connectBwalletX(opts);
|
|
499
623
|
if (method !== "pairing") await wallet.waitForAuthentication({}).catch(() => {
|
|
500
624
|
});
|
|
501
|
-
const { publicKey: identityKey } = await wallet.getPublicKey({ identityKey: true });
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
625
|
+
const { publicKey: identityKey } = await atStage("identity", () => wallet.getPublicKey({ identityKey: true }));
|
|
626
|
+
try {
|
|
627
|
+
opts.onStatus?.("signing");
|
|
628
|
+
} catch {
|
|
629
|
+
}
|
|
630
|
+
const c = await atStage("challenge", () => opts.challenge(identityKey));
|
|
631
|
+
const { signature } = await atStage(
|
|
632
|
+
"signature",
|
|
633
|
+
() => wallet.createSignature({
|
|
634
|
+
protocolID: c.protocolID ?? LOGIN_PROTOCOL,
|
|
635
|
+
keyID: c.keyID,
|
|
636
|
+
counterparty: "anyone",
|
|
637
|
+
data: Array.from(new TextEncoder().encode(c.message))
|
|
638
|
+
})
|
|
639
|
+
);
|
|
509
640
|
return { identityKey, signature: Array.from(signature), nonce: c.nonce, method, wallet };
|
|
510
641
|
}
|
|
642
|
+
async function atStage(stage, run) {
|
|
643
|
+
try {
|
|
644
|
+
return await run();
|
|
645
|
+
} catch (e) {
|
|
646
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
647
|
+
if (!err.stage) Object.assign(err, { stage });
|
|
648
|
+
throw err;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
511
651
|
|
|
512
652
|
// src/button.ts
|
|
513
653
|
var CSS = `
|
|
@@ -554,7 +694,7 @@ function renderButton(el2, opts = {}) {
|
|
|
554
694
|
}
|
|
555
695
|
|
|
556
696
|
// src/access-client.ts
|
|
557
|
-
var
|
|
697
|
+
var import_sdk4 = require("@bsv/sdk");
|
|
558
698
|
|
|
559
699
|
// src/access.ts
|
|
560
700
|
var ACCESS_VERSION = 1;
|
|
@@ -740,7 +880,7 @@ async function proveHoldings(wallet, challenge, tokenId, basket = "bsv21") {
|
|
|
740
880
|
const counterparty = ci.counterparty ?? "self";
|
|
741
881
|
for (const protocolID of ci.protocolID ? [ci.protocolID] : [ONESAT, LEGACY_ONESAT]) {
|
|
742
882
|
const { publicKey } = await wallet.getPublicKey({ protocolID, keyID: ci.keyID, counterparty });
|
|
743
|
-
const h =
|
|
883
|
+
const h = import_sdk4.Utils.toHex(import_sdk4.Hash.hash160(import_sdk4.PublicKey.fromString(publicKey).encode(true)));
|
|
744
884
|
if (want && h !== want) continue;
|
|
745
885
|
const existing = byKey.get(publicKey);
|
|
746
886
|
if (existing) {
|
|
@@ -936,6 +1076,7 @@ function createClass() {
|
|
|
936
1076
|
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>` : "";
|
|
937
1077
|
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}`;
|
|
938
1078
|
this.button.addEventListener("click", () => void this.#click());
|
|
1079
|
+
bindPrewarm(this.button);
|
|
939
1080
|
}
|
|
940
1081
|
#emit(type, detail, cancelable = false) {
|
|
941
1082
|
return this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true, cancelable }));
|
|
@@ -962,7 +1103,7 @@ function createClass() {
|
|
|
962
1103
|
this.#notFound = false;
|
|
963
1104
|
this.#setBusy(true);
|
|
964
1105
|
try {
|
|
965
|
-
const ms = Number(this.#attr("discover-ms")) ||
|
|
1106
|
+
const ms = Number(this.#attr("discover-ms")) || DEFAULT_DISCOVER_MS;
|
|
966
1107
|
const found = await discoverBwalletX(ms);
|
|
967
1108
|
if (!found) {
|
|
968
1109
|
this.#notFound = true;
|
|
@@ -1011,7 +1152,7 @@ function defineBwalletxSignin(tag = SIGNIN_TAG) {
|
|
|
1011
1152
|
}
|
|
1012
1153
|
|
|
1013
1154
|
// src/pay.ts
|
|
1014
|
-
var
|
|
1155
|
+
var import_sdk5 = require("@bsv/sdk");
|
|
1015
1156
|
var BRC29_PROTOCOL = [2, "3241645161d8"];
|
|
1016
1157
|
var PaymentError = class extends Error {
|
|
1017
1158
|
constructor(code, message, maybeSent = false, cause) {
|
|
@@ -1031,13 +1172,13 @@ var isPaymail = (s) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s);
|
|
|
1031
1172
|
function randomB64(n) {
|
|
1032
1173
|
const b = new Uint8Array(n);
|
|
1033
1174
|
globalThis.crypto.getRandomValues(b);
|
|
1034
|
-
return
|
|
1175
|
+
return import_sdk5.Utils.toBase64(Array.from(b));
|
|
1035
1176
|
}
|
|
1036
1177
|
function opReturn(text) {
|
|
1037
|
-
const d =
|
|
1178
|
+
const d = import_sdk5.Utils.toArray(text, "utf8");
|
|
1038
1179
|
const len = d.length;
|
|
1039
1180
|
const push = len < 76 ? [len] : len <= 255 ? [76, len] : [77, len & 255, len >> 8];
|
|
1040
|
-
return
|
|
1181
|
+
return import_sdk5.Utils.toHex([0, 106, ...push, ...d]);
|
|
1041
1182
|
}
|
|
1042
1183
|
var clip = (s, n) => s.length > n ? s.slice(0, n - 1) + "\u2026" : s;
|
|
1043
1184
|
var describe = (s) => clip(s.length < 5 ? `${s} payment`.trim() : s, 50);
|
|
@@ -1090,11 +1231,11 @@ async function resolvePaymailP2P(paymail, sats, f = fetch) {
|
|
|
1090
1231
|
return {
|
|
1091
1232
|
outputs: body.outputs.map((o) => ({ script: o.script, satoshis: o.satoshis })),
|
|
1092
1233
|
reference: body.reference,
|
|
1093
|
-
submit: receive ? async (
|
|
1234
|
+
submit: receive ? async (hex2) => {
|
|
1094
1235
|
await f(fill(receive), {
|
|
1095
1236
|
method: "POST",
|
|
1096
1237
|
headers: { "content-type": "application/json" },
|
|
1097
|
-
body: JSON.stringify({ hex, reference: body.reference, metadata: {} })
|
|
1238
|
+
body: JSON.stringify({ hex: hex2, reference: body.reference, metadata: {} })
|
|
1098
1239
|
});
|
|
1099
1240
|
} : void 0
|
|
1100
1241
|
};
|
|
@@ -1133,7 +1274,7 @@ async function pay(source, req, o = {}) {
|
|
|
1133
1274
|
} catch (e) {
|
|
1134
1275
|
throw new PaymentError("WALLET_ERROR", `The wallet could not derive the payment key: ${e.message}`, false, e);
|
|
1135
1276
|
}
|
|
1136
|
-
outputs = [{ script: new
|
|
1277
|
+
outputs = [{ script: new import_sdk5.P2PKH().lock(import_sdk5.PublicKey.fromString(pk).toHash()).toHex(), satoshis: sats, description: "payment" }];
|
|
1137
1278
|
remittance = { senderIdentityKey: me, derivationPrefix, derivationSuffix, outputIndex: 0 };
|
|
1138
1279
|
} else if (isPaymail(to)) {
|
|
1139
1280
|
const r2 = await (o.resolvePaymail ?? ((p, s) => resolvePaymailP2P(p, s, o.fetch ?? fetch)))(to, sats);
|
|
@@ -1141,7 +1282,7 @@ async function pay(source, req, o = {}) {
|
|
|
1141
1282
|
submit = r2.submit;
|
|
1142
1283
|
} else {
|
|
1143
1284
|
try {
|
|
1144
|
-
outputs = [{ script: new
|
|
1285
|
+
outputs = [{ script: new import_sdk5.P2PKH().lock(to).toHex(), satoshis: sats, description: "payment" }];
|
|
1145
1286
|
} catch {
|
|
1146
1287
|
throw new PaymentError("BAD_REQUEST", `Not a paymail, address or identity key: ${to}`);
|
|
1147
1288
|
}
|
|
@@ -1151,7 +1292,7 @@ async function pay(source, req, o = {}) {
|
|
|
1151
1292
|
if (!r.txid) throw new PaymentError("WALLET_ERROR", "The wallet did not return a txid", true);
|
|
1152
1293
|
const tx = r.tx ? Array.from(r.tx) : void 0;
|
|
1153
1294
|
if (submit && tx) {
|
|
1154
|
-
await submit(
|
|
1295
|
+
await submit(import_sdk5.Transaction.fromAtomicBEEF(tx).toHex()).catch(() => {
|
|
1155
1296
|
});
|
|
1156
1297
|
}
|
|
1157
1298
|
return { txid: r.txid, tx, sats, outputs, remittance };
|
|
@@ -1172,7 +1313,7 @@ async function buyToken(source, req) {
|
|
|
1172
1313
|
}
|
|
1173
1314
|
|
|
1174
1315
|
// src/wallets.ts
|
|
1175
|
-
var
|
|
1316
|
+
var import_sdk6 = require("@bsv/sdk");
|
|
1176
1317
|
async function brc100Connected(wallet, o) {
|
|
1177
1318
|
await wallet.waitForAuthentication({}).catch(() => {
|
|
1178
1319
|
});
|
|
@@ -1231,7 +1372,7 @@ function handcashAdapter(o) {
|
|
|
1231
1372
|
var NAMES = { [RDNS_EXTENSION]: "bWalletX", "space.bwallet.mobile": "bWalletX" };
|
|
1232
1373
|
async function probe(substrate, ms) {
|
|
1233
1374
|
try {
|
|
1234
|
-
const w = new
|
|
1375
|
+
const w = new import_sdk6.WalletClient(substrate);
|
|
1235
1376
|
const ok = await Promise.race([w.isAuthenticated({}).then(() => true), new Promise((r) => setTimeout(() => r(false), ms))]);
|
|
1236
1377
|
return ok ? w : null;
|
|
1237
1378
|
} catch {
|
|
@@ -1240,7 +1381,7 @@ async function probe(substrate, ms) {
|
|
|
1240
1381
|
}
|
|
1241
1382
|
async function discoverWallets(o = {}) {
|
|
1242
1383
|
const out = [];
|
|
1243
|
-
const ms = o.ms ??
|
|
1384
|
+
const ms = o.ms ?? 300;
|
|
1244
1385
|
if (typeof window !== "undefined") {
|
|
1245
1386
|
const seen = /* @__PURE__ */ new Map();
|
|
1246
1387
|
const onAnnounce = (e) => {
|
|
@@ -1254,7 +1395,7 @@ async function discoverWallets(o = {}) {
|
|
|
1254
1395
|
window.addEventListener("brc100:announceWallet", onAnnounce);
|
|
1255
1396
|
window.dispatchEvent(new Event("brc100:requestWallet"));
|
|
1256
1397
|
const local = o.probeLocal ? Promise.all([probe("json-api", ms), probe("Cicada", ms)]) : Promise.resolve([null, null]);
|
|
1257
|
-
await new Promise((r) => setTimeout(r, ms));
|
|
1398
|
+
await new Promise((r) => setTimeout(r, seen.size > 0 || window.CWI ? Math.min(ms, 50) : ms));
|
|
1258
1399
|
window.removeEventListener("brc100:announceWallet", onAnnounce);
|
|
1259
1400
|
out.push(...seen.values());
|
|
1260
1401
|
const cwi = window.CWI;
|
|
@@ -1284,6 +1425,9 @@ var CSS2 = `
|
|
|
1284
1425
|
.bwx-row{display:flex;gap:8px;margin-top:14px}
|
|
1285
1426
|
.bwx-btn{flex:1;border:1px solid #3a3220;background:#15130e;color:#f4f1e8;border-radius:10px;padding:10px 12px;font:inherit;cursor:pointer}
|
|
1286
1427
|
.bwx-btn:hover{border-color:#e8c766}
|
|
1428
|
+
a.bwx-btn{display:block;text-align:center;text-decoration:none;box-sizing:border-box}
|
|
1429
|
+
.bwx-primary{background:linear-gradient(180deg,#fcd34d,#f59e0b);color:#000;border:0;font-weight:700;min-height:48px;padding:13px 12px}
|
|
1430
|
+
.bwx-stack{display:flex;flex-direction:column;gap:8px}
|
|
1287
1431
|
.bwx-list{display:flex;flex-direction:column;gap:8px}
|
|
1288
1432
|
.bwx-opt{display:flex;align-items:center;gap:10px;text-align:left}
|
|
1289
1433
|
.bwx-opt img{width:24px;height:24px;border-radius:6px}
|
|
@@ -1314,6 +1458,18 @@ function qrSvg(text) {
|
|
|
1314
1458
|
q.make();
|
|
1315
1459
|
return q.createSvgTag({ cellSize: 4, margin: 2, scalable: true });
|
|
1316
1460
|
}
|
|
1461
|
+
function isTouchDevice(env = globalThis) {
|
|
1462
|
+
const nav = env.navigator;
|
|
1463
|
+
if (!nav) return false;
|
|
1464
|
+
const ua = nav.userAgent ?? "";
|
|
1465
|
+
if (/Android|iPhone|iPad|iPod|Mobile|Silk|Kindle/i.test(ua)) return true;
|
|
1466
|
+
if (/Macintosh/.test(ua) && (nav.maxTouchPoints ?? 0) > 1) return true;
|
|
1467
|
+
try {
|
|
1468
|
+
return !!env.matchMedia?.("(pointer: coarse)").matches && !env.matchMedia?.("(hover: hover)").matches;
|
|
1469
|
+
} catch {
|
|
1470
|
+
return false;
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1317
1473
|
function pairingModal(o = {}) {
|
|
1318
1474
|
const ac = new AbortController();
|
|
1319
1475
|
let ui = null;
|
|
@@ -1330,20 +1486,37 @@ function pairingModal(o = {}) {
|
|
|
1330
1486
|
if (typeof document === "undefined") return;
|
|
1331
1487
|
close();
|
|
1332
1488
|
ui = mount();
|
|
1489
|
+
const app = o.mode === "app" || (o.mode ?? "auto") === "auto" && isTouchDevice();
|
|
1333
1490
|
const h = el("h2", "", o.title ?? "Connect bWalletX");
|
|
1491
|
+
const cancel = el("button", "bwx-btn", "Cancel");
|
|
1492
|
+
cancel.onclick = () => {
|
|
1493
|
+
o.onCancel?.();
|
|
1494
|
+
ac.abort();
|
|
1495
|
+
};
|
|
1496
|
+
codeEl = el("div", "bwx-code", "");
|
|
1497
|
+
codeEl.setAttribute("aria-live", "polite");
|
|
1498
|
+
if (app) {
|
|
1499
|
+
const p2 = el("p", "", "Open bWalletX, approve, then come back to this page.");
|
|
1500
|
+
const stack = el("div", "bwx-stack");
|
|
1501
|
+
const open = el("a", "bwx-btn bwx-primary", "Open bWalletX");
|
|
1502
|
+
open.href = link;
|
|
1503
|
+
open.rel = "noopener";
|
|
1504
|
+
const web = el("button", "bwx-btn", "Use web.bwalletx.com instead");
|
|
1505
|
+
web.onclick = () => {
|
|
1506
|
+
void navigator.clipboard?.writeText(link).catch(() => void 0);
|
|
1507
|
+
window.open(WEB_WALLET_URL, "_blank", "noopener");
|
|
1508
|
+
p2.textContent = "Link copied. In web.bwalletx.com tap Connect and paste it, then come back here.";
|
|
1509
|
+
};
|
|
1510
|
+
stack.append(open, web, cancel);
|
|
1511
|
+
ui.box.append(h, p2, codeEl, stack);
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1334
1514
|
const p = el("p", "", "Scan with bWalletX on your phone, or paste the link into web.bwalletx.com.");
|
|
1335
1515
|
const qr = el("div", "bwx-qr");
|
|
1336
1516
|
qr.innerHTML = qrSvg(link);
|
|
1337
|
-
codeEl = el("div", "bwx-code", "");
|
|
1338
|
-
codeEl.setAttribute("aria-live", "polite");
|
|
1339
1517
|
const row = el("div", "bwx-row");
|
|
1340
1518
|
const copy = el("button", "bwx-btn", "Copy link");
|
|
1341
1519
|
copy.onclick = () => void navigator.clipboard?.writeText(link).then(() => copy.textContent = "Copied");
|
|
1342
|
-
const cancel = el("button", "bwx-btn", "Cancel");
|
|
1343
|
-
cancel.onclick = () => {
|
|
1344
|
-
o.onCancel?.();
|
|
1345
|
-
ac.abort();
|
|
1346
|
-
};
|
|
1347
1520
|
row.append(copy, cancel);
|
|
1348
1521
|
ui.box.append(h, p, qr, codeEl, row);
|
|
1349
1522
|
},
|
|
@@ -1387,6 +1560,25 @@ function pickWallet(options, o = {}) {
|
|
|
1387
1560
|
ui.box.lastChild.append(cancel);
|
|
1388
1561
|
});
|
|
1389
1562
|
}
|
|
1563
|
+
|
|
1564
|
+
// src/theme.ts
|
|
1565
|
+
var WALLET_THEME_META = "bwalletx-theme";
|
|
1566
|
+
var ID = /^[a-z0-9-]{1,32}$/;
|
|
1567
|
+
function declareWalletTheme(theme) {
|
|
1568
|
+
if (typeof document === "undefined") return;
|
|
1569
|
+
const id = (theme ?? "").trim().toLowerCase();
|
|
1570
|
+
let meta = document.head.querySelector(`meta[name="${WALLET_THEME_META}"]`);
|
|
1571
|
+
if (!id || !ID.test(id)) {
|
|
1572
|
+
meta?.remove();
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
if (!meta) {
|
|
1576
|
+
meta = document.createElement("meta");
|
|
1577
|
+
meta.name = WALLET_THEME_META;
|
|
1578
|
+
document.head.appendChild(meta);
|
|
1579
|
+
}
|
|
1580
|
+
if (meta.content !== id) meta.content = id;
|
|
1581
|
+
}
|
|
1390
1582
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1391
1583
|
0 && (module.exports = {
|
|
1392
1584
|
ACCESS_ERROR_STATUS,
|
|
@@ -1395,6 +1587,7 @@ function pickWallet(options, o = {}) {
|
|
|
1395
1587
|
AccessError,
|
|
1396
1588
|
BRC29_PROTOCOL,
|
|
1397
1589
|
BWALLETX_RDNS,
|
|
1590
|
+
DEFAULT_DISCOVER_MS,
|
|
1398
1591
|
GET_URL,
|
|
1399
1592
|
LOGIN_PROTOCOL,
|
|
1400
1593
|
LOGO_URL,
|
|
@@ -1404,15 +1597,18 @@ function pickWallet(options, o = {}) {
|
|
|
1404
1597
|
RDNS_MOBILE,
|
|
1405
1598
|
SIGNIN_CSS,
|
|
1406
1599
|
SIGNIN_TAG,
|
|
1600
|
+
WALLET_THEME_META,
|
|
1407
1601
|
WEB_WALLET_URL,
|
|
1408
1602
|
accessErrorMessage,
|
|
1409
1603
|
amountInSats,
|
|
1604
|
+
bindPrewarm,
|
|
1410
1605
|
brc100Option,
|
|
1411
1606
|
buildAuthorizeUrl,
|
|
1412
1607
|
buyToken,
|
|
1413
1608
|
canonicalJson,
|
|
1414
1609
|
clearPairing,
|
|
1415
1610
|
connectBwalletX,
|
|
1611
|
+
declareWalletTheme,
|
|
1416
1612
|
defineBwalletxSignin,
|
|
1417
1613
|
discoverBwalletX,
|
|
1418
1614
|
discoverWallets,
|
|
@@ -1421,12 +1617,14 @@ function pickWallet(options, o = {}) {
|
|
|
1421
1617
|
inOrder,
|
|
1422
1618
|
isIdentityKeyHex,
|
|
1423
1619
|
isPaymail,
|
|
1620
|
+
isTouchDevice,
|
|
1424
1621
|
markSvg,
|
|
1425
1622
|
pairBwalletX,
|
|
1426
1623
|
pairingModal,
|
|
1427
1624
|
pairingOption,
|
|
1428
1625
|
pay,
|
|
1429
1626
|
pickWallet,
|
|
1627
|
+
prewarmBwalletX,
|
|
1430
1628
|
protocolMediaUrl,
|
|
1431
1629
|
proveHoldings,
|
|
1432
1630
|
qrSvg,
|