@bwalletx/connect 0.5.6 → 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.
Files changed (36) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +22 -2
  3. package/dist/bwalletx-connect.global.js +15 -10
  4. package/dist/bwalletx-connect.global.js.map +1 -1
  5. package/dist/{choice-DCh-tgpT.d.cts → choice-B97AjqF4.d.cts} +87 -3
  6. package/dist/{choice-DCh-tgpT.d.ts → choice-B97AjqF4.d.ts} +87 -3
  7. package/dist/{chunk-LS6AYEBO.js → chunk-6EFFOIHK.js} +596 -41
  8. package/dist/chunk-6EFFOIHK.js.map +1 -0
  9. package/dist/{chunk-34DKBQNN.js → chunk-DIKJFKND.js} +22 -5
  10. package/dist/chunk-DIKJFKND.js.map +1 -0
  11. package/dist/{chunk-IFGOAROM.js → chunk-TNRI7ARM.js} +14 -63
  12. package/dist/chunk-TNRI7ARM.js.map +1 -0
  13. package/dist/{element-D9Zl-x12.d.cts → element-BXEoOdXY.d.cts} +11 -4
  14. package/dist/{element-D9Zl-x12.d.ts → element-BXEoOdXY.d.ts} +11 -4
  15. package/dist/element.cjs +480 -50
  16. package/dist/element.cjs.map +1 -1
  17. package/dist/element.d.cts +7 -2
  18. package/dist/element.d.ts +7 -2
  19. package/dist/element.js +8 -2
  20. package/dist/element.js.map +1 -1
  21. package/dist/index.cjs +676 -100
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +169 -11
  24. package/dist/index.d.ts +169 -11
  25. package/dist/index.js +92 -6
  26. package/dist/index.js.map +1 -1
  27. package/dist/react.cjs +683 -103
  28. package/dist/react.cjs.map +1 -1
  29. package/dist/react.d.cts +43 -4
  30. package/dist/react.d.ts +43 -4
  31. package/dist/react.js +147 -12
  32. package/dist/react.js.map +1 -1
  33. package/package.json +1 -1
  34. package/dist/chunk-34DKBQNN.js.map +0 -1
  35. package/dist/chunk-IFGOAROM.js.map +0 -1
  36. package/dist/chunk-LS6AYEBO.js.map +0 -1
@@ -1,15 +1,29 @@
1
1
  import {
2
+ BWALLETX_TYPE,
2
3
  SIGNIN_CSS,
3
4
  clearPairing,
4
5
  connectBwalletX,
5
6
  discoverBwalletX,
7
+ forgetWalletChoice,
6
8
  markSvg,
7
- pairingModal
8
- } from "./chunk-LS6AYEBO.js";
9
+ pairingModal,
10
+ rememberWalletChoice,
11
+ rememberedWalletChoice
12
+ } from "./chunk-6EFFOIHK.js";
9
13
 
10
14
  // src/wallet-button.ts
11
15
  var BUTTON_TAG = "bwalletx-button";
12
16
  var CONNECTED_KEY = "bwx:connected";
