@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
package/dist/index.cjs CHANGED
@@ -40,13 +40,27 @@ __export(src_exports, {
40
40
  BWALLETX_RDNS: () => BWALLETX_RDNS,
41
41
  BWALLETX_TYPE: () => BWALLETX_TYPE,
42
42
  CONNECTED_KEY: () => CONNECTED_KEY,
43
+ CONTINUE_OTHER_LABEL: () => CONTINUE_OTHER_LABEL,
43
44
  DEFAULT_DISCOVER_MS: () => DEFAULT_DISCOVER_MS,
44
45
  DESKTOP_OPTION_ID: () => DESKTOP_OPTION_ID,
45
46
  GET_URL: () => GET_URL,
46
47
  IDENTITY_HINT_KEY: () => IDENTITY_HINT_KEY,
48
+ KNOWN_KEYS_KEY: () => KNOWN_KEYS_KEY,
47
49
  LOGIN_PROTOCOL: () => LOGIN_PROTOCOL,
48
50
  LOGO_URL: () => LOGO_URL,
49
51
  MENU_CSS: () => MENU_CSS,
52
+ METANET_ANSWER_MS: () => METANET_ANSWER_MS,
53
+ METANET_JSON_API: () => METANET_JSON_API,
54
+ METANET_LABEL: () => METANET_LABEL,
55
+ METANET_NOTE: () => METANET_NOTE,
56
+ METANET_OPTION_ID: () => METANET_OPTION_ID,
57
+ METANET_REMEMBERED_NOTE: () => METANET_REMEMBERED_NOTE,
58
+ METANET_SILENT_MS: () => METANET_SILENT_MS,
59
+ METANET_TYPE: () => METANET_TYPE,
60
+ METANET_UNREACHABLE: () => METANET_UNREACHABLE,
61
+ MetanetUnreachableError: () => MetanetUnreachableError,
62
+ NOT_YOU_LABEL: () => NOT_YOU_LABEL,
63
+ NO_COINS_TEXT: () => NO_COINS_TEXT,
50
64
  PAYMAIL_LOOKUP_URL: () => PAYMAIL_LOOKUP_URL,
51
65
  PENDING_LABEL: () => PENDING_LABEL,
52
66
  PENDING_LABEL_OTHER: () => PENDING_LABEL_OTHER,
@@ -57,11 +71,14 @@ __export(src_exports, {
57
71
  RDNS_MOBILE: () => RDNS_MOBILE,
58
72
  SIGNIN_CSS: () => SIGNIN_CSS,
59
73
  SIGNIN_TAG: () => SIGNIN_TAG,
74
+ SWITCH_NOTE: () => SWITCH_NOTE,
75
+ WALLET_CHOICE_KEY: () => WALLET_CHOICE_KEY,
60
76
  WALLET_THEME_META: () => WALLET_THEME_META,
61
77
  WEB_WALLET_URL: () => WEB_WALLET_URL,
62
78
  accessErrorMessage: () => accessErrorMessage,
63
79
  accountLabel: () => accountLabel,
64
80
  amountInSats: () => amountInSats,
81
+ attachRemembered: () => attachRemembered,
65
82
  attemptFor: () => attemptFor,
66
83
  autoChoice: () => autoChoice,
67
84
  avatarUrlFor: () => avatarUrlFor,
@@ -73,8 +90,10 @@ __export(src_exports, {
73
90
  challengeWantsIdentityKey: () => challengeWantsIdentityKey,
74
91
  chooseWallet: () => chooseWallet,
75
92
  chooserOrder: () => chooserOrder,
93
+ claimSilentAttempt: () => claimSilentAttempt,
76
94
  clearPairing: () => clearPairing,
77
95
  connectBwalletX: () => connectBwalletX,
96
+ connectMetanetDesktop: () => connectMetanetDesktop,
78
97
  cwiIsAnnounced: () => cwiIsAnnounced,
79
98
  decideWallet: () => decideWallet,
80
99
  declareWalletTheme: () => declareWalletTheme,
@@ -85,19 +104,33 @@ __export(src_exports, {
85
104
  discoverWallets: () => discoverWallets,
86
105
  dropLegacyConnectedKey: () => dropLegacyConnectedKey,
87
106
  findBwalletX: () => findBwalletX,
107
+ forgetWalletChoice: () => forgetWalletChoice,
88
108
  getUrlFor: () => getUrlFor,
89
109
  handcashAdapter: () => handcashAdapter,
90
110
  handleLabel: () => handleLabel,
91
111
  hasBwalletX: () => hasBwalletX,
112
+ inAnyFrame: () => inAnyFrame,
92
113
  inOrder: () => inOrder,
114
+ isExplicitPick: () => isExplicitPick,
93
115
  isFramed: () => isFramed,
94
116
  isIdentityKeyHex: () => isIdentityKeyHex,
117
+ isInsufficientFunds: () => isInsufficientFunds,
118
+ isKnownIdentityKey: () => isKnownIdentityKey,
119
+ isLocalDesktop: () => isLocalDesktop,
120
+ isLocalDesktopType: () => isLocalDesktopType,
95
121
  isPaymail: () => isPaymail,
96
122
  isPresentBwalletX: () => isPresentBwalletX,
123
+ isRememberable: () => isRememberable,
97
124
  isTouchDevice: () => isTouchDevice,
98
125
  isUserRejection: () => isUserRejection,
126
+ knownIdentityKeys: () => knownIdentityKeys,
99
127
  lookupPaymail: () => lookupPaymail,
100
128
  markSvg: () => markSvg,
129
+ matchRemembered: () => matchRemembered,
130
+ metanetOffered: () => metanetOffered,
131
+ metanetOption: () => metanetOption,
132
+ migrateConnectedKey: () => migrateConnectedKey,
133
+ needsBwalletX: () => needsBwalletX,
101
134
  otherDetected: () => otherDetected,
102
135
  outcomeOf: () => outcomeOf,
103
136
  pairBwalletX: () => pairBwalletX,
@@ -105,30 +138,40 @@ __export(src_exports, {
105
138
  pairingOption: () => pairingOption,
106
139
  pay: () => pay,
107
140
  pickWallet: () => pickWallet,
141
+ planAutoConnect: () => planAutoConnect,
108
142
  prewarmBwalletX: () => prewarmBwalletX,
109
143
  protocolMediaUrl: () => protocolMediaUrl,
110
144
  proveHoldings: () => proveHoldings,
111
145
  qrSvg: () => qrSvg,
112
146
  rememberIdentity: () => rememberIdentity,
147
+ rememberKnownIdentityKey: () => rememberKnownIdentityKey,
148
+ rememberWalletChoice: () => rememberWalletChoice,
113
149
  rememberedIdentity: () => rememberedIdentity,
150
+ rememberedWalletChoice: () => rememberedWalletChoice,
114
151
  renderButton: () => renderButton,
115
152
  reportAttempt: () => reportAttempt,
116
153
  requestAccess: () => requestAccess,
154
+ resetSilentAttempt: () => resetSilentAttempt,
117
155
  resolvePaymailP2P: () => resolvePaymailP2P,
118
156
  restorePairing: () => restorePairing,
119
157
  runConnect: () => runConnect,
158
+ runSilentMetanet: () => runSilentMetanet,
120
159
  shortKey: () => shortKey,
121
160
  signInAndVerify: () => signInAndVerify,
122
161
  signInErrorText: () => signInErrorText,
123
162
  signInWithBwalletX: () => signInWithBwalletX,
124
163
  signinText: () => signinText,
164
+ silentAttemptUsed: () => silentAttemptUsed,
125
165
  stateFor: () => stateFor,
126
166
  substrateOf: () => substrateOf,
167
+ tapGoesElsewhere: () => tapGoesElsewhere,
127
168
  throwIfAccessError: () => throwIfAccessError,
128
169
  tip: () => tip,
129
170
  toAccessError: () => toAccessError,
171
+ trySilentMetanet: () => trySilentMetanet,
130
172
  waitIfLocked: () => waitIfLocked,
131
- walletTypeOf: () => walletTypeOf
173
+ walletTypeOf: () => walletTypeOf,
174
+ warnIfNoLogout: () => warnIfNoLogout
132
175
  });
133
176
  module.exports = __toCommonJS(src_exports);
134
177
 
@@ -143,7 +186,7 @@ function discoverBwalletX(ms = DEFAULT_DISCOVER_MS) {
143
186
  return new Promise((resolve) => {
144
187
  let done = false;
145
188
  let timer;
146
- const finish = (r) => {
189
+ const finish2 = (r) => {
147
190
  if (done) return;
148
191
  done = true;
149
192
  if (timer !== void 0) clearTimeout(timer);
@@ -154,19 +197,19 @@ function discoverBwalletX(ms = DEFAULT_DISCOVER_MS) {
154
197
  const d = e.detail;
155
198
  const rdns = d?.info?.rdns ?? "";
156
199
  if (d?.wallet && BWALLETX_RDNS.includes(rdns)) {
157
- finish({ wallet: d.wallet, method: rdns === RDNS_EXTENSION ? "extension" : "in-app", rdns });
200
+ finish2({ wallet: d.wallet, method: rdns === RDNS_EXTENSION ? "extension" : "in-app", rdns });
158
201
  }
159
202
  };
160
203
  window.addEventListener("brc100:announceWallet", onAnnounce);
161
204
  window.dispatchEvent(new Event("brc100:requestWallet"));
162
205
  if (done) return;
163
206
  if (isFramed()) {
164
- void probeXdm(Math.max(ms, 1200)).then((w) => finish(w ? { wallet: w, method: "in-app", rdns: null } : null));
207
+ void probeXdm(Math.max(ms, 1200)).then((w) => finish2(w ? { wallet: w, method: "in-app", rdns: null } : null));
165
208
  return;
166
209
  }
167
210
  timer = setTimeout(() => {
168
211
  timer = void 0;
169
- finish(null);
212
+ finish2(null);
170
213
  }, ms);
171
214
  });
172
215
  }
@@ -903,15 +946,20 @@ function desktopOption(ms = 1500) {
903
946
  return opt;
904
947
  }
905
948
  function autoChoice(list, force = false) {
906
- const detected = list.filter((w) => w.kind === "brc100");
907
- const others = list.filter((w) => w.kind === "handcash" || w.kind === "custom");
908
- if (force) return detected[0] ?? list.find((w) => w.kind !== "pairing") ?? list[0] ?? null;
949
+ const auto = list.filter((w) => !isLocalDesktop(w));
950
+ const detected = auto.filter((w) => w.kind === "brc100");
951
+ const others = auto.filter((w) => w.kind === "handcash" || w.kind === "custom");
952
+ const hasLocal = auto.length !== list.length;
953
+ if (force) return detected[0] ?? auto.find((w) => w.kind !== "pairing") ?? auto[0] ?? null;
909
954
  if (!list.length) return null;
910
- if (list.length === 1) return list[0];
911
- if (detected.length === 1 && others.length === 0) return detected[0];
912
- if (detected.length === 0 && others.length === 0) return list[0];
955
+ if (list.length === 1) return hasLocal ? void 0 : list[0];
956
+ if (detected.length === 1 && others.length === 0 && !hasLocal) return detected[0];
957
+ if (detected.length === 0 && others.length === 0) return auto[0] ?? void 0;
913
958
  return void 0;
914
959
  }
960
+ function isLocalDesktop(w) {
961
+ return w.substrate === "json-api" || w.substrate === "cicada" || w.id === "localhost:3321" || w.id === "localhost:3301" || w.id === DESKTOP_OPTION_ID;
962
+ }
915
963
 
916
964
  // src/account.ts
917
965
  var PAYMAIL_LOOKUP_URL = "https://pay.bwallet.space/api/paymail/lookup?key=";
@@ -947,6 +995,7 @@ function isUserRejection(e) {
947
995
  }
948
996
  function signInErrorText(e) {
949
997
  if (isUserRejection(e)) return "Sign-in cancelled";
998
+ if (e?.name === "MetanetUnreachableError") return e.message;
950
999
  const code = e?.code;
951
1000
  if (code === "NOT_FOUND") return "bWalletX was not found in this browser";
952
1001
  const msg = e instanceof Error ? e.message : String(e ?? "");
@@ -980,6 +1029,175 @@ function rememberIdentity(key) {
980
1029
  }
981
1030
  }
982
1031
 
1032
+ // src/metanet.ts
1033
+ var import_sdk5 = require("@bsv/sdk");
1034
+
1035
+ // src/device.ts
1036
+ function isTouchDevice(env = globalThis) {
1037
+ const nav = env.navigator;
1038
+ if (!nav) return false;
1039
+ const ua = nav.userAgent ?? "";
1040
+ if (/Android|iPhone|iPad|iPod|Mobile|Silk|Kindle/i.test(ua)) return true;
1041
+ if (/Macintosh/.test(ua) && (nav.maxTouchPoints ?? 0) > 1) return true;
1042
+ try {
1043
+ return !!env.matchMedia?.("(pointer: coarse)").matches && !env.matchMedia?.("(hover: hover)").matches;
1044
+ } catch {
1045
+ return false;
1046
+ }
1047
+ }
1048
+
1049
+ // src/metanet.ts
1050
+ var METANET_TYPE = "metanet";
1051
+ var METANET_OPTION_ID = METANET_TYPE;
1052
+ var METANET_JSON_API = "http://localhost:3321";
1053
+ var METANET_LABEL = "Use Metanet Desktop or another BRC-100 wallet";
1054
+ var METANET_NOTE = "Metanet Desktop must be running on this computer";
1055
+ var METANET_REMEMBERED_NOTE = "Signs in with Metanet Desktop on this computer.";
1056
+ var NOT_YOU_LABEL = "Not you? Use another wallet";
1057
+ var METANET_UNREACHABLE = "We couldn\u2019t reach Metanet Desktop. Open it, then try again.";
1058
+ var METANET_ANSWER_MS = 4e3;
1059
+ var METANET_SILENT_MS = 2e3;
1060
+ var MetanetUnreachableError = class extends Error {
1061
+ code = "NOT_FOUND";
1062
+ constructor() {
1063
+ super(METANET_UNREACHABLE);
1064
+ this.name = "MetanetUnreachableError";
1065
+ }
1066
+ };
1067
+ function inAnyFrame(win = typeof window === "undefined" ? void 0 : window) {
1068
+ if (!win) return false;
1069
+ try {
1070
+ return win.top !== win.self;
1071
+ } catch {
1072
+ return true;
1073
+ }
1074
+ }
1075
+ function metanetOffered(env = {}) {
1076
+ const win = env.window ?? (typeof window === "undefined" ? void 0 : window);
1077
+ if (!win) return false;
1078
+ const nav = env.navigator ?? (typeof navigator === "undefined" ? void 0 : navigator);
1079
+ const mm = env.matchMedia ?? (typeof matchMedia === "undefined" ? void 0 : (q) => matchMedia(q));
1080
+ return !isTouchDevice({ navigator: nav, matchMedia: mm }) && !inAnyFrame(win);
1081
+ }
1082
+ function client(o) {
1083
+ if (o.make) return o.make();
1084
+ const originator = o.originator ?? (typeof location !== "undefined" && location.host ? location.host : void 0);
1085
+ return new import_sdk5.WalletClient("json-api", originator);
1086
+ }
1087
+ async function answers(wallet) {
1088
+ return Promise.resolve().then(() => wallet.getVersion({})).then((v) => typeof v?.version === "string", () => false);
1089
+ }
1090
+ async function connectMetanetDesktop(o = {}) {
1091
+ let wallet;
1092
+ try {
1093
+ wallet = client(o);
1094
+ } catch {
1095
+ throw new MetanetUnreachableError();
1096
+ }
1097
+ let timer;
1098
+ const ok = await Promise.race([answers(wallet), new Promise((r) => timer = setTimeout(() => r(false), o.timeoutMs ?? METANET_ANSWER_MS))]);
1099
+ clearTimeout(timer);
1100
+ if (!ok) throw new MetanetUnreachableError();
1101
+ return wallet;
1102
+ }
1103
+ function metanetOption(o = {}) {
1104
+ const opt = {
1105
+ id: METANET_OPTION_ID,
1106
+ name: METANET_LABEL,
1107
+ kind: "brc100",
1108
+ isBwalletX: false,
1109
+ substrate: "json-api",
1110
+ async connect() {
1111
+ const wallet = await connectMetanetDesktop(o);
1112
+ opt.wallet = wallet;
1113
+ await waitIfLocked(wallet);
1114
+ const { publicKey } = await wallet.getPublicKey({ identityKey: true });
1115
+ return { wallet, payer: wallet, identityKey: publicKey, optionId: opt.id, kind: "brc100" };
1116
+ }
1117
+ };
1118
+ return opt;
1119
+ }
1120
+ var KNOWN_KEYS_KEY = "bwx:known-keys";
1121
+ var KEY_RE = /^0[23][0-9a-f]{64}$/;
1122
+ var MAX_KNOWN = 8;
1123
+ function knownIdentityKeys() {
1124
+ try {
1125
+ const v = JSON.parse(globalThis.localStorage?.getItem(KNOWN_KEYS_KEY) || "[]");
1126
+ return Array.isArray(v) ? v.filter((k) => typeof k === "string" && KEY_RE.test(k)) : [];
1127
+ } catch {
1128
+ return [];
1129
+ }
1130
+ }
1131
+ function isKnownIdentityKey(key) {
1132
+ if (!key) return false;
1133
+ const k = key.toLowerCase();
1134
+ if (!KEY_RE.test(k)) return false;
1135
+ return knownIdentityKeys().includes(k) || rememberedIdentity()?.toLowerCase() === k;
1136
+ }
1137
+ function rememberKnownIdentityKey(key) {
1138
+ const k = (key ?? "").toLowerCase();
1139
+ if (!KEY_RE.test(k)) return;
1140
+ try {
1141
+ const list = [k, ...knownIdentityKeys().filter((x) => x !== k)].slice(0, MAX_KNOWN);
1142
+ globalThis.localStorage?.setItem(KNOWN_KEYS_KEY, JSON.stringify(list));
1143
+ } catch {
1144
+ }
1145
+ }
1146
+ var triedThisLoad = false;
1147
+ function silentAttemptUsed() {
1148
+ return triedThisLoad;
1149
+ }
1150
+ function claimSilentAttempt() {
1151
+ if (triedThisLoad) return false;
1152
+ triedThisLoad = true;
1153
+ return true;
1154
+ }
1155
+ function resetSilentAttempt() {
1156
+ triedThisLoad = false;
1157
+ }
1158
+ async function trySilentMetanet(o = {}) {
1159
+ if (!metanetOffered()) return { ok: false, stop: "not-here" };
1160
+ if (!claimSilentAttempt()) return { ok: false, stop: "used" };
1161
+ const run = async () => {
1162
+ let wallet;
1163
+ try {
1164
+ wallet = client(o);
1165
+ } catch {
1166
+ return { ok: false, stop: "unreachable" };
1167
+ }
1168
+ if (!await answers(wallet)) return { ok: false, stop: "unreachable" };
1169
+ const unlocked = await Promise.resolve().then(() => wallet.isAuthenticated({})).then((r2) => r2?.authenticated === true, () => false);
1170
+ if (!unlocked) return { ok: false, stop: "locked" };
1171
+ const identityKey = await Promise.resolve().then(() => wallet.getPublicKey({ identityKey: true })).then((r2) => r2.publicKey, () => null);
1172
+ if (!identityKey) return { ok: false, stop: "unreachable" };
1173
+ if (!isKnownIdentityKey(identityKey)) return { ok: false, stop: "unknown-key" };
1174
+ return { ok: true, wallet, identityKey };
1175
+ };
1176
+ let timer;
1177
+ const r = await Promise.race([
1178
+ run().catch(() => ({ ok: false, stop: "unreachable" })),
1179
+ new Promise((res) => timer = setTimeout(() => res({ ok: false, stop: "slow" }), o.windowMs ?? METANET_SILENT_MS))
1180
+ ]);
1181
+ clearTimeout(timer);
1182
+ return r;
1183
+ }
1184
+ var warnedLogout = false;
1185
+ var isProduction = () => {
1186
+ try {
1187
+ return globalThis.process?.env?.NODE_ENV === "production";
1188
+ } catch {
1189
+ return false;
1190
+ }
1191
+ };
1192
+ function warnIfNoLogout(o) {
1193
+ if (!o.verifyUrl || o.logoutUrl || warnedLogout || isProduction() || typeof console === "undefined") return false;
1194
+ warnedLogout = true;
1195
+ console.warn(
1196
+ `@bwalletx/connect: ${o.where} has a verify URL but no logout URL. Set it: "Not you? Use another wallet" and Disconnect must be able to end a session the verify route created.`
1197
+ );
1198
+ return true;
1199
+ }
1200
+
983
1201
  // src/choice.ts
984
1202
  var BWALLETX_TYPE = "bwalletx";
985
1203
  function substrateOf(o) {
@@ -1021,6 +1239,10 @@ function decideWallet(list, o = {}) {
1021
1239
  const a = autoChoice([...list], o.picker === false);
1022
1240
  return a === void 0 ? { option: null, reason: "chooser" } : a === null ? { option: null, reason: "none" } : { option: a, reason: "legacy" };
1023
1241
  }
1242
+ if (o.remembered && !o.preferBwalletX) {
1243
+ const m = matchRemembered(list, o.remembered);
1244
+ if (m) return { option: m, reason: "remembered" };
1245
+ }
1024
1246
  const b = list.find(isPresentBwalletX);
1025
1247
  if (b) return { option: b, reason: "bwalletx" };
1026
1248
  if (o.picker === false) {
@@ -1051,6 +1273,74 @@ function reportAttempt(hook, a) {
1051
1273
  } catch {
1052
1274
  }
1053
1275
  }
1276
+ var WALLET_CHOICE_KEY = "bwx:wallet";
1277
+ var SUBSTRATES = ["extension", "in-app", "xdm", "injected", "window.CWI", "json-api", "cicada", "pairing", "adapter"];
1278
+ var TYPE_RE = /^[A-Za-z0-9._:-]{1,64}$/;
1279
+ var KEY_LIKE = /^(0[23][0-9a-f]{64}|04[0-9a-f]{128}|[13][1-9A-HJ-NP-Za-km-z]{25,34})$/i;
1280
+ function isRememberable(o) {
1281
+ const t = walletTypeOf(o);
1282
+ return substrateOf(o) !== "window.CWI" && TYPE_RE.test(t) && !KEY_LIKE.test(t);
1283
+ }
1284
+ function isExplicitPick(o, reason) {
1285
+ return o.isBwalletX || reason === "chooser" || reason === "requested" || reason === "remembered";
1286
+ }
1287
+ function rememberWalletChoice(o) {
1288
+ try {
1289
+ if (!o) return void globalThis.localStorage?.removeItem(WALLET_CHOICE_KEY);
1290
+ if (!isRememberable(o)) return;
1291
+ const v = { type: walletTypeOf(o), substrate: substrateOf(o), v: 1 };
1292
+ globalThis.localStorage?.setItem(WALLET_CHOICE_KEY, JSON.stringify(v));
1293
+ } catch {
1294
+ }
1295
+ }
1296
+ function rememberedWalletChoice() {
1297
+ try {
1298
+ const raw = globalThis.localStorage?.getItem(WALLET_CHOICE_KEY);
1299
+ if (!raw) return null;
1300
+ const j = JSON.parse(raw);
1301
+ if (typeof j.type !== "string" || !TYPE_RE.test(j.type) || KEY_LIKE.test(j.type)) return null;
1302
+ if (!SUBSTRATES.includes(j.substrate) || j.substrate === "window.CWI") return null;
1303
+ return { type: j.type, substrate: j.substrate };
1304
+ } catch {
1305
+ return null;
1306
+ }
1307
+ }
1308
+ function forgetWalletChoice() {
1309
+ rememberWalletChoice(null);
1310
+ }
1311
+ function needsBwalletX(type) {
1312
+ return !!type && type !== BWALLETX_TYPE;
1313
+ }
1314
+ function tapGoesElsewhere(type) {
1315
+ return needsBwalletX(type) && type !== METANET_TYPE && type !== DESKTOP_OPTION_ID;
1316
+ }
1317
+ function isLocalDesktopType(r) {
1318
+ return r.type === METANET_TYPE || r.type === DESKTOP_OPTION_ID || r.substrate === "json-api" || r.substrate === "cicada";
1319
+ }
1320
+ function matchRemembered(list, r) {
1321
+ if (isLocalDesktopType(r)) return null;
1322
+ if (r.type === BWALLETX_TYPE) {
1323
+ return (r.substrate === "pairing" ? list.find((o) => o.kind === "pairing") : list.find(isPresentBwalletX)) ?? null;
1324
+ }
1325
+ return list.find((o) => !o.isBwalletX && !isLocalDesktop(o) && isRememberable(o) && walletTypeOf(o) === r.type) ?? null;
1326
+ }
1327
+ var ATTACHABLE = ["extension", "in-app", "xdm", "injected"];
1328
+ function planAutoConnect(o) {
1329
+ const r = o.remembered;
1330
+ if (!r || o.enabled === false) return { action: "none", remembered: r, needsBwalletX: false };
1331
+ if (r.type === METANET_TYPE) {
1332
+ return { action: o.metanetHere ?? metanetOffered() ? "silent-metanet" : "none", remembered: r, needsBwalletX: false };
1333
+ }
1334
+ if (isLocalDesktopType(r)) return { action: "none", remembered: r, needsBwalletX: false };
1335
+ const action = o.signedIn && ATTACHABLE.includes(r.substrate) ? "attach" : "wait-for-tap";
1336
+ return { action, remembered: r, needsBwalletX: needsBwalletX(r.type) };
1337
+ }
1338
+ async function attachRemembered(r, o = {}) {
1339
+ if (!ATTACHABLE.includes(r.substrate)) return null;
1340
+ const list = await discoverWallets({ ms: o.ms });
1341
+ const m = matchRemembered(list, r);
1342
+ return m && m.kind === "brc100" && m.wallet && ATTACHABLE.includes(substrateOf(m)) ? m : null;
1343
+ }
1054
1344
 
1055
1345
  // src/modal.ts
1056
1346
  var import_qrcode_generator = __toESM(require("qrcode-generator"), 1);
@@ -1112,18 +1402,6 @@ function qrSvg(text) {
1112
1402
  q.make();
1113
1403
  return q.createSvgTag({ cellSize: 4, margin: 2, scalable: true });
1114
1404
  }
1115
- function isTouchDevice(env = globalThis) {
1116
- const nav = env.navigator;
1117
- if (!nav) return false;
1118
- const ua = nav.userAgent ?? "";
1119
- if (/Android|iPhone|iPad|iPod|Mobile|Silk|Kindle/i.test(ua)) return true;
1120
- if (/Macintosh/.test(ua) && (nav.maxTouchPoints ?? 0) > 1) return true;
1121
- try {
1122
- return !!env.matchMedia?.("(pointer: coarse)").matches && !env.matchMedia?.("(hover: hover)").matches;
1123
- } catch {
1124
- return false;
1125
- }
1126
- }
1127
1405
  function pairingModal(o = {}) {
1128
1406
  const ac = new AbortController();
1129
1407
  let ui = null;
@@ -1284,10 +1562,11 @@ function chooseWallet(options, o = {}) {
1284
1562
  row2.onclick = () => done(w);
1285
1563
  list.append(row2);
1286
1564
  }
1287
- if (o.desktop !== false && !options.some((w) => w.substrate === "json-api" || w.substrate === "cicada")) {
1565
+ if (o.desktop !== false && metanetOffered() && !options.some((w) => w.substrate === "json-api" || w.substrate === "cicada")) {
1288
1566
  if (!here && !sep) list.append(el("p", "bwx-sep", "Or use"));
1289
- const d = desktopOption();
1290
- const row2 = optionRow(d, false, "Metanet or BSV Desktop on this computer", "Fewer features");
1567
+ const d = metanetOption();
1568
+ const row2 = optionRow(d, false, METANET_NOTE);
1569
+ row2.title = "Connects to Metanet Desktop on this computer, never to a browser extension.";
1291
1570
  row2.onclick = () => done(d);
1292
1571
  list.append(row2);
1293
1572
  }
@@ -1305,7 +1584,7 @@ function chooseWallet(options, o = {}) {
1305
1584
  }
1306
1585
 
1307
1586
  // src/access-client.ts
1308
- var import_sdk5 = require("@bsv/sdk");
1587
+ var import_sdk6 = require("@bsv/sdk");
1309
1588
 
1310
1589
  // src/access.ts
1311
1590
  var ACCESS_VERSION = 1;
@@ -1491,7 +1770,7 @@ async function proveHoldings(wallet, challenge, tokenId, basket = "bsv21") {
1491
1770
  const counterparty = ci.counterparty ?? "self";
1492
1771
  for (const protocolID of ci.protocolID ? [ci.protocolID] : [ONESAT, LEGACY_ONESAT]) {
1493
1772
  const { publicKey } = await wallet.getPublicKey({ protocolID, keyID: ci.keyID, counterparty });
1494
- const h = import_sdk5.Utils.toHex(import_sdk5.Hash.hash160(import_sdk5.PublicKey.fromString(publicKey).encode(true)));
1773
+ const h = import_sdk6.Utils.toHex(import_sdk6.Hash.hash160(import_sdk6.PublicKey.fromString(publicKey).encode(true)));
1495
1774
  if (want && h !== want) continue;
1496
1775
  const existing = byKey.get(publicKey);
1497
1776
  if (existing) {
@@ -1537,6 +1816,114 @@ async function requestAccess(o) {
1537
1816
  }
1538
1817
  }
1539
1818
 
1819
+ // src/connect-flow.ts
1820
+ async function runConnect(o) {
1821
+ const started = Date.now();
1822
+ const { list } = o;
1823
+ let choice = null;
1824
+ let reason = "none";
1825
+ try {
1826
+ if (o.metanet) {
1827
+ if (!metanetOffered()) throw Object.assign(new Error("Metanet Desktop runs on a computer, outside any frame."), { code: "NOT_SUPPORTED" });
1828
+ choice = metanetOption(typeof o.metanet === "object" ? o.metanet : {});
1829
+ reason = "requested";
1830
+ return await finish(o, choice, reason, started);
1831
+ }
1832
+ const d = decideWallet(list, {
1833
+ walletId: o.walletId,
1834
+ chooser: o.chooser,
1835
+ picker: o.picker,
1836
+ fastPath: o.fastPath,
1837
+ remembered: o.remembered,
1838
+ preferBwalletX: o.preferBwalletX
1839
+ });
1840
+ choice = d.option;
1841
+ reason = d.reason;
1842
+ if (!choice && d.reason === "chooser") choice = await o.pick(list);
1843
+ if (!choice) {
1844
+ if (d.reason === "none" || !list.length) throw Object.assign(new Error("No wallet found. Get bWalletX at bwalletx.com."), { code: "NOT_FOUND" });
1845
+ reportAttempt(o.onAttempt, attemptFor(null, "cancelled", started));
1846
+ return null;
1847
+ }
1848
+ return await finish(o, choice, reason, started);
1849
+ } catch (e) {
1850
+ reportAttempt(o.onAttempt, attemptFor(choice, outcomeOf(e), started));
1851
+ throw e;
1852
+ }
1853
+ }
1854
+ async function finish(o, choice, reason, started) {
1855
+ const signIn = !!(o.challengeUrl && o.verifyUrl) && choice.kind !== "handcash";
1856
+ const cw = await choice.connect(signIn ? { identity: false } : void 0);
1857
+ let handle = cw.handle ?? null;
1858
+ let paymail = cw.paymail ?? null;
1859
+ let identityKey = cw.identityKey;
1860
+ let signedIn = false;
1861
+ if (cw.wallet && signIn) {
1862
+ const { result, verified } = await signInAndVerify({
1863
+ wallet: cw.wallet,
1864
+ identityKey: cw.identityKey ?? void 0,
1865
+ // Metanet's connect() just checked the lock: don't ask again (rule 7, the minimum).
1866
+ skipWaitForAuthentication: choice.id === METANET_OPTION_ID,
1867
+ // The key that signed in here last time: a repeat sign-in is then the signature alone.
1868
+ identityKeyHint: rememberedIdentity(),
1869
+ challengeNeedsIdentityKey: o.challengeNeedsIdentityKey,
1870
+ challenge: (key) => o.post(o.challengeUrl, key ? { identityKey: key } : {}),
1871
+ verify: (r) => o.post(o.verifyUrl, { identityKey: r.identityKey, nonce: r.nonce, signature: r.signature })
1872
+ });
1873
+ rememberIdentity(result.identityKey);
1874
+ identityKey = result.identityKey;
1875
+ handle = verified.handle ?? handle;
1876
+ paymail = verified.paymail ?? paymail;
1877
+ signedIn = true;
1878
+ } else if (cw.wallet && !identityKey) {
1879
+ identityKey = (await cw.wallet.getPublicKey({ identityKey: true })).publicKey;
1880
+ }
1881
+ if (o.remember && isExplicitPick(choice, reason)) rememberWalletChoice(choice);
1882
+ if (o.remember && signedIn) rememberKnownIdentityKey(identityKey);
1883
+ reportAttempt(o.onAttempt, attemptFor(choice, signedIn ? "signed-in" : "connected", started));
1884
+ return { connected: cw, identityKey, handle, paymail, signedIn, walletType: walletTypeOf(choice), substrate: substrateOf(choice), reason };
1885
+ }
1886
+ async function runSilentMetanet(o = {}) {
1887
+ const s = await trySilentMetanet(o);
1888
+ if (!s.ok || o.isAbandoned?.()) return null;
1889
+ const started = Date.now();
1890
+ const opt = metanetOption(o);
1891
+ opt.wallet = s.wallet;
1892
+ const cw = { wallet: s.wallet, payer: s.wallet, identityKey: s.identityKey, optionId: METANET_OPTION_ID, kind: "brc100" };
1893
+ const done = (signedIn, handle = null, paymail = null) => {
1894
+ rememberWalletChoice(opt);
1895
+ if (signedIn) rememberKnownIdentityKey(s.identityKey);
1896
+ reportAttempt(o.onAttempt, attemptFor(opt, signedIn ? "signed-in" : "connected", started));
1897
+ return { connected: cw, identityKey: s.identityKey, handle, paymail, signedIn, walletType: walletTypeOf(opt), substrate: "json-api", reason: "remembered" };
1898
+ };
1899
+ if (o.sessionKey !== void 0 && o.sessionKey !== null) {
1900
+ return o.sessionKey.toLowerCase() === s.identityKey.toLowerCase() ? done(true) : null;
1901
+ }
1902
+ if (!o.challengeUrl || !o.verifyUrl || !o.post) return done(false);
1903
+ if (!isKnownIdentityKey(s.identityKey)) return null;
1904
+ try {
1905
+ o.onSignIn?.();
1906
+ const post = o.post;
1907
+ const { result, verified } = await signInAndVerify({
1908
+ wallet: s.wallet,
1909
+ identityKey: s.identityKey,
1910
+ skipWaitForAuthentication: true,
1911
+ // trySilentMetanet just saw it unlocked
1912
+ challenge: (key) => post(o.challengeUrl, key ? { identityKey: key } : {}),
1913
+ verify: (r) => post(o.verifyUrl, { identityKey: r.identityKey, nonce: r.nonce, signature: r.signature })
1914
+ });
1915
+ if (o.isAbandoned?.()) {
1916
+ await Promise.resolve(o.logout?.()).catch(() => void 0);
1917
+ return null;
1918
+ }
1919
+ rememberIdentity(result.identityKey);
1920
+ return done(true, verified.handle ?? null, verified.paymail ?? null);
1921
+ } catch (e) {
1922
+ reportAttempt(o.onAttempt, attemptFor(opt, outcomeOf(e), started));
1923
+ return null;
1924
+ }
1925
+ }
1926
+
1540
1927
  // src/element.ts
1541
1928
  var SIGNIN_TAG = "bwalletx-signin";
1542
1929
  var GET_URL = "https://bwalletx.com/get";
@@ -1602,6 +1989,11 @@ button[aria-busy=true]{cursor:wait}
1602
1989
  /* "Other wallets" (0.5.6): one small link under the button */
1603
1990
  .ow{margin:8px 0 0;width:0;min-width:100%;font-size:12px;line-height:1.4;color:#71717a;text-align:center}
1604
1991
  :host([theme=dark]) .ow,:host-context(.dark) .ow{color:#a1a1aa}
1992
+ .sw{margin:8px 0 0;width:0;min-width:100%;font-size:12px;line-height:1.4;color:#a16207;text-align:center}
1993
+ :host([theme=dark]) .sw,:host-context(.dark) .sw{color:#fcd34d}
1994
+ .mn{margin:8px 0 0;width:0;min-width:100%;font-size:12px;line-height:1.4;color:#71717a;text-align:center}
1995
+ .mn small{display:block;font-size:11px;opacity:.85}
1996
+ :host([theme=dark]) .mn,:host-context(.dark) .mn{color:#a1a1aa}
1605
1997
  .lnk{all:unset;cursor:pointer;color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px}
1606
1998
  .lnk:focus-visible{outline:2px solid #b45309;outline-offset:2px;border-radius:2px}
1607
1999
  /* error: one line plus Retry */
@@ -1640,6 +2032,11 @@ var MENU_CSS = `
1640
2032
  var PENDING_NOTE = "Sign in: shares only your public identity key, moves no money";
1641
2033
  var PENDING_LABEL = "Approve in bWalletX\u2026";
1642
2034
  var PENDING_LABEL_OTHER = "Approve in your wallet\u2026";
2035
+ var SWITCH_NOTE = "Some features need bWalletX";
2036
+ var CONTINUE_OTHER_LABEL = "Continue with your wallet";
2037
+ function walletGlyph(px) {
2038
+ return `<svg viewBox="0 0 24 24" width="${px}" height="${px}" aria-hidden="true" focusable="false" fill="none" stroke="#FFD24D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 7V5a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2"/><path d="M3 6v12a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-3"/></svg>`;
2039
+ }
1643
2040
  function b64url2(bytes) {
1644
2041
  let s = "";
1645
2042
  for (const b of bytes) s += String.fromCharCode(b);
@@ -1679,7 +2076,7 @@ async function postAccess(url, body) {
1679
2076
  const res = await fetch(url, { method: "POST", credentials: "include", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
1680
2077
  return res.json().catch(() => ({ error: "bad_request", message: `HTTP ${res.status}` }));
1681
2078
  }
1682
- var OBSERVED = ["size", "theme", "label", "brand", "subtitle", "loading", "disabled", "full-width", "aria-label", "get-url", "web-url", "state", "identity-key", "paymail", "handle", "avatar-url", "error", "other-wallets", "challenge-url"];
2079
+ var OBSERVED = ["size", "theme", "label", "brand", "subtitle", "loading", "disabled", "full-width", "aria-label", "get-url", "web-url", "state", "identity-key", "paymail", "handle", "avatar-url", "error", "other-wallets", "challenge-url", "wallet-type", "switch-note", "remember", "metanet"];
1683
2080
  var STATES = ["signed-out", "restoring", "pending", "signed-in", "error"];
1684
2081
  function createClass() {
1685
2082
  return class BwalletxSigninElement extends HTMLElement {
@@ -1694,14 +2091,21 @@ function createClass() {
1694
2091
  #error = "";
1695
2092
  #restored = false;
1696
2093
  #pendingLabel = PENDING_LABEL;
2094
+ /** The wallet type signed in with here (0.6.0), for the Switch note. */
2095
+ #signedType = null;
1697
2096
  #menu = null;
2097
+ /** (0.7.0) A Metanet sign-in (tapped or silent) is in flight. */
2098
+ #viaMetanet = false;
2099
+ /** (0.7.0) Bumped by "Not you?": a Metanet sign-in started before it lands nobody. */
2100
+ #run = 0;
1698
2101
  constructor() {
1699
2102
  super();
1700
2103
  this.#root = this.attachShadow({ mode: "open" });
1701
2104
  }
1702
2105
  connectedCallback() {
2106
+ if (!this.#controlled && this.#stateful) warnIfNoLogout({ verifyUrl: this.#attr("verify-url"), logoutUrl: this.#attr("logout-url"), where: "<bwalletx-signin>" });
1703
2107
  this.#render();
1704
- void this.#restore();
2108
+ void this.#restore().then(() => this.#silentMetanet());
1705
2109
  }
1706
2110
  disconnectedCallback() {
1707
2111
  this.#menu?.close(false);
@@ -1807,10 +2211,11 @@ function createClass() {
1807
2211
  const restoring = state === "restoring";
1808
2212
  const error = state === "error";
1809
2213
  const pendingLabel = this.#controlled ? PENDING_LABEL : this.#pendingLabel;
1810
- const text = pending ? pendingLabel : error ? "Retry" : signinText(this.#attr("label") ?? "signin", brand);
2214
+ const elsewhere = state === "signed-out" && tapGoesElsewhere(this.#walletType());
2215
+ const text = pending ? pendingLabel : error ? "Retry" : elsewhere ? CONTINUE_OTHER_LABEL : signinText(this.#attr("label") ?? "signin", brand);
1811
2216
  const subAttr = this.#attr("subtitle");
1812
2217
  const subDefault = brand === "bWalletX" && (size === "lg" || size === "md") ? "also works with bWallet" : null;
1813
- const subtitle = pending || error ? null : subAttr === null || subAttr === "" || subAttr === "on" ? subAttr === "on" ? "also works with bWallet" : subDefault : subAttr === "off" ? null : subAttr;
2218
+ const subtitle = pending || error || elsewhere ? null : subAttr === null || subAttr === "" || subAttr === "on" ? subAttr === "on" ? "also works with bWallet" : subDefault : subAttr === "off" ? null : subAttr;
1814
2219
  const loading = this.hasAttribute("loading") || this.#busy || pending || restoring;
1815
2220
  const disabled = this.hasAttribute("disabled");
1816
2221
  const markPx = size === "icon" ? 24 : size === "sm" ? 15 : size === "md" ? 17 : 20;
@@ -1819,18 +2224,26 @@ function createClass() {
1819
2224
  const webUrl = this.#attr("web-url") ?? WEB_WALLET_URL;
1820
2225
  const errText = error ? (this.#controlled ? this.#attr("error") : this.#error) || "Sign-in failed" : "";
1821
2226
  const label = size === "icon" ? "" : `<span class="txt" part="text"><b part="label">${esc(text)}</b>${subtitle ? `<small part="subtitle">${esc(subtitle)}</small>` : ""}</span>`;
1822
- const mark = loading ? '<span class="spin" aria-hidden="true"></span>' : markSvg(markPx);
2227
+ const mark = loading ? '<span class="spin" aria-hidden="true"></span>' : elsewhere ? walletGlyph(markPx - 4) : markSvg(markPx);
1823
2228
  const otherOff = this.#attr("other-wallets") === "off";
1824
2229
  const otherLink = '<button type="button" class="lnk" data-act="other" part="other-wallets-link">Other wallets</button>';
1825
2230
  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>.${otherOff ? "" : ` ${otherLink}`}</p>` : "";
1826
2231
  const ow = !this.#notFound && !pending && !restoring && this.#otherWalletsShown(size) ? `<p class="ow" part="other-wallets">${otherLink}</p>` : "";
2232
+ const sw = !pending && !restoring && this.#switchNoteShown(size) ? `<p class="sw" part="switch-note">${esc(SWITCH_NOTE)} \xB7 <button type="button" class="lnk" data-act="switch" part="switch-link">Switch</button></p>` : "";
1827
2233
  const err = error ? `<p class="err" part="error" role="alert">${esc(errText)}</p>` : "";
2234
+ const mnHere = this.#metanetShown(size);
2235
+ const mnRemembered = mnHere && (pending ? this.#metanetPending() : !restoring && this.#walletType() === METANET_TYPE);
2236
+ const notYou = `<button type="button" class="lnk" data-act="not-you" part="not-you-link">${esc(NOT_YOU_LABEL)}</button>`;
2237
+ const mn = !mnHere ? "" : pending ? mnRemembered ? `<p class="mn" part="metanet">${esc(METANET_REMEMBERED_NOTE)} ${notYou}</p>` : "" : restoring ? "" : `<p class="mn" part="metanet"><button type="button" class="lnk" data-act="metanet" part="metanet-link" title="Connects to Metanet Desktop on this computer, never to a browser extension.">${esc(METANET_LABEL)}</button><small>${esc(METANET_NOTE)}</small>${mnRemembered ? `<small>${esc(METANET_REMEMBERED_NOTE)} ${notYou}</small>` : ""}</p>`;
1828
2238
  const compact = size === "sm" || size === "icon";
1829
2239
  const note = pending && !compact ? `<p class="note" part="note">${esc(PENDING_NOTE)}</p>` : "";
1830
2240
  const status = pending ? `<span class="sr" role="status">${esc(pendingLabel)}</span>` : loading ? '<span class="sr" role="status">Connecting to bWalletX\u2026</span>' : "";
1831
- this.#root.innerHTML = `<style>${SIGNIN_CSS}</style>${err}<button type="button" part="button" aria-label="${esc(aria)}" title="${esc(subtitle ? `${text} (${subtitle})` : text)}"${disabled ? " disabled" : ""}${loading ? ' aria-busy="true"' : ""}><span class="mark" part="mark">${mark}</span>${label}</button>${status}${note}${ow}${nf}`;
2241
+ this.#root.innerHTML = `<style>${SIGNIN_CSS}</style>${err}<button type="button" part="button" aria-label="${esc(aria)}" title="${esc(subtitle ? `${text} (${subtitle})` : text)}"${disabled ? " disabled" : ""}${loading ? ' aria-busy="true"' : ""}><span class="mark" part="mark">${mark}</span>${label}</button>${status}${note}${sw}${mn}${ow}${nf}`;
1832
2242
  this.button.addEventListener("click", () => void this.#click());
1833
2243
  for (const l of Array.from(this.#root.querySelectorAll("[data-act=other]"))) l.addEventListener("click", () => void this.otherWallets());
2244
+ this.#root.querySelector("[data-act=switch]")?.addEventListener("click", () => void this.switchToBwalletX());
2245
+ this.#root.querySelector("[data-act=metanet]")?.addEventListener("click", () => void this.useMetanet());
2246
+ this.#root.querySelector("[data-act=not-you]")?.addEventListener("click", () => this.notYou());
1834
2247
  bindPrewarm(this.button);
1835
2248
  if (pending && compact) this.#showTip(PENDING_NOTE);
1836
2249
  else this.#hideTip();
@@ -1898,7 +2311,20 @@ function createClass() {
1898
2311
  close(false);
1899
2312
  void this.signOut();
1900
2313
  });
1901
- menu.append(who, copy, out);
2314
+ const items = [copy, out];
2315
+ menu.append(who);
2316
+ if (needsBwalletX(this.#walletType())) {
2317
+ const sw = item("Switch to bWalletX", () => {
2318
+ close(false);
2319
+ void this.switchToBwalletX();
2320
+ });
2321
+ const line = document.createElement("div");
2322
+ line.className = "who";
2323
+ line.textContent = SWITCH_NOTE;
2324
+ menu.append(line, sw);
2325
+ items.unshift(sw);
2326
+ }
2327
+ menu.append(copy, out);
1902
2328
  root.append(style, menu);
1903
2329
  document.body.appendChild(host);
1904
2330
  const place = () => {
@@ -1914,7 +2340,6 @@ function createClass() {
1914
2340
  menu.style.top = `${below + h > vh && r.top - 8 - h > 0 ? r.top - 8 - h : below}px`;
1915
2341
  };
1916
2342
  place();
1917
- const items = [copy, out];
1918
2343
  const focusAt = (i) => items[(i + items.length) % items.length].focus();
1919
2344
  const onKey = (e) => {
1920
2345
  const i = items.indexOf(root.activeElement);
@@ -1969,6 +2394,8 @@ function createClass() {
1969
2394
  if (this.#controlled) return;
1970
2395
  const url = this.#attr("logout-url");
1971
2396
  if (url) await fetch(url, { method: "POST", credentials: "include", headers: { "content-type": "application/json" }, body: "{}" }).catch(() => void 0);
2397
+ if (this.#remember) forgetWalletChoice();
2398
+ this.#signedType = null;
1972
2399
  this.#account = null;
1973
2400
  this.#set("signed-out");
1974
2401
  this.#emit("bwalletx-signed-out");
@@ -1988,6 +2415,110 @@ function createClass() {
1988
2415
  otherWallets() {
1989
2416
  return this.#click("chooser");
1990
2417
  }
2418
+ /** (0.6.0) "Switch": sign in with bWalletX (its sheet when here, else the chooser with Get bWalletX first). */
2419
+ switchToBwalletX() {
2420
+ return this.#click("bwalletx");
2421
+ }
2422
+ get #remember() {
2423
+ return this.#attr("remember") !== "off";
2424
+ }
2425
+ /**
2426
+ * (0.7.0) "Use Metanet Desktop or another BRC-100 wallet" is offered: metanet on, or auto at lg/md when this
2427
+ * element signs in or follows a provider. Never on a phone or inside a frame.
2428
+ */
2429
+ #metanetShown(size) {
2430
+ const a = this.#attr("metanet");
2431
+ if (a === "off" || !metanetOffered()) return false;
2432
+ if (a === "on") return true;
2433
+ return (size === "lg" || size === "md") && (this.#controlled || !!this.#attr("challenge-url"));
2434
+ }
2435
+ /** A Metanet sign-in is on screen: our own, or (driven) the provider's with Metanet remembered. */
2436
+ #metanetPending() {
2437
+ return this.#controlled ? this.#attr("wallet-type") === METANET_TYPE : this.#viaMetanet;
2438
+ }
2439
+ /** (0.7.0) The Metanet link: connect to Metanet Desktop on localhost:3321 (after this tap, never before). */
2440
+ useMetanet() {
2441
+ return this.#click("metanet");
2442
+ }
2443
+ /**
2444
+ * (0.7.0) "Not you? Use another wallet": forget the remembered wallet here, and drop a Metanet sign-in in flight
2445
+ * (if its verify already set a session, logout-url ends it). Emits bwalletx-not-you (cancelable).
2446
+ */
2447
+ notYou() {
2448
+ if (!this.#emit("bwalletx-not-you", { element: this }, true)) return;
2449
+ this.#run++;
2450
+ if (this.#remember) forgetWalletChoice();
2451
+ this.#signedType = null;
2452
+ if (this.#viaMetanet && !this.#controlled) {
2453
+ this.#viaMetanet = false;
2454
+ this.#busy = false;
2455
+ if (this.#phase === "pending") this.#phase = "signed-out";
2456
+ }
2457
+ this.#render();
2458
+ }
2459
+ /**
2460
+ * (0.7.0) Rule 4: back with Metanet remembered and no session, ONE silent attempt per page load (2 s, a known
2461
+ * identity key only), then the signature alone. Any stop or failure is silent: the normal button stays.
2462
+ */
2463
+ async #silentMetanet() {
2464
+ if (this.#controlled || !this.#stateful || !this.#remember || this.#attr("require-token")) return;
2465
+ if (!this.#metanetShown(this.#attr("size") ?? "lg")) return;
2466
+ const challengeUrl = this.#attr("challenge-url");
2467
+ const verifyUrl = this.#attr("verify-url");
2468
+ if (!challengeUrl || !verifyUrl || this.#phase !== "signed-out" || this.#busy || silentAttemptUsed()) return;
2469
+ if (rememberedWalletChoice()?.type !== METANET_TYPE || !metanetOffered()) return;
2470
+ const run = ++this.#run;
2471
+ const live2 = () => run === this.#run;
2472
+ const started = Date.now();
2473
+ const r = await runSilentMetanet({
2474
+ challengeUrl,
2475
+ verifyUrl,
2476
+ post: (url, body) => postJson(url, body),
2477
+ isAbandoned: () => !live2(),
2478
+ logout: async () => {
2479
+ const out = this.#attr("logout-url");
2480
+ if (out) await fetch(out, { method: "POST", credentials: "include", headers: { "content-type": "application/json" }, body: "{}" }).catch(() => void 0);
2481
+ },
2482
+ onSignIn: () => {
2483
+ if (!live2() || this.#phase !== "signed-out" || this.#busy) return;
2484
+ this.#viaMetanet = true;
2485
+ this.#busy = true;
2486
+ this.#pendingLabel = PENDING_LABEL_OTHER;
2487
+ this.#set("pending");
2488
+ },
2489
+ onAttempt: (a) => this.#emit("bwalletx-attempt", a)
2490
+ });
2491
+ if (!live2()) return;
2492
+ this.#viaMetanet = false;
2493
+ this.#busy = false;
2494
+ if (!r) {
2495
+ if (this.#phase === "pending") this.#set("signed-out");
2496
+ return;
2497
+ }
2498
+ this.#signedType = r.walletType;
2499
+ this.#signedIn({ identityKey: r.identityKey, handle: r.handle, paymail: r.paymail });
2500
+ this.#emit("bwalletx-signed-in", { identityKey: r.identityKey, method: "wallet", nonce: null, signature: null, response: { handle: r.handle, paymail: r.paymail }, silent: true, ms: Date.now() - started });
2501
+ }
2502
+ /** The wallet type the Switch note judges: the provider's, else what signed in here, else the remembered one. */
2503
+ #walletType() {
2504
+ if (this.#controlled) return this.#attr("wallet-type");
2505
+ return this.#signedType ?? (this.#remember ? rememberedWalletChoice()?.type ?? null : null);
2506
+ }
2507
+ #switchNoteShown(size) {
2508
+ const a = this.#attr("switch-note");
2509
+ if (a === "off" || !tapGoesElsewhere(this.#walletType())) return false;
2510
+ return a === "on" || size === "lg" || size === "md";
2511
+ }
2512
+ /**
2513
+ * Signed in: note the wallet type, and remember it for this origin when the user picked it (0.6.0), plus the
2514
+ * identity key as known here (0.7.0, public keys only: Metanet's silent attempt goes on only for these). Pass a key
2515
+ * only after the site's verify route accepted it.
2516
+ */
2517
+ #picked(option, reason, identityKey) {
2518
+ this.#signedType = walletTypeOf(option);
2519
+ if (this.#remember && isExplicitPick(option, reason)) rememberWalletChoice(option);
2520
+ if (this.#remember) rememberKnownIdentityKey(identityKey);
2521
+ }
1991
2522
  #attempt(option, outcome, started) {
1992
2523
  this.#emit("bwalletx-attempt", attemptFor(option, outcome, started));
1993
2524
  }
@@ -1996,16 +2527,24 @@ function createClass() {
1996
2527
  * when another wallet is here or the user asked; otherwise 'not-found'. null: the chooser was closed.
1997
2528
  */
1998
2529
  async #choose(mode, ms, pairing) {
2530
+ if (mode === "metanet") return { option: metanetOption(), reason: "requested" };
2531
+ const r = mode === "signin" && this.#remember ? rememberedWalletChoice() : null;
2532
+ if (r && r.type !== METANET_TYPE && !(r.type === BWALLETX_TYPE && r.substrate !== "pairing")) {
2533
+ const m = matchRemembered(await discoverWallets({ ms, pairing: () => pairing }), r);
2534
+ if (m) return { option: m, reason: "remembered" };
2535
+ }
1999
2536
  if (mode !== "chooser") {
2000
2537
  const f = await discoverBwalletX(ms);
2001
2538
  if (f) {
2002
2539
  const substrate = f.rdns === RDNS_EXTENSION ? "extension" : f.rdns === RDNS_MOBILE ? "in-app" : "xdm";
2003
- return brc100Option(f.wallet, { id: f.rdns ?? "bwalletx-xdm", rdns: f.rdns ?? void 0, name: "bWalletX", isBwalletX: true, substrate });
2540
+ const option = brc100Option(f.wallet, { id: f.rdns ?? "bwalletx-xdm", rdns: f.rdns ?? void 0, name: "bWalletX", isBwalletX: true, substrate });
2541
+ return { option, reason: "bwalletx" };
2004
2542
  }
2005
2543
  }
2006
2544
  const list = await discoverWallets({ ms: 50, pairing: () => pairing });
2007
2545
  if (mode !== "chooser" && !hasBwalletX(list) && !otherDetected(list).length) return "not-found";
2008
- return chooseWallet(list, { getUrl: this.#attr("get-url") ?? void 0 });
2546
+ const picked = await chooseWallet(list, { getUrl: this.#attr("get-url") ?? void 0 });
2547
+ return picked ? { option: picked, reason: "chooser" } : null;
2009
2548
  }
2010
2549
  async #click(mode = "signin") {
2011
2550
  if (this.hasAttribute("disabled") || this.hasAttribute("loading") || this.#busy || this.state === "pending") return;
@@ -2029,9 +2568,12 @@ function createClass() {
2029
2568
  const started = Date.now();
2030
2569
  const pairing = pairingModal();
2031
2570
  let option = null;
2571
+ const run = ++this.#run;
2572
+ const live2 = () => run === this.#run;
2032
2573
  this.#notFound = false;
2033
2574
  this.#busy = true;
2034
- this.#pendingLabel = PENDING_LABEL;
2575
+ this.#viaMetanet = mode === "metanet";
2576
+ this.#pendingLabel = mode === "metanet" ? PENDING_LABEL_OTHER : PENDING_LABEL;
2035
2577
  if (own) this.#set("pending");
2036
2578
  else this.#render();
2037
2579
  try {
@@ -2050,12 +2592,14 @@ function createClass() {
2050
2592
  this.#attempt(null, "cancelled", started);
2051
2593
  return;
2052
2594
  }
2053
- option = picked;
2595
+ option = picked.option;
2596
+ const reason = picked.reason;
2054
2597
  if (!option.isBwalletX) {
2055
2598
  this.#pendingLabel = PENDING_LABEL_OTHER;
2056
2599
  if (own) this.#render();
2057
2600
  }
2058
2601
  const cw = await option.connect({ identity: false });
2602
+ if (!live2()) return;
2059
2603
  const wallet = cw.wallet;
2060
2604
  if (!wallet) throw Object.assign(new Error("This wallet cannot sign in here"), { code: "NOT_SUPPORTED" });
2061
2605
  const sub = substrateOf(option);
@@ -2073,6 +2617,7 @@ function createClass() {
2073
2617
  challenge: (identityKey) => postJson(challengeUrl, { identityKey, require: hint }),
2074
2618
  verify: verifyUrl2 ? (response2) => postAccess(verifyUrl2, response2) : void 0
2075
2619
  });
2620
+ this.#picked(option, reason, verifyUrl2 ? a.response.identityKey : null);
2076
2621
  this.#attempt(option, "signed-in", started);
2077
2622
  this.#emit("bwalletx-access-granted", { identityKey: a.response.identityKey, response: a.verified });
2078
2623
  } catch (e) {
@@ -2085,18 +2630,29 @@ function createClass() {
2085
2630
  const verifyUrl = this.#attr("verify-url");
2086
2631
  const { result: r, verified } = await signInAndVerify({
2087
2632
  wallet,
2633
+ // Metanet hands over its key on connect (one request at a time), so its sign-in is the signature alone.
2634
+ identityKey: cw.identityKey ?? void 0,
2635
+ skipWaitForAuthentication: option.id === METANET_OPTION_ID,
2636
+ // its connect() just checked the lock
2088
2637
  identityKeyHint: verifyUrl ? rememberedIdentity() : void 0,
2089
2638
  challenge: (identityKey) => postJson(challengeUrl, identityKey ? { identityKey } : {}),
2090
2639
  verify: async (res) => verifyUrl ? await postJson(verifyUrl, { identityKey: res.identityKey, nonce: res.nonce, signature: res.signature }) : {}
2091
2640
  });
2641
+ if (!live2()) {
2642
+ const out = this.#attr("logout-url");
2643
+ if (verifyUrl && out) await fetch(out, { method: "POST", credentials: "include", headers: { "content-type": "application/json" }, body: "{}" }).catch(() => void 0);
2644
+ return;
2645
+ }
2092
2646
  if (verifyUrl) rememberIdentity(r.identityKey);
2093
2647
  const response = verifyUrl ? verified : null;
2648
+ this.#picked(option, reason, verifyUrl ? r.identityKey : null);
2094
2649
  if (own) this.#signedIn({ identityKey: r.identityKey, handle: response?.handle ?? null, paymail: response?.paymail ?? null });
2095
2650
  this.#attempt(option, "signed-in", started);
2096
2651
  this.#emit("bwalletx-signed-in", { identityKey: r.identityKey, method, nonce: r.nonce, signature: r.signature, response });
2097
2652
  } catch (error) {
2098
2653
  const outcome = outcomeOf(error);
2099
2654
  this.#attempt(option, outcome, started);
2655
+ if (!live2()) return;
2100
2656
  const closedQr = outcome === "cancelled" && option?.kind === "pairing";
2101
2657
  if (own) {
2102
2658
  if (closedQr) this.#phase = prev;
@@ -2107,12 +2663,15 @@ function createClass() {
2107
2663
  }
2108
2664
  if (!closedQr) this.#emit("bwalletx-error", { error });
2109
2665
  } finally {
2110
- this.#busy = false;
2111
2666
  try {
2112
2667
  pairing.close();
2113
2668
  } catch {
2114
2669
  }
2115
- this.#render();
2670
+ if (live2()) {
2671
+ this.#busy = false;
2672
+ this.#viaMetanet = false;
2673
+ this.#render();
2674
+ }
2116
2675
  }
2117
2676
  }
2118
2677
  };
@@ -2129,6 +2688,16 @@ function defineBwalletxSignin(tag = SIGNIN_TAG) {
2129
2688
  // src/wallet-button.ts
2130
2689
  var BUTTON_TAG = "bwalletx-button";
2131
2690
  var CONNECTED_KEY = "bwx:connected";
2691
+ function migrateConnectedKey() {
2692
+ const had = dropLegacyConnectedKey();
2693
+ if (had && !rememberedWalletChoice()) rememberBwalletX("extension");
2694
+ return had;
2695
+ }
2696
+ function rememberBwalletX(substrate) {
2697
+ rememberWalletChoice({ id: "bwalletx", name: "bWalletX", kind: substrate === "pairing" ? "pairing" : "brc100", isBwalletX: true, substrate, connect: async () => {
2698
+ throw new Error("unused");
2699
+ } });
2700
+ }
2132
2701
  function dropLegacyConnectedKey() {
2133
2702
  try {
2134
2703
  const had = globalThis.localStorage?.getItem(CONNECTED_KEY) != null;
@@ -2198,7 +2767,7 @@ function createClass2() {
2198
2767
  }
2199
2768
  live.add(this);
2200
2769
  this.#hideLegacy();
2201
- dropLegacyConnectedKey();
2770
+ migrateConnectedKey();
2202
2771
  const phone = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
2203
2772
  this.#set(stateFor({ connected: false, found: null, phone }));
2204
2773
  const ms = Number(this.getAttribute("discover-ms")) || 800;
@@ -2265,8 +2834,9 @@ function createClass2() {
2265
2834
  const modal = pairingModal({ title: "Connect bWalletX" });
2266
2835
  this.#set("connecting");
2267
2836
  try {
2268
- const { wallet } = await connectBwalletX({ pairing: modal });
2837
+ const { wallet, method } = await connectBwalletX({ pairing: modal });
2269
2838
  const { publicKey } = await wallet.getPublicKey({ identityKey: true });
2839
+ rememberBwalletX(method === "pairing" ? "pairing" : method === "in-app" ? "in-app" : "extension");
2270
2840
  this.#connected(publicKey);
2271
2841
  } catch (e) {
2272
2842
  if (e?.code === "NOT_FOUND") this.#set("none");
@@ -2293,6 +2863,7 @@ function createClass2() {
2293
2863
  this.#key = null;
2294
2864
  this.#paymail = null;
2295
2865
  dropLegacyConnectedKey();
2866
+ if (rememberedWalletChoice()?.type === BWALLETX_TYPE) forgetWalletChoice();
2296
2867
  this.#set("available");
2297
2868
  this.#emit("bwalletx-disconnected");
2298
2869
  }
@@ -2326,8 +2897,17 @@ function defineBwalletxButton(tag = BUTTON_TAG) {
2326
2897
  }
2327
2898
 
2328
2899
  // src/pay.ts
2329
- var import_sdk6 = require("@bsv/sdk");
2900
+ var import_sdk7 = require("@bsv/sdk");
2330
2901
  var BRC29_PROTOCOL = [2, "3241645161d8"];
2902
+ 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.";
2903
+ function isInsufficientFunds(e) {
2904
+ const err = e;
2905
+ if (!err) return false;
2906
+ if (err.name === "WERR_INSUFFICIENT_FUNDS" || err.code === "WERR_INSUFFICIENT_FUNDS" || err.code === "ERR_INSUFFICIENT_FUNDS") return true;
2907
+ if (err.isError === true && err.code === 7) return true;
2908
+ const msg = typeof err.message === "string" ? err.message : String(e);
2909
+ return /insufficient (funds|balance)|not enough (funds|coins|satoshis|sats)|more satoshis are needed/i.test(msg);
2910
+ }
2331
2911
  var PaymentError = class extends Error {
2332
2912
  constructor(code, message, maybeSent = false, cause) {
2333
2913
  super(message);
@@ -2346,13 +2926,13 @@ var isPaymail = (s) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s);
2346
2926
  function randomB64(n) {
2347
2927
  const b = new Uint8Array(n);
2348
2928
  globalThis.crypto.getRandomValues(b);
2349
- return import_sdk6.Utils.toBase64(Array.from(b));
2929
+ return import_sdk7.Utils.toBase64(Array.from(b));
2350
2930
  }
2351
2931
  function opReturn(text) {
2352
- const d = import_sdk6.Utils.toArray(text, "utf8");
2932
+ const d = import_sdk7.Utils.toArray(text, "utf8");
2353
2933
  const len = d.length;
2354
2934
  const push = len < 76 ? [len] : len <= 255 ? [76, len] : [77, len & 255, len >> 8];
2355
- return import_sdk6.Utils.toHex([0, 106, ...push, ...d]);
2935
+ return import_sdk7.Utils.toHex([0, 106, ...push, ...d]);
2356
2936
  }
2357
2937
  var clip = (s, n) => s.length > n ? s.slice(0, n - 1) + "\u2026" : s;
2358
2938
  var describe = (s) => clip(s.length < 5 ? `${s} payment`.trim() : s, 50);
@@ -2423,6 +3003,7 @@ async function runAction(wallet, description, outputs, labels) {
2423
3003
  options: { randomizeOutputs: false }
2424
3004
  });
2425
3005
  } catch (e) {
3006
+ if (isInsufficientFunds(e)) throw new PaymentError("INSUFFICIENT_FUNDS", NO_COINS_TEXT, false, e);
2426
3007
  const msg = e?.message ?? String(e);
2427
3008
  const rejected = /denied|reject|cancel|abort|user/i.test(msg) || e?.code === 4001;
2428
3009
  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);
@@ -2448,7 +3029,7 @@ async function pay(source, req, o = {}) {
2448
3029
  } catch (e) {
2449
3030
  throw new PaymentError("WALLET_ERROR", `The wallet could not derive the payment key: ${e.message}`, false, e);
2450
3031
  }
2451
- outputs = [{ script: new import_sdk6.P2PKH().lock(import_sdk6.PublicKey.fromString(pk).toHash()).toHex(), satoshis: sats, description: "payment" }];
3032
+ outputs = [{ script: new import_sdk7.P2PKH().lock(import_sdk7.PublicKey.fromString(pk).toHash()).toHex(), satoshis: sats, description: "payment" }];
2452
3033
  remittance = { senderIdentityKey: me, derivationPrefix, derivationSuffix, outputIndex: 0 };
2453
3034
  } else if (isPaymail(to)) {
2454
3035
  const r2 = await (o.resolvePaymail ?? ((p, s) => resolvePaymailP2P(p, s, o.fetch ?? fetch)))(to, sats);
@@ -2456,7 +3037,7 @@ async function pay(source, req, o = {}) {
2456
3037
  submit = r2.submit;
2457
3038
  } else {
2458
3039
  try {
2459
- outputs = [{ script: new import_sdk6.P2PKH().lock(to).toHex(), satoshis: sats, description: "payment" }];
3040
+ outputs = [{ script: new import_sdk7.P2PKH().lock(to).toHex(), satoshis: sats, description: "payment" }];
2460
3041
  } catch {
2461
3042
  throw new PaymentError("BAD_REQUEST", `Not a paymail, address or identity key: ${to}`);
2462
3043
  }
@@ -2466,7 +3047,7 @@ async function pay(source, req, o = {}) {
2466
3047
  if (!r.txid) throw new PaymentError("WALLET_ERROR", "The wallet did not return a txid", true);
2467
3048
  const tx = r.tx ? Array.from(r.tx) : void 0;
2468
3049
  if (submit && tx) {
2469
- await submit(import_sdk6.Transaction.fromAtomicBEEF(tx).toHex()).catch(() => {
3050
+ await submit(import_sdk7.Transaction.fromAtomicBEEF(tx).toHex()).catch(() => {
2470
3051
  });
2471
3052
  }
2472
3053
  return { txid: r.txid, tx, sats, outputs, remittance };
@@ -2504,54 +3085,6 @@ function declareWalletTheme(theme) {
2504
3085
  }
2505
3086
  if (meta.content !== id) meta.content = id;
2506
3087
  }
2507
-
2508
- // src/connect-flow.ts
2509
- async function runConnect(o) {
2510
- const started = Date.now();
2511
- const { list } = o;
2512
- let choice = null;
2513
- let reason = "none";
2514
- try {
2515
- const d = decideWallet(list, { walletId: o.walletId, chooser: o.chooser, picker: o.picker, fastPath: o.fastPath });
2516
- choice = d.option;
2517
- reason = d.reason;
2518
- if (!choice && d.reason === "chooser") choice = await o.pick(list);
2519
- if (!choice) {
2520
- if (d.reason === "none" || !list.length) throw Object.assign(new Error("No wallet found. Get bWalletX at bwalletx.com."), { code: "NOT_FOUND" });
2521
- reportAttempt(o.onAttempt, attemptFor(null, "cancelled", started));
2522
- return null;
2523
- }
2524
- const signIn = !!(o.challengeUrl && o.verifyUrl) && choice.kind !== "handcash";
2525
- const cw = await choice.connect(signIn ? { identity: false } : void 0);
2526
- let handle = cw.handle ?? null;
2527
- let paymail = cw.paymail ?? null;
2528
- let identityKey = cw.identityKey;
2529
- let signedIn = false;
2530
- if (cw.wallet && signIn) {
2531
- const { result, verified } = await signInAndVerify({
2532
- wallet: cw.wallet,
2533
- identityKey: cw.identityKey ?? void 0,
2534
- // The key that signed in here last time: a repeat sign-in is then the signature alone.
2535
- identityKeyHint: rememberedIdentity(),
2536
- challengeNeedsIdentityKey: o.challengeNeedsIdentityKey,
2537
- challenge: (key) => o.post(o.challengeUrl, key ? { identityKey: key } : {}),
2538
- verify: (r) => o.post(o.verifyUrl, { identityKey: r.identityKey, nonce: r.nonce, signature: r.signature })
2539
- });
2540
- rememberIdentity(result.identityKey);
2541
- identityKey = result.identityKey;
2542
- handle = verified.handle ?? handle;
2543
- paymail = verified.paymail ?? paymail;
2544
- signedIn = true;
2545
- } else if (cw.wallet && !identityKey) {
2546
- identityKey = (await cw.wallet.getPublicKey({ identityKey: true })).publicKey;
2547
- }
2548
- reportAttempt(o.onAttempt, attemptFor(choice, signedIn ? "signed-in" : "connected", started));
2549
- return { connected: cw, identityKey, handle, paymail, signedIn, walletType: walletTypeOf(choice), substrate: substrateOf(choice), reason };
2550
- } catch (e) {
2551
- reportAttempt(o.onAttempt, attemptFor(choice, outcomeOf(e), started));
2552
- throw e;
2553
- }
2554
- }
2555
3088
  // Annotate the CommonJS export names for ESM import in node:
2556
3089
  0 && (module.exports = {
2557
3090
  ACCESS_ERROR_STATUS,
@@ -2564,13 +3097,27 @@ async function runConnect(o) {
2564
3097
  BWALLETX_RDNS,
2565
3098
  BWALLETX_TYPE,
2566
3099
  CONNECTED_KEY,
3100
+ CONTINUE_OTHER_LABEL,
2567
3101
  DEFAULT_DISCOVER_MS,
2568
3102
  DESKTOP_OPTION_ID,
2569
3103
  GET_URL,
2570
3104
  IDENTITY_HINT_KEY,
3105
+ KNOWN_KEYS_KEY,
2571
3106
  LOGIN_PROTOCOL,
2572
3107
  LOGO_URL,
2573
3108
  MENU_CSS,
3109
+ METANET_ANSWER_MS,
3110
+ METANET_JSON_API,
3111
+ METANET_LABEL,
3112
+ METANET_NOTE,
3113
+ METANET_OPTION_ID,
3114
+ METANET_REMEMBERED_NOTE,
3115
+ METANET_SILENT_MS,
3116
+ METANET_TYPE,
3117
+ METANET_UNREACHABLE,
3118
+ MetanetUnreachableError,
3119
+ NOT_YOU_LABEL,
3120
+ NO_COINS_TEXT,
2574
3121
  PAYMAIL_LOOKUP_URL,
2575
3122
  PENDING_LABEL,
2576
3123
  PENDING_LABEL_OTHER,
@@ -2581,11 +3128,14 @@ async function runConnect(o) {
2581
3128
  RDNS_MOBILE,
2582
3129
  SIGNIN_CSS,
2583
3130
  SIGNIN_TAG,
3131
+ SWITCH_NOTE,
3132
+ WALLET_CHOICE_KEY,
2584
3133
  WALLET_THEME_META,
2585
3134
  WEB_WALLET_URL,
2586
3135
  accessErrorMessage,
2587
3136
  accountLabel,
2588
3137
  amountInSats,
3138
+ attachRemembered,
2589
3139
  attemptFor,
2590
3140
  autoChoice,
2591
3141
  avatarUrlFor,
@@ -2597,8 +3147,10 @@ async function runConnect(o) {
2597
3147
  challengeWantsIdentityKey,
2598
3148
  chooseWallet,
2599
3149
  chooserOrder,
3150
+ claimSilentAttempt,
2600
3151
  clearPairing,
2601
3152
  connectBwalletX,
3153
+ connectMetanetDesktop,
2602
3154
  cwiIsAnnounced,
2603
3155
  decideWallet,
2604
3156
  declareWalletTheme,
@@ -2609,19 +3161,33 @@ async function runConnect(o) {
2609
3161
  discoverWallets,
2610
3162
  dropLegacyConnectedKey,
2611
3163
  findBwalletX,
3164
+ forgetWalletChoice,
2612
3165
  getUrlFor,
2613
3166
  handcashAdapter,
2614
3167
  handleLabel,
2615
3168
  hasBwalletX,
3169
+ inAnyFrame,
2616
3170
  inOrder,
3171
+ isExplicitPick,
2617
3172
  isFramed,
2618
3173
  isIdentityKeyHex,
3174
+ isInsufficientFunds,
3175
+ isKnownIdentityKey,
3176
+ isLocalDesktop,
3177
+ isLocalDesktopType,
2619
3178
  isPaymail,
2620
3179
  isPresentBwalletX,
3180
+ isRememberable,
2621
3181
  isTouchDevice,
2622
3182
  isUserRejection,
3183
+ knownIdentityKeys,
2623
3184
  lookupPaymail,
2624
3185
  markSvg,
3186
+ matchRemembered,
3187
+ metanetOffered,
3188
+ metanetOption,
3189
+ migrateConnectedKey,
3190
+ needsBwalletX,
2625
3191
  otherDetected,
2626
3192
  outcomeOf,
2627
3193
  pairBwalletX,
@@ -2629,29 +3195,39 @@ async function runConnect(o) {
2629
3195
  pairingOption,
2630
3196
  pay,
2631
3197
  pickWallet,
3198
+ planAutoConnect,
2632
3199
  prewarmBwalletX,
2633
3200
  protocolMediaUrl,
2634
3201
  proveHoldings,
2635
3202
  qrSvg,
2636
3203
  rememberIdentity,
3204
+ rememberKnownIdentityKey,
3205
+ rememberWalletChoice,
2637
3206
  rememberedIdentity,
3207
+ rememberedWalletChoice,
2638
3208
  renderButton,
2639
3209
  reportAttempt,
2640
3210
  requestAccess,
3211
+ resetSilentAttempt,
2641
3212
  resolvePaymailP2P,
2642
3213
  restorePairing,
2643
3214
  runConnect,
3215
+ runSilentMetanet,
2644
3216
  shortKey,
2645
3217
  signInAndVerify,
2646
3218
  signInErrorText,
2647
3219
  signInWithBwalletX,
2648
3220
  signinText,
3221
+ silentAttemptUsed,
2649
3222
  stateFor,
2650
3223
  substrateOf,
3224
+ tapGoesElsewhere,
2651
3225
  throwIfAccessError,
2652
3226
  tip,
2653
3227
  toAccessError,
3228
+ trySilentMetanet,
2654
3229
  waitIfLocked,
2655
- walletTypeOf
3230
+ walletTypeOf,
3231
+ warnIfNoLogout
2656
3232
  });
2657
3233
  //# sourceMappingURL=index.cjs.map