@swype-org/react-sdk 0.2.315 → 0.2.323

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1442,6 +1442,53 @@ var DEFAULT_POLL_INTERVAL_MS = 1e3;
1442
1442
  var DEFAULT_COMMITMENT = "confirmed";
1443
1443
  var cachedAdapter = null;
1444
1444
  var cachedProviderKey = null;
1445
+ var solanaAccountChangeListeners = /* @__PURE__ */ new Set();
1446
+ var accountChangeBinding = null;
1447
+ function subscribeSolanaAccountChange(listener) {
1448
+ solanaAccountChangeListeners.add(listener);
1449
+ return () => {
1450
+ solanaAccountChangeListeners.delete(listener);
1451
+ };
1452
+ }
1453
+ function notifySolanaAccountChange(pubkey) {
1454
+ for (const listener of solanaAccountChangeListeners) {
1455
+ listener(pubkey);
1456
+ }
1457
+ }
1458
+ function bindAccountChangeListeners(adapter) {
1459
+ if (accountChangeBinding?.adapter === adapter) {
1460
+ return;
1461
+ }
1462
+ detachAccountChangeListeners();
1463
+ const binding = {
1464
+ adapter,
1465
+ lastNotifiedPubkey: adapter.publicKey?.toBase58() ?? null,
1466
+ onConnect: (publicKey) => {
1467
+ const next = publicKey?.toBase58();
1468
+ if (!next || next === binding.lastNotifiedPubkey) {
1469
+ return;
1470
+ }
1471
+ binding.lastNotifiedPubkey = next;
1472
+ console.info("[blink-sdk][solana-account-switch] adapter reported new account");
1473
+ notifySolanaAccountChange(next);
1474
+ },
1475
+ onDisconnect: () => {
1476
+ binding.lastNotifiedPubkey = null;
1477
+ }
1478
+ };
1479
+ adapter.on("connect", binding.onConnect);
1480
+ adapter.on("disconnect", binding.onDisconnect);
1481
+ accountChangeBinding = binding;
1482
+ }
1483
+ function detachAccountChangeListeners() {
1484
+ if (!accountChangeBinding) {
1485
+ return;
1486
+ }
1487
+ const { adapter, onConnect, onDisconnect } = accountChangeBinding;
1488
+ adapter.off("connect", onConnect);
1489
+ adapter.off("disconnect", onDisconnect);
1490
+ accountChangeBinding = null;
1491
+ }
1445
1492
  function providerKey(selection) {
1446
1493
  const providerName = selection.providerName?.trim();
1447
1494
  if (!providerName) {
@@ -1493,6 +1540,7 @@ async function connectSolanaWallet(selection, options) {
1493
1540
  await connectPromise;
1494
1541
  }
1495
1542
  }
1543
+ bindAccountChangeListeners(cachedAdapter);
1496
1544
  return {
1497
1545
  adapter: cachedAdapter,
1498
1546
  publicKey: readPublicKey(cachedAdapter)
@@ -1651,6 +1699,7 @@ async function disconnectSolanaWallet(windowImpl) {
1651
1699
  const adapter = cachedAdapter;
1652
1700
  cachedAdapter = null;
1653
1701
  cachedProviderKey = null;
1702
+ detachAccountChangeListeners();
1654
1703
  if (adapter?.connected) {
1655
1704
  try {
1656
1705
  console.info("[blink-sdk][solana-disconnect] disconnecting cached adapter");
@@ -2112,6 +2161,7 @@ __export(api_exports, {
2112
2161
  postTransferQuote: () => postTransferQuote,
2113
2162
  probeActionCompletion: () => probeActionCompletion,
2114
2163
  refreshManualTransferQuote: () => refreshManualTransferQuote,
2164
+ regenerateTransferSignPayload: () => regenerateTransferSignPayload,
2115
2165
  registerPasskey: () => registerPasskey,
2116
2166
  reportActionCompletion: () => reportActionCompletion,
2117
2167
  reportPasskeyActivity: () => reportPasskeyActivity,
@@ -2209,13 +2259,33 @@ async function fetchWithRetry(input, init, options) {
2209
2259
  throw lastError;
2210
2260
  }
2211
2261
 
2262
+ // src/apiError.ts
2263
+ var ApiError = class extends Error {
2264
+ status;
2265
+ code;
2266
+ constructor(status, code, message) {
2267
+ super(message);
2268
+ this.name = "ApiError";
2269
+ this.status = status;
2270
+ this.code = code;
2271
+ }
2272
+ };
2273
+ function isApiError(err) {
2274
+ if (err instanceof ApiError) return true;
2275
+ return typeof err === "object" && err !== null && "name" in err && err.name === "ApiError";
2276
+ }
2277
+ var SVM_SIGN_PAYLOAD_EXPIRED_CODE = "SVM_SIGN_PAYLOAD_EXPIRED";
2278
+ function isSvmSignExpiredError(err) {
2279
+ return isApiError(err) && err.code === SVM_SIGN_PAYLOAD_EXPIRED_CODE;
2280
+ }
2281
+
2212
2282
  // src/api.ts
2213
2283
  async function throwApiError(res) {
2214
2284
  const body = await res.json().catch(() => null);
2215
2285
  const detail = body?.error ?? body;
2216
2286
  const msg = detail?.message ?? res.statusText;
2217
2287
  const code = detail?.code ?? String(res.status);
2218
- throw new Error(`${res.status} \u2014 ${code}: ${msg}`);
2288
+ throw new ApiError(res.status, code, `${res.status} \u2014 ${code}: ${msg}`);
2219
2289
  }
2220
2290
  async function fetchProviders(apiBaseUrl, token) {
2221
2291
  const headers = {};
@@ -2404,6 +2474,21 @@ async function signTransfer(apiBaseUrl, token, transferId, signedTransfer, autho
2404
2474
  if (!res.ok) await throwApiError(res);
2405
2475
  return await res.json();
2406
2476
  }
2477
+ async function regenerateTransferSignPayload(apiBaseUrl, token, transferId, authorizationSessionToken) {
2478
+ if (!token && !authorizationSessionToken) {
2479
+ throw new Error("Missing auth credentials for sign payload regeneration.");
2480
+ }
2481
+ const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}/sign-payload`, {
2482
+ method: "POST",
2483
+ headers: {
2484
+ "Content-Type": "application/json",
2485
+ ...token ? { Authorization: `Bearer ${token}` } : {},
2486
+ ...authorizationSessionToken ? { "x-authorization-session-token": authorizationSessionToken } : {}
2487
+ }
2488
+ });
2489
+ if (!res.ok) await throwApiError(res);
2490
+ return await res.json();
2491
+ }
2407
2492
  async function fetchAuthorizationSession(apiBaseUrl, sessionId) {
2408
2493
  const res = await fetchWithRetry(
2409
2494
  `${apiBaseUrl}/v1/authorization-sessions/${sessionId}`
@@ -6162,7 +6247,28 @@ function useTransferSigning(pollIntervalMs = 2e3, options) {
6162
6247
  },
6163
6248
  [apiBaseUrl, getAccessToken, pollIntervalMs, authorizationSessionToken]
6164
6249
  );
6165
- return { signing, signPayload, error, passkeyDismissed, signTransfer: signTransfer2 };
6250
+ const regenerateSignPayload = react.useCallback(
6251
+ async (transferId) => {
6252
+ if (!apiBaseUrl) {
6253
+ throw new Error("Missing apiBaseUrl. Provide useTransferSigning(_, { apiBaseUrl }) or wrap in <BlinkProvider>.");
6254
+ }
6255
+ if (!getAccessToken && !authorizationSessionToken) {
6256
+ throw new Error("Missing getAccessToken provider. Provide useTransferSigning(_, { getAccessToken }).");
6257
+ }
6258
+ const token = getAccessToken ? await getAccessToken() : null;
6259
+ if (!token && !authorizationSessionToken) {
6260
+ throw new Error("Could not get access token");
6261
+ }
6262
+ return regenerateTransferSignPayload(
6263
+ apiBaseUrl,
6264
+ token ?? "",
6265
+ transferId,
6266
+ authorizationSessionToken
6267
+ );
6268
+ },
6269
+ [apiBaseUrl, getAccessToken, authorizationSessionToken]
6270
+ );
6271
+ return { signing, signPayload, error, passkeyDismissed, signTransfer: signTransfer2, regenerateSignPayload };
6166
6272
  }
6167
6273
 
6168
6274
  // src/authorizationOrchestratorOrdering.ts
@@ -7538,6 +7644,9 @@ function resolveStickyPhase(state) {
7538
7644
  accountId: null
7539
7645
  };
7540
7646
  }
7647
+ if (currentPhase.step === "welcome-back" && state.enableFullWidget && !state.welcomeBackAcknowledged && state.privyAuthenticated && state.activeCredentialId != null && !hasActiveWallet(state.accounts) && !state.mobileFlow && !state.loginRequested) {
7648
+ return currentPhase;
7649
+ }
7541
7650
  if (currentPhase.step === "wallet-picker" && currentPhase.reason === "switch" && !state.creatingTransfer && !(state.mobileFlow && state.deeplinkUri)) {
7542
7651
  return currentPhase;
7543
7652
  }
@@ -7562,6 +7671,9 @@ function deriveFreshPhase(state) {
7562
7671
  if (state.loadingData && state.activeCredentialId != null) {
7563
7672
  return { step: "data-loading" };
7564
7673
  }
7674
+ if (state.activeCredentialId != null && !state.initialDataLoaded && state.error == null) {
7675
+ return { step: "data-loading" };
7676
+ }
7565
7677
  if (state.enableFullWidget && state.authenticatedOnOpen && !state.welcomeBackAcknowledged && state.activeCredentialId != null && !hasActiveWallet(state.accounts) && !state.mobileFlow) {
7566
7678
  return { step: "welcome-back" };
7567
7679
  }
@@ -7621,6 +7733,7 @@ function createInitialState(config) {
7621
7733
  amount: config.depositAmount != null ? config.depositAmount.toString() : "",
7622
7734
  transfer: null,
7623
7735
  creatingTransfer: false,
7736
+ signPayloadExpired: false,
7624
7737
  passkeyConfigLoaded: false,
7625
7738
  activeCredentialId: config.activeCredentialId,
7626
7739
  knownCredentialIds: [],
@@ -7646,7 +7759,8 @@ function createInitialState(config) {
7646
7759
  enableFullWidget: config.enableFullWidget ?? false,
7647
7760
  requireAmountEntry: config.depositAmount == null,
7648
7761
  authenticatedOnOpen: false,
7649
- welcomeBackAcknowledged: false
7762
+ welcomeBackAcknowledged: false,
7763
+ initialDataLoaded: false
7650
7764
  };
7651
7765
  }
7652
7766
  function clearAuthenticatedSessionState(state) {
@@ -7666,6 +7780,7 @@ function clearAuthenticatedSessionState(state) {
7666
7780
  savedSelection: null,
7667
7781
  transfer: null,
7668
7782
  creatingTransfer: false,
7783
+ signPayloadExpired: false,
7669
7784
  passkeyConfigLoaded: false,
7670
7785
  activeCredentialId: null,
7671
7786
  knownCredentialIds: [],
@@ -7686,7 +7801,8 @@ function clearAuthenticatedSessionState(state) {
7686
7801
  guestWalletDeeplinksPreparing: false,
7687
7802
  amountTooLow: null,
7688
7803
  authenticatedOnOpen: false,
7689
- welcomeBackAcknowledged: false
7804
+ welcomeBackAcknowledged: false,
7805
+ initialDataLoaded: false
7690
7806
  };
7691
7807
  }
7692
7808
  function paymentReducer(state, action) {
@@ -7749,7 +7865,8 @@ function applyAction(state, action) {
7749
7865
  providers: action.providers,
7750
7866
  accounts: action.accounts,
7751
7867
  chains: action.chains,
7752
- depositSelectionRefreshing: false
7868
+ depositSelectionRefreshing: false,
7869
+ initialDataLoaded: true
7753
7870
  };
7754
7871
  if (action.defaults) {
7755
7872
  next.selectedAccountId = action.defaults.accountId;
@@ -7774,7 +7891,8 @@ function applyAction(state, action) {
7774
7891
  const next = {
7775
7892
  ...state,
7776
7893
  accounts: action.accounts,
7777
- providers: action.providers
7894
+ providers: action.providers,
7895
+ initialDataLoaded: true
7778
7896
  };
7779
7897
  if (action.defaults) {
7780
7898
  next.selectedAccountId = action.defaults.accountId;
@@ -7849,6 +7967,7 @@ function applyAction(state, action) {
7849
7967
  return {
7850
7968
  ...state,
7851
7969
  error: null,
7970
+ signPayloadExpired: false,
7852
7971
  creatingTransfer: true,
7853
7972
  depositSelectionRefreshing: false,
7854
7973
  deeplinkUri: null,
@@ -7865,14 +7984,27 @@ function applyAction(state, action) {
7865
7984
  error: action.error,
7866
7985
  creatingTransfer: false
7867
7986
  };
7987
+ case "SIGN_PAYLOAD_EXPIRED":
7988
+ return {
7989
+ ...state,
7990
+ error: action.error,
7991
+ signPayloadExpired: true,
7992
+ creatingTransfer: false
7993
+ };
7868
7994
  case "TRANSFER_CREATED":
7869
7995
  return { ...state, transfer: action.transfer };
7870
7996
  case "TRANSFER_SIGNED":
7871
- return { ...state, transfer: action.transfer, setupAuthorizationSessionId: null };
7997
+ return {
7998
+ ...state,
7999
+ transfer: action.transfer,
8000
+ signPayloadExpired: false,
8001
+ setupAuthorizationSessionId: null
8002
+ };
7872
8003
  case "TRANSFER_COMPLETED":
7873
8004
  return {
7874
8005
  ...state,
7875
8006
  transfer: action.transfer,
8007
+ signPayloadExpired: false,
7876
8008
  mobileFlow: false,
7877
8009
  deeplinkUri: null,
7878
8010
  setupAuthorizationSessionId: null
@@ -8017,6 +8149,11 @@ function applyAction(state, action) {
8017
8149
  return { ...state, loginRequested: false, error: null };
8018
8150
  case "ACKNOWLEDGE_WELCOME_BACK":
8019
8151
  return { ...state, welcomeBackAcknowledged: true };
8152
+ // Back from WalletPickerScreen. Pin the welcome screen (preserved by the
8153
+ // welcome-back sticky branch in resolvePhase) and clear the acknowledged
8154
+ // flag so the sticky gate treats the user as un-acknowledged again.
8155
+ case "RETURN_TO_WELCOME_BACK":
8156
+ return { ...state, welcomeBackAcknowledged: false, phase: { step: "welcome-back" } };
8020
8157
  case "SET_ERROR":
8021
8158
  return { ...state, error: action.error };
8022
8159
  case "AMOUNT_TOO_LOW":
@@ -10605,14 +10742,14 @@ var textStyle2 = (color, fontWeight) => ({
10605
10742
  });
10606
10743
 
10607
10744
  // src/deviceBiometricUnlockText.ts
10608
- var FALLBACK = "Biometric verification";
10745
+ var FALLBACK = "Passkey";
10609
10746
  function getDeviceBiometricUnlockText() {
10610
10747
  const ua = typeof navigator !== "undefined" && typeof navigator.userAgent === "string" ? navigator.userAgent : "";
10611
10748
  if (/iPhone|iPad|iPod/i.test(ua)) {
10612
10749
  return "Face ID";
10613
10750
  }
10614
10751
  if (/Android/i.test(ua)) {
10615
- return "Fingerprint or face unlock";
10752
+ return "Fingerprint or Face";
10616
10753
  }
10617
10754
  if (/Windows NT/i.test(ua)) {
10618
10755
  return "Windows Hello";
@@ -13151,14 +13288,34 @@ function SelectDepositSourceScreen({
13151
13288
  const requiresAuth = selectableOptions.filter(
13152
13289
  (opt) => opt.status && opt.status !== "AUTHORIZED"
13153
13290
  );
13154
- const orderedAccounts = (() => {
13155
- if (!selectedAccountId) return accounts;
13156
- const selected = accounts.find((a) => a.id === selectedAccountId);
13157
- if (!selected) return accounts;
13158
- return [selected, ...accounts.filter((a) => a.id !== selectedAccountId)];
13159
- })();
13291
+ const sectionsPerAccount = /* @__PURE__ */ new Map();
13292
+ for (const section of accounts) {
13293
+ sectionsPerAccount.set(section.id, (sectionsPerAccount.get(section.id) ?? 0) + 1);
13294
+ }
13160
13295
  const fallbackAccountId = selectedAccountId ?? accounts[0]?.id ?? null;
13161
13296
  const rowAccountId = (opt) => opt.accountId ?? fallbackAccountId;
13297
+ const rowMatchesSection = (opt, section) => {
13298
+ if (rowAccountId(opt) !== section.id) return false;
13299
+ if (opt.walletAddress != null) return opt.walletAddress === section.address;
13300
+ return (sectionsPerAccount.get(section.id) ?? 0) <= 1;
13301
+ };
13302
+ const orderedAccounts = (() => {
13303
+ const selectedOption = selectedWalletId ? tokenOptions.find((opt) => opt.walletId === selectedWalletId) : void 0;
13304
+ const selectedAddress = selectedOption?.walletAddress ?? null;
13305
+ const selectedSectionId = selectedOption?.accountId ?? selectedAccountId ?? null;
13306
+ if (!selectedSectionId) return accounts;
13307
+ const matchesSelected = (section) => {
13308
+ if (section.id !== selectedSectionId) return false;
13309
+ if (selectedAddress != null) return section.address === selectedAddress;
13310
+ return true;
13311
+ };
13312
+ const selectedIndex = accounts.findIndex(matchesSelected);
13313
+ if (selectedIndex < 0) return accounts;
13314
+ return [
13315
+ accounts[selectedIndex],
13316
+ ...accounts.filter((_, index) => index !== selectedIndex)
13317
+ ];
13318
+ })();
13162
13319
  const isSelected = (opt) => !!selectedTokenSymbol && !!selectedChainName && !!selectedWalletId && opt.symbol === selectedTokenSymbol && opt.chainName === selectedChainName && opt.walletId === selectedWalletId;
13163
13320
  const tokenOptionKey = (opt) => `${opt.accountId ?? ""}-${opt.chainName}-${opt.symbol}-${opt.walletId ?? ""}`;
13164
13321
  const hasPendingMobileSelection = pendingMobileSelection != null;
@@ -13243,8 +13400,8 @@ function SelectDepositSourceScreen({
13243
13400
  /* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { title: "Select source", onBack: onBack ?? onDone, onLogout }),
13244
13401
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-testid": "select-deposit-source-scroll-content", style: contentStyle12, children: [
13245
13402
  orderedAccounts.map((account) => {
13246
- const authRows = authorized.filter((opt) => rowAccountId(opt) === account.id);
13247
- const reqRows = requiresAuth.filter((opt) => rowAccountId(opt) === account.id);
13403
+ const authRows = authorized.filter((opt) => rowMatchesSection(opt, account));
13404
+ const reqRows = requiresAuth.filter((opt) => rowMatchesSection(opt, account));
13248
13405
  if (authRows.length === 0 && reqRows.length === 0) return null;
13249
13406
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: accountSectionStyle, children: [
13250
13407
  renderAccountHeader(account),
@@ -13259,7 +13416,7 @@ function SelectDepositSourceScreen({
13259
13416
  selected: !hasPendingMobileSelection && isSelected(opt),
13260
13417
  onClick: () => handleAuthorizedPick(opt)
13261
13418
  },
13262
- `auth-${opt.accountId ?? ""}-${opt.chainName}-${opt.symbol}-${opt.walletId ?? ""}`
13419
+ `auth-${opt.accountId ?? ""}-${opt.walletAddress ?? ""}-${opt.chainName}-${opt.symbol}-${opt.walletId ?? ""}`
13263
13420
  )),
13264
13421
  reqRows.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
13265
13422
  TokenSourceRow,
@@ -13272,12 +13429,12 @@ function SelectDepositSourceScreen({
13272
13429
  selected: hasPendingMobileSelection ? pendingMobileSelection?.key === tokenOptionKey(opt) : isSelected(opt),
13273
13430
  onClick: () => handleRequiresAuthPick(account, opt)
13274
13431
  },
13275
- `req-${opt.accountId ?? ""}-${opt.chainName}-${opt.symbol}-${opt.walletId ?? ""}`
13432
+ `req-${opt.accountId ?? ""}-${opt.walletAddress ?? ""}-${opt.chainName}-${opt.symbol}-${opt.walletId ?? ""}`
13276
13433
  ))
13277
13434
  ] })
13278
- ] }, `account-${account.id}`);
13435
+ ] }, `account-${account.id}-${account.address ?? ""}`);
13279
13436
  }),
13280
- (onSendManually || onAddProvider) && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: groupCardStyle(tokens.bgRecessed), children: [
13437
+ (onSendManually || onAddProvider) && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...groupCardStyle(tokens.bgRecessed), marginTop: 8 }, children: [
13281
13438
  onSendManually && /* @__PURE__ */ jsxRuntime.jsx(
13282
13439
  ActionRow,
13283
13440
  {
@@ -13561,14 +13718,16 @@ function DepositScreen({
13561
13718
  const formattedBalance = selectedTokenSymbol != null ? `$${formatUsdTwoDecimals2(availableBalance)}` : void 0;
13562
13719
  const tokenAriaLabel = selectedTokenSymbol && selectedChainName ? `Selected token: ${selectedTokenSymbol} on ${selectedChainName}${formattedBalance ? `, ${formattedBalance}` : ""}` : selectedTokenSymbol ? `Selected token: ${selectedTokenSymbol}${formattedBalance ? `, ${formattedBalance}` : ""}` : "Select token";
13563
13720
  if (tokenPickerOpen && canOpenInlineSheet) {
13564
- const depositSourceAccounts = (accounts ?? []).map((a) => {
13565
- const preferred = getPreferredDepositWallet(a, amount);
13566
- return {
13567
- id: a.id,
13568
- name: a.name,
13569
- logoURI: a.logoURI,
13570
- address: preferred ? getWalletAddress(preferred) : null
13571
- };
13721
+ const depositSourceAccounts = (accounts ?? []).flatMap((a) => {
13722
+ const seen = /* @__PURE__ */ new Set();
13723
+ const sections = [];
13724
+ for (const wallet of getAddressableWallets(a)) {
13725
+ const address = getWalletAddress(wallet);
13726
+ if (!address || seen.has(address)) continue;
13727
+ seen.add(address);
13728
+ sections.push({ id: a.id, name: a.name, logoURI: a.logoURI, address });
13729
+ }
13730
+ return sections;
13572
13731
  });
13573
13732
  return /* @__PURE__ */ jsxRuntime.jsx(
13574
13733
  SelectDepositSourceScreen,
@@ -13632,7 +13791,6 @@ function DepositScreen({
13632
13791
  }
13633
13792
  };
13634
13793
  const presetsInFooter = mobileEntryWithKeypad;
13635
- const showHeroPresets = isEntryMode && isDesktop;
13636
13794
  const showFooterPresets = presetsInFooter;
13637
13795
  const presetsRow = onPreset ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: entryPresetsRowStyle, role: "group", "aria-label": "Preset amounts", children: presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
13638
13796
  "button",
@@ -13760,8 +13918,7 @@ function DepositScreen({
13760
13918
  }
13761
13919
  )
13762
13920
  }
13763
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: redesignNoFeesStyle(tokens.text), children: "No fees" }) }),
13764
- showHeroPresets && presetsRow
13921
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: redesignNoFeesStyle(tokens.text), children: "No fees" }) })
13765
13922
  ] }),
13766
13923
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: bannerSlotStyle2, children: mobileEntryWithKeypad ? null : showLowFunds ? /* @__PURE__ */ jsxRuntime.jsx(
13767
13924
  NotificationBanner,
@@ -14108,7 +14265,7 @@ function SuccessScreen({
14108
14265
  return /* @__PURE__ */ jsxRuntime.jsxs(
14109
14266
  ScreenLayout,
14110
14267
  {
14111
- footer: /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: onDone ? /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onClick: onDone, children: succeeded ? "Done" : "Try again" }) : returnMessage ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: returnMessageStyle(tokens.textSecondary), children: returnMessage }) : null }),
14268
+ footer: /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: onDone ? /* @__PURE__ */ jsxRuntime.jsx(PrimaryButton, { onClick: onDone, children: succeeded ? "Close" : "Try again" }) : returnMessage ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: returnMessageStyle(tokens.textSecondary), children: returnMessage }) : null }),
14112
14269
  children: [
14113
14270
  /* @__PURE__ */ jsxRuntime.jsx(
14114
14271
  ScreenHeader,
@@ -14127,7 +14284,7 @@ function SuccessScreen({
14127
14284
  style: illustrationStyle5
14128
14285
  }
14129
14286
  ),
14130
- /* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle8(tokens.text), children: "You\u2019re all set" })
14287
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle8(tokens.text), children: "Deposit complete" })
14131
14288
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: screenContentStyle, children: [
14132
14289
  /* @__PURE__ */ jsxRuntime.jsx(IconCircle, { variant: "error", size: 64, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z", fill: tokens.error }) }) }),
14133
14290
  /* @__PURE__ */ jsxRuntime.jsx("h2", { style: failureHeadingStyle(tokens.text), children: "Transfer failed" }),
@@ -14663,6 +14820,7 @@ function TransferStatusLayout({
14663
14820
  retryLabel = "Retry wallet prompt",
14664
14821
  retryAfterDelay = true,
14665
14822
  showRetryOnError = false,
14823
+ errorVariant = "error",
14666
14824
  heading,
14667
14825
  visibleError = error,
14668
14826
  children
@@ -14683,7 +14841,7 @@ function TransferStatusLayout({
14683
14841
  onLogout && /* @__PURE__ */ jsxRuntime.jsx("div", { style: menuOverlayStyle, children: /* @__PURE__ */ jsxRuntime.jsx(SettingsMenu, { onLogout }) }),
14684
14842
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: contentStyle13, children: [
14685
14843
  /* @__PURE__ */ jsxRuntime.jsx("h2", { style: headingStyle10(tokens.text), children: heading }),
14686
- visibleError && /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBannerStyle7(tokens), children: visibleError }),
14844
+ visibleError && (errorVariant === "info" ? /* @__PURE__ */ jsxRuntime.jsx(NotificationBanner, { title: "Signing window expired", description: visibleError }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: errorBannerStyle7(tokens), children: visibleError })),
14687
14845
  children
14688
14846
  ] })
14689
14847
  ] })
@@ -14792,6 +14950,7 @@ function DepositTransferStatusScreen({
14792
14950
  phase,
14793
14951
  error,
14794
14952
  visibleError = error,
14953
+ errorVariant,
14795
14954
  onLogout,
14796
14955
  onRetry
14797
14956
  }) {
@@ -14802,6 +14961,7 @@ function DepositTransferStatusScreen({
14802
14961
  phase,
14803
14962
  error,
14804
14963
  visibleError,
14964
+ errorVariant,
14805
14965
  onLogout,
14806
14966
  onRetry,
14807
14967
  retryLabel: "Retry",
@@ -16666,7 +16826,12 @@ function buildWalletPickerScreenProps({
16666
16826
  onPrepareProvider: handlers.onPrepareProvider,
16667
16827
  onSelectProvider: handlers.onSelectProvider,
16668
16828
  onSelectWalletConnectWallet: handlers.onSelectWalletConnectWallet,
16669
- onBack: !flow.authenticated ? flow.onBack : () => handlers.onSetPhase({ step: "deposit" }),
16829
+ // Back target depends on the user's state:
16830
+ // • guest → host close (flow.onBack)
16831
+ // • authenticated with a linked (ACTIVE) wallet → DepositScreen
16832
+ // • authenticated, no linked wallet, full-widget → WelcomeBackScreen
16833
+ // • authenticated, no linked wallet, non-full-widget → host close
16834
+ onBack: !flow.authenticated ? flow.onBack : hasActiveWallet(flow.state.accounts) ? () => handlers.onSetPhase({ step: "deposit" }) : flow.state.enableFullWidget ? handlers.onReturnToWelcomeBack : flow.onBack,
16670
16835
  onLogout: flow.authenticated ? handlers.onLogout : void 0,
16671
16836
  isDesktop: flow.isDesktop,
16672
16837
  directLinkCards: isMobile,
@@ -16869,6 +17034,7 @@ function buildDepositScreenProps({
16869
17034
  tokenAddress: source.address,
16870
17035
  chainId: chain?.commonId ?? void 0,
16871
17036
  accountId: account.id,
17037
+ walletAddress: getWalletAddress(wallet) ?? void 0,
16872
17038
  logoURI: source.token.logoURI
16873
17039
  });
16874
17040
  }
@@ -16986,14 +17152,18 @@ function buildProcessingScreenProps({
16986
17152
  }) {
16987
17153
  const bestKnownTransfer = remote.pollingTransfer ?? flow.state.transfer;
16988
17154
  const transferStatus = bestKnownTransfer?.status;
16989
- const canRetryDepositSigning = remote.transferSigningError != null && isTransferSignable(bestKnownTransfer);
16990
- const error = flow.state.error || remote.authExecutorError || remote.transferSigningError || remote.pollingError;
16991
- const visibleError = remote.transferSigningPasskeyDismissed === true && !flow.state.error && !remote.authExecutorError ? remote.pollingError : error;
17155
+ const signExpired = flow.state.signPayloadExpired === true;
17156
+ const canRetryDepositSigning = (remote.transferSigningError != null || signExpired) && isTransferSignable(bestKnownTransfer);
17157
+ const error = signExpired ? flow.state.error : flow.state.error || remote.authExecutorError || remote.transferSigningError || remote.pollingError;
17158
+ const visibleError = signExpired ? flow.state.error : remote.transferSigningPasskeyDismissed === true && !flow.state.error && !remote.authExecutorError ? remote.pollingError : error;
16992
17159
  const transferPhase = flow.state.creatingTransfer ? "creating" : transferStatus === "SENDING" || transferStatus === "SENT" || transferStatus === "COMPLETED" ? "sent" : transferStatus === "AUTHORIZED" ? "submitting" : "signing";
16993
17160
  return {
16994
17161
  phase: transferPhase,
16995
17162
  error,
16996
17163
  visibleError,
17164
+ // An expired SVM signing window is a benign, retryable condition — present it
17165
+ // as an informational banner rather than the alarming red error banner.
17166
+ errorVariant: signExpired ? "info" : "error",
16997
17167
  onRetry: canRetryDepositSigning ? handlers.onRetryTransferSigning : void 0,
16998
17168
  onLogout: handlers.onLogout
16999
17169
  };
@@ -17130,6 +17300,7 @@ function StepRendererContent({
17130
17300
  phase: processingProps.phase,
17131
17301
  error: processingProps.error,
17132
17302
  visibleError: processingProps.visibleError,
17303
+ errorVariant: processingProps.errorVariant,
17133
17304
  onRetry: processingProps.onRetry,
17134
17305
  onLogout: processingProps.onLogout
17135
17306
  }
@@ -17486,6 +17657,7 @@ function resolveStandardTransferSource({
17486
17657
  }
17487
17658
 
17488
17659
  // src/hooks/useTransferHandlers.ts
17660
+ var SIGN_PAYLOAD_EXPIRED_MESSAGE = "This transfer must be signed within 20 seconds. Tap Retry to try again.";
17489
17661
  function useTransferHandlers(deps) {
17490
17662
  const {
17491
17663
  dispatch,
@@ -17509,6 +17681,7 @@ function useTransferHandlers(deps) {
17509
17681
  selectedTokenSymbol,
17510
17682
  quoteId,
17511
17683
  transfer,
17684
+ signPayloadExpired,
17512
17685
  accounts,
17513
17686
  chains
17514
17687
  } = deps;
@@ -17639,6 +17812,10 @@ function useTransferHandlers(deps) {
17639
17812
  if (isTransferSigningPasskeyDismissedError(err)) {
17640
17813
  return;
17641
17814
  }
17815
+ if (isSvmSignExpiredError(err)) {
17816
+ dispatch({ type: "SIGN_PAYLOAD_EXPIRED", error: SIGN_PAYLOAD_EXPIRED_MESSAGE });
17817
+ return;
17818
+ }
17642
17819
  captureException(err);
17643
17820
  const msg = err instanceof Error ? err.message : "Transfer failed";
17644
17821
  dispatch({ type: "PAY_ERROR", error: msg });
@@ -17676,6 +17853,10 @@ function useTransferHandlers(deps) {
17676
17853
  dispatch({ type: "CONFIRM_SIGN_SUCCESS", transfer: signedTransfer });
17677
17854
  polling.startPolling(t.id);
17678
17855
  } catch (err) {
17856
+ if (isSvmSignExpiredError(err)) {
17857
+ dispatch({ type: "SIGN_PAYLOAD_EXPIRED", error: SIGN_PAYLOAD_EXPIRED_MESSAGE });
17858
+ return;
17859
+ }
17679
17860
  captureException(err);
17680
17861
  const msg = err instanceof Error ? err.message : "Failed to sign transfer";
17681
17862
  dispatch({ type: "SET_ERROR", error: msg });
@@ -17685,9 +17866,19 @@ function useTransferHandlers(deps) {
17685
17866
  const handleRetryTransferSigning = react.useCallback(async () => {
17686
17867
  const t = polling.transfer ?? transfer;
17687
17868
  if (!isTransferSignable(t)) return;
17869
+ const wasExpired = signPayloadExpired;
17688
17870
  try {
17689
17871
  dispatch({ type: "SET_ERROR", error: null });
17690
17872
  processingStartedAtRef.current = Date.now();
17873
+ if (wasExpired) {
17874
+ const refreshed = await transferSigning.regenerateSignPayload(t.id);
17875
+ const signedTransfer2 = await transferSigning.signTransfer(t.id, {
17876
+ knownSignPayload: refreshed.signPayload
17877
+ });
17878
+ dispatch({ type: "TRANSFER_SIGNED", transfer: signedTransfer2 });
17879
+ polling.startPolling(t.id);
17880
+ return;
17881
+ }
17691
17882
  const signedTransfer = await transferSigning.signTransfer(t.id);
17692
17883
  dispatch({ type: "TRANSFER_SIGNED", transfer: signedTransfer });
17693
17884
  polling.startPolling(t.id);
@@ -17695,12 +17886,16 @@ function useTransferHandlers(deps) {
17695
17886
  if (isTransferSigningPasskeyDismissedError(err)) {
17696
17887
  return;
17697
17888
  }
17889
+ if (isSvmSignExpiredError(err)) {
17890
+ dispatch({ type: "SIGN_PAYLOAD_EXPIRED", error: SIGN_PAYLOAD_EXPIRED_MESSAGE });
17891
+ return;
17892
+ }
17698
17893
  captureException(err);
17699
17894
  const msg = err instanceof Error ? err.message : "Failed to sign transfer";
17700
17895
  dispatch({ type: "PAY_ERROR", error: msg });
17701
17896
  onError?.(msg);
17702
17897
  }
17703
- }, [transfer, polling.transfer, polling.startPolling, transferSigning, onError, dispatch]);
17898
+ }, [transfer, polling.transfer, polling.startPolling, transferSigning, onError, dispatch, signPayloadExpired]);
17704
17899
  return {
17705
17900
  reloadAccounts,
17706
17901
  handlePay,
@@ -17854,6 +18049,9 @@ async function replaceOpenProviderForAccountSwitch(input) {
17854
18049
  if (input.chainId != null) {
17855
18050
  result.chainId = `0x${input.chainId.toString(16)}`;
17856
18051
  }
18052
+ if (input.userSolanaWalletPubkey) {
18053
+ result.userSolanaWalletPubkey = input.userSolanaWalletPubkey;
18054
+ }
17857
18055
  const updated = await reportActionCompletion(
17858
18056
  input.apiBaseUrl,
17859
18057
  openProvider.id,
@@ -18849,7 +19047,8 @@ function useProviderHandlers(deps) {
18849
19047
  apiBaseUrl,
18850
19048
  sessionId,
18851
19049
  accounts: change.accounts,
18852
- chainId: change.chainId
19050
+ chainId: change.chainId,
19051
+ ...change.chainId == null ? { userSolanaWalletPubkey: change.accounts[0] } : {}
18853
19052
  });
18854
19053
  if (outcome.status === "success") {
18855
19054
  dispatch({ type: "CLEAR_SETUP_DEPOSIT_TOKEN" });
@@ -19858,6 +20057,31 @@ function useWalletAccountSwitchEffect(deps) {
19858
20057
  });
19859
20058
  }, [enabled, isDesktop, address, chainId, connectorId, addresses, onAccountChanged]);
19860
20059
  }
20060
+ function useSolanaAccountSwitchEffect(deps) {
20061
+ const { enabled = true, onAccountChanged } = deps;
20062
+ const baselineRef = react.useRef(null);
20063
+ react.useEffect(() => {
20064
+ if (!enabled) {
20065
+ baselineRef.current = null;
20066
+ return;
20067
+ }
20068
+ const unsubscribe = subscribeSolanaAccountChange((pubkey) => {
20069
+ if (baselineRef.current === pubkey) {
20070
+ return;
20071
+ }
20072
+ const previous = baselineRef.current;
20073
+ baselineRef.current = pubkey;
20074
+ void onAccountChanged({
20075
+ previousAddress: previous,
20076
+ nextAddress: pubkey,
20077
+ connectorId: "phantom",
20078
+ chainId: null,
20079
+ accounts: [pubkey]
20080
+ });
20081
+ });
20082
+ return unsubscribe;
20083
+ }, [enabled, onAccountChanged]);
20084
+ }
19861
20085
  function usePersistAmountToActiveSession({
19862
20086
  apiBaseUrl,
19863
20087
  accounts,
@@ -20041,6 +20265,7 @@ function BlinkPaymentInner({
20041
20265
  selectedTokenSymbol: state.selectedTokenSymbol,
20042
20266
  quoteId: depositFee.quoteId,
20043
20267
  transfer: state.transfer,
20268
+ signPayloadExpired: state.signPayloadExpired,
20044
20269
  accounts: state.accounts,
20045
20270
  chains: state.chains
20046
20271
  });
@@ -20110,6 +20335,10 @@ function BlinkPaymentInner({
20110
20335
  isDesktop,
20111
20336
  onAccountChanged: onWalletAccountChanged
20112
20337
  });
20338
+ useSolanaAccountSwitchEffect({
20339
+ enabled: accountSwitchListenerArmed && isDesktop,
20340
+ onAccountChanged: onWalletAccountChanged
20341
+ });
20113
20342
  const clearLocalSessionArtifacts = react.useCallback(() => {
20114
20343
  popupAuthRef.current = null;
20115
20344
  clearPopupAuth();
@@ -20415,6 +20644,7 @@ function BlinkPaymentInner({
20415
20644
  onLogin: () => dispatch({ type: "REQUEST_LOGIN" }),
20416
20645
  onCancelLogin: () => dispatch({ type: "CANCEL_LOGIN_REQUEST" }),
20417
20646
  onAcknowledgeWelcomeBack: () => dispatch({ type: "ACKNOWLEDGE_WELCOME_BACK" }),
20647
+ onReturnToWelcomeBack: () => dispatch({ type: "RETURN_TO_WELCOME_BACK" }),
20418
20648
  onSetDepositToken: handleSetDepositToken,
20419
20649
  onConfirmSetupDeposit: handleConfirmSetupDeposit,
20420
20650
  onAmountInput: (value) => dispatch({ type: "SET_AMOUNT_INPUT", value }),
@@ -20597,6 +20827,7 @@ exports.useAuthorizationOrchestrator = useAuthorizationOrchestrator;
20597
20827
  exports.useBlinkConfig = useBlinkConfig;
20598
20828
  exports.useBlinkDebugLog = useBlinkDebugLog;
20599
20829
  exports.useBlinkDepositAmount = useBlinkDepositAmount;
20830
+ exports.useSolanaAccountSwitchEffect = useSolanaAccountSwitchEffect;
20600
20831
  exports.useTransferPolling = useTransferPolling;
20601
20832
  exports.useTransferSigning = useTransferSigning;
20602
20833
  //# sourceMappingURL=index.cjs.map