17
+ function migrateConnectedKey() {
18
+ const had = dropLegacyConnectedKey();
19
+ if (had && !rememberedWalletChoice()) rememberBwalletX("extension");
20
+ return had;
21
+ }
22
+ function rememberBwalletX(substrate) {
23
+ rememberWalletChoice({ id: "bwalletx", name: "bWalletX", kind: substrate === "pairing" ? "pairing" : "brc100", isBwalletX: true, substrate, connect: async () => {
24
+ throw new Error("unused");
25
+ } });
26
+ }
13
27
  function dropLegacyConnectedKey() {
14
28
  try {
15
29
  const had = globalThis.localStorage?.getItem(CONNECTED_KEY) != null;
@@ -79,7 +93,7 @@ function createClass() {
79
93
  }
80
94
  live.add(this);
81
95
  this.#hideLegacy();
82
- dropLegacyConnectedKey();
96
+ migrateConnectedKey();
83
97
  const phone = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
84
98
  this.#set(stateFor({ connected: false, found: null, phone }));
85
99
  const ms = Number(this.getAttribute("discover-ms")) || 800;
@@ -146,8 +160,9 @@ function createClass() {
146
160
  const modal = pairingModal({ title: "Connect bWalletX" });
147
161
  this.#set("connecting");
148
162
  try {
149
- const { wallet } = await connectBwalletX({ pairing: modal });
163
+ const { wallet, method } = await connectBwalletX({ pairing: modal });
150
164
  const { publicKey } = await wallet.getPublicKey({ identityKey: true });
165
+ rememberBwalletX(method === "pairing" ? "pairing" : method === "in-app" ? "in-app" : "extension");
151
166
  this.#connected(publicKey);
152
167
  } catch (e) {
153
168
  if (e?.code === "NOT_FOUND") this.#set("none");
@@ -174,6 +189,7 @@ function createClass() {
174
189
  this.#key = null;
175
190
  this.#paymail = null;
176
191
  dropLegacyConnectedKey();
192
+ if (rememberedWalletChoice()?.type === BWALLETX_TYPE) forgetWalletChoice();
177
193
  this.#set("available");
178
194
  this.#emit("bwalletx-disconnected");
179
195
  }
@@ -212,6 +228,7 @@ function _resetBwalletxButtons() {
212
228
  export {
213
229
  BUTTON_TAG,
214
230
  CONNECTED_KEY,
231
+ migrateConnectedKey,
215
232
  dropLegacyConnectedKey,
216
233
  getUrlFor,
217
234
  stateFor,
@@ -219,4 +236,4 @@ export {
219
236
  defineBwalletxButton,
220
237
  _resetBwalletxButtons
221
238
  };
222
- //# sourceMappingURL=chunk-34DKBQNN.js.map
239
+ //# sourceMappingURL=chunk-DIKJFKND.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/wallet-button.ts"],"sourcesContent":["/**\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) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' })[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":["s"]}
@@ -1,18 +1,15 @@
1
- import {
2
- attemptFor,
3
- decideWallet,
4
- outcomeOf,
5
- rememberIdentity,
6
- rememberedIdentity,
7
- reportAttempt,
8
- signInAndVerify,
9
- substrateOf,
10
- walletTypeOf
11
- } from "./chunk-LS6AYEBO.js";
12
-
13
1
  // src/pay.ts
14
2
  import { P2PKH, PublicKey, Transaction, Utils } from "@bsv/sdk";
15
3
  var BRC29_PROTOCOL = [2, "3241645161d8"];
4
+ var NO_COINS_TEXT = "Your wallet doesn't have enough to cover this payment and its small network fee. Add a little and try again.";
5
+ function isInsufficientFunds(e) {
6
+ const err = e;
7
+ if (!err) return false;
8
+ if (err.name === "WERR_INSUFFICIENT_FUNDS" || err.code === "WERR_INSUFFICIENT_FUNDS" || err.code === "ERR_INSUFFICIENT_FUNDS") return true;
9
+ if (err.isError === true && err.code === 7) return true;
10
+ const msg = typeof err.message === "string" ? err.message : String(e);
11
+ return /insufficient (funds|balance)|not enough (funds|coins|satoshis|sats)|more satoshis are needed/i.test(msg);
12
+ }
16
13
  var PaymentError = class extends Error {
17
14
  constructor(code, message, maybeSent = false, cause) {
18
15
  super(message);
@@ -108,6 +105,7 @@ async function runAction(wallet, description, outputs, labels) {
108
105
  options: { randomizeOutputs: false }
109
106
  });
110
107
  } catch (e) {
108
+ if (isInsufficientFunds(e)) throw new PaymentError("INSUFFICIENT_FUNDS", NO_COINS_TEXT, false, e);
111
109
  const msg = e?.message ?? String(e);
112
110
  const rejected = /denied|reject|cancel|abort|user/i.test(msg) || e?.code === 4001;
113
111
  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);
@@ -190,56 +188,10 @@ function declareWalletTheme(theme) {
190
188
  if (meta.content !== id) meta.content = id;
191
189
  }
192
190
 
193
- // src/connect-flow.ts
194
- async function runConnect(o) {
195
- const started = Date.now();
196
- const { list } = o;
197
- let choice = null;
198
- let reason = "none";
199
- try {
200
- const d = decideWallet(list, { walletId: o.walletId, chooser: o.chooser, picker: o.picker, fastPath: o.fastPath });
201
- choice = d.option;
202
- reason = d.reason;
203
- if (!choice && d.reason === "chooser") choice = await o.pick(list);
204
- if (!choice) {
205
- if (d.reason === "none" || !list.length) throw Object.assign(new Error("No wallet found. Get bWalletX at bwalletx.com."), { code: "NOT_FOUND" });
206
- reportAttempt(o.onAttempt, attemptFor(null, "cancelled", started));
207
- return null;
208
- }
209
- const signIn = !!(o.challengeUrl && o.verifyUrl) && choice.kind !== "handcash";
210
- const cw = await choice.connect(signIn ? { identity: false } : void 0);
211
- let handle = cw.handle ?? null;
212
- let paymail = cw.paymail ?? null;
213
- let identityKey = cw.identityKey;
214
- let signedIn = false;
215
- if (cw.wallet && signIn) {
216
- const { result, verified } = await signInAndVerify({
217
- wallet: cw.wallet,
218
- identityKey: cw.identityKey ?? void 0,
219
- // The key that signed in here last time: a repeat sign-in is then the signature alone.
220
- identityKeyHint: rememberedIdentity(),
221
- challengeNeedsIdentityKey: o.challengeNeedsIdentityKey,
222
- challenge: (key) => o.post(o.challengeUrl, key ? { identityKey: key } : {}),
223
- verify: (r) => o.post(o.verifyUrl, { identityKey: r.identityKey, nonce: r.nonce, signature: r.signature })
224
- });
225
- rememberIdentity(result.identityKey);
226
- identityKey = result.identityKey;
227
- handle = verified.handle ?? handle;
228
- paymail = verified.paymail ?? paymail;
229
- signedIn = true;
230
- } else if (cw.wallet && !identityKey) {
231
- identityKey = (await cw.wallet.getPublicKey({ identityKey: true })).publicKey;
232
- }
233
- reportAttempt(o.onAttempt, attemptFor(choice, signedIn ? "signed-in" : "connected", started));
234
- return { connected: cw, identityKey, handle, paymail, signedIn, walletType: walletTypeOf(choice), substrate: substrateOf(choice), reason };
235
- } catch (e) {
236
- reportAttempt(o.onAttempt, attemptFor(choice, outcomeOf(e), started));
237
- throw e;
238
- }
239
- }
240
-
241
191
  export {
242
192
  BRC29_PROTOCOL,
193
+ NO_COINS_TEXT,
194
+ isInsufficientFunds,
243
195
  PaymentError,
244
196
  isIdentityKeyHex,
245
197
  isPaymail,
@@ -249,7 +201,6 @@ export {
249
201
  tip,
250
202
  buyToken,
251
203
  WALLET_THEME_META,
252
- declareWalletTheme,
253
- runConnect
204
+ declareWalletTheme
254
205
  };
255
- //# sourceMappingURL=chunk-IFGOAROM.js.map
206
+ //# sourceMappingURL=chunk-TNRI7ARM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pay.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' | 'INSUFFICIENT_FUNDS';\n\n/** (0.7.0) The plain message for a wallet with no coins for the network fee (PaymentError code INSUFFICIENT_FUNDS). */\nexport const NO_COINS_TEXT = \"Your wallet doesn't have enough to cover this payment and its small network fee. Add a little and try again.\";\n\n/**\n * True when createAction failed because the wallet has no coins (or too few) to fund it: the SDK's\n * WERR_INSUFFICIENT_FUNDS (code 7, also as it arrives from Metanet Desktop over the JSON API), or a wallet's own\n * \"insufficient funds\" text. Nothing was sent in that case.\n */\nexport function isInsufficientFunds(e: unknown): boolean {\n const err = e as { name?: unknown; code?: unknown; isError?: unknown; message?: unknown } | null;\n if (!err) return false;\n if (err.name === 'WERR_INSUFFICIENT_FUNDS' || err.code === 'WERR_INSUFFICIENT_FUNDS' || err.code === 'ERR_INSUFFICIENT_FUNDS') return true;\n if (err.isError === true && err.code === 7) return true;\n const msg = typeof err.message === 'string' ? err.message : String(e);\n return /insufficient (funds|balance)|not enough (funds|coins|satoshis|sats)|more satoshis are needed/i.test(msg);\n}\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 // No coins for the fee: one plain line, and nothing was sent (maybeSent false).\n if (isInsufficientFunds(e)) throw new PaymentError('INSUFFICIENT_FUNDS', NO_COINS_TEXT, false, 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 * 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"]}
@@ -9,7 +9,7 @@ type SigninBrand = 'bWalletX' | 'bWallet';
9
9
  declare function signinText(label?: SigninLabel, brand?: SigninBrand): string;
10
10
  /** The gold "b" (bwalletx-site/logo.svg). Ids are unique per copy so several marks can share a page. */
11
11
  declare function markSvg(px?: number): string;
12
- declare 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.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";
12
+ declare 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";
13
13
  /** The badge menu. Rendered in a body-level portal (position: fixed), so overflow:hidden parents never clip it. */
14
14
  declare 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";
15
15
  type SigninState = 'signed-out' | 'restoring' | 'pending' | 'signed-in' | 'error';
@@ -25,8 +25,15 @@ declare const PENDING_NOTE = "Sign in: shares only your public identity key, mov
25
25
  declare const PENDING_LABEL = "Approve in bWalletX\u2026";
26
26
  /** The pending label when the user picked a wallet other than bWalletX. */
27
27
  declare const PENDING_LABEL_OTHER = "Approve in your wallet\u2026";
28
- /** What started a sign-in: the button ('signin') or "Other wallets" ('chooser'). */
29
- type SigninMode = 'signin' | 'chooser';
28
+ /**
29
+ * What started a sign-in: the button ('signin'), "Other wallets" ('chooser'), "Switch" ('bwalletx', 0.6.0) or "Use
30
+ * Metanet Desktop or another BRC-100 wallet" ('metanet', 0.7.0).
31
+ */
32
+ type SigninMode = 'signin' | 'chooser' | 'bwalletx' | 'metanet';
33
+ /** (0.6.0) The note shown when the remembered or connected wallet isn't bWalletX. */
34
+ declare const SWITCH_NOTE = "Some features need bWalletX";
35
+ /** (0.6.0) The button's label when the tap goes to a remembered wallet that isn't bWalletX. */
36
+ declare const CONTINUE_OTHER_LABEL = "Continue with your wallet";
30
37
  /** Optional OAuth parameters for authorize-url mode. auth.bwalletx.com is planned, not live. */
31
38
  interface AuthorizeParams {
32
39
  authorizeUrl: string;
@@ -43,4 +50,4 @@ declare function buildAuthorizeUrl(p: AuthorizeParams): Promise<string>;
43
50
  /** Register <bwalletx-signin> (once). Safe to call on a server: it does nothing there. */
44
51
  declare function defineBwalletxSignin(tag?: string): CustomElementConstructor | undefined;
45
52
 
46
- export { type AuthorizeParams as A, GET_URL as G, MENU_CSS as M, PENDING_LABEL as P, type SigninSize as S, WEB_WALLET_URL as W, type SigninTheme as a, type SigninLabel as b, type SigninBrand as c, type SigninState as d, PENDING_LABEL_OTHER as e, PENDING_NOTE as f, SIGNIN_CSS as g, SIGNIN_TAG as h, type SigninAccount as i, type SigninMode as j, buildAuthorizeUrl as k, defineBwalletxSignin as l, markSvg as m, signinText as s };
53
+ export { type AuthorizeParams as A, CONTINUE_OTHER_LABEL as C, GET_URL as G, MENU_CSS as M, PENDING_LABEL as P, type SigninSize as S, WEB_WALLET_URL as W, type SigninTheme as a, type SigninLabel as b, type SigninBrand as c, type SigninState as d, PENDING_LABEL_OTHER as e, PENDING_NOTE as f, SIGNIN_CSS as g, SIGNIN_TAG as h, SWITCH_NOTE as i, type SigninAccount as j, type SigninMode as k, buildAuthorizeUrl as l, defineBwalletxSignin as m, markSvg as n, signinText as s };
@@ -9,7 +9,7 @@ type SigninBrand = 'bWalletX' | 'bWallet';
9
9
  declare function signinText(label?: SigninLabel, brand?: SigninBrand): string;
10
10
  /** The gold "b" (bwalletx-site/logo.svg). Ids are unique per copy so several marks can share a page. */
11
11
  declare function markSvg(px?: number): string;
12
- declare 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.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";
12
+ declare 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";
13
13
  /** The badge menu. Rendered in a body-level portal (position: fixed), so overflow:hidden parents never clip it. */
14
14
  declare 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";
15
15
  type SigninState = 'signed-out' | 'restoring' | 'pending' | 'signed-in' | 'error';
@@ -25,8 +25,15 @@ declare const PENDING_NOTE = "Sign in: shares only your public identity key, mov
25
25
  declare const PENDING_LABEL = "Approve in bWalletX\u2026";
26
26
  /** The pending label when the user picked a wallet other than bWalletX. */
27
27
  declare const PENDING_LABEL_OTHER = "Approve in your wallet\u2026";
28
- /** What started a sign-in: the button ('signin') or "Other wallets" ('chooser'). */
29
- type SigninMode = 'signin' | 'chooser';
28
+ /**
29
+ * What started a sign-in: the button ('signin'), "Other wallets" ('chooser'), "Switch" ('bwalletx', 0.6.0) or "Use
30
+ * Metanet Desktop or another BRC-100 wallet" ('metanet', 0.7.0).
31
+ */
32
+ type SigninMode = 'signin' | 'chooser' | 'bwalletx' | 'metanet';
33
+ /** (0.6.0) The note shown when the remembered or connected wallet isn't bWalletX. */
34
+ declare const SWITCH_NOTE = "Some features need bWalletX";
35
+ /** (0.6.0) The button's label when the tap goes to a remembered wallet that isn't bWalletX. */
36
+ declare const CONTINUE_OTHER_LABEL = "Continue with your wallet";
30
37
  /** Optional OAuth parameters for authorize-url mode. auth.bwalletx.com is planned, not live. */
31
38
  interface AuthorizeParams {
32
39
  authorizeUrl: string;
@@ -43,4 +50,4 @@ declare function buildAuthorizeUrl(p: AuthorizeParams): Promise<string>;
43
50
  /** Register <bwalletx-signin> (once). Safe to call on a server: it does nothing there. */
44
51
  declare function defineBwalletxSignin(tag?: string): CustomElementConstructor | undefined;
45
52
 
46
- export { type AuthorizeParams as A, GET_URL as G, MENU_CSS as M, PENDING_LABEL as P, type SigninSize as S, WEB_WALLET_URL as W, type SigninTheme as a, type SigninLabel as b, type SigninBrand as c, type SigninState as d, PENDING_LABEL_OTHER as e, PENDING_NOTE as f, SIGNIN_CSS as g, SIGNIN_TAG as h, type SigninAccount as i, type SigninMode as j, buildAuthorizeUrl as k, defineBwalletxSignin as l, markSvg as m, signinText as s };
53
+ export { type AuthorizeParams as A, CONTINUE_OTHER_LABEL as C, GET_URL as G, MENU_CSS as M, PENDING_LABEL as P, type SigninSize as S, WEB_WALLET_URL as W, type SigninTheme as a, type SigninLabel as b, type SigninBrand as c, type SigninState as d, PENDING_LABEL_OTHER as e, PENDING_NOTE as f, SIGNIN_CSS as g, SIGNIN_TAG as h, SWITCH_NOTE as i, type SigninAccount as j, type SigninMode as k, buildAuthorizeUrl as l, defineBwalletxSignin as m, markSvg as n, signinText as s };