@swype-org/react-sdk 0.2.226 → 0.2.232

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
@@ -1616,6 +1616,93 @@ __export(api_exports, {
1616
1616
  updateUserConfigBySession: () => updateUserConfigBySession,
1617
1617
  waitForActionTransactionReceipt: () => waitForActionTransactionReceipt
1618
1618
  });
1619
+ var DEBUG_BUFFER_CAPACITY = 200;
1620
+ var nextId = 1;
1621
+ var entries = [];
1622
+ var listeners = /* @__PURE__ */ new Set();
1623
+ function notify() {
1624
+ for (const listener of listeners) {
1625
+ try {
1626
+ listener();
1627
+ } catch (err) {
1628
+ console.error("[blink-sdk][debug-log] listener threw:", err);
1629
+ }
1630
+ }
1631
+ }
1632
+ function appendDebug(level, message, data) {
1633
+ const entry = {
1634
+ id: nextId++,
1635
+ ts: Date.now(),
1636
+ level,
1637
+ message,
1638
+ data
1639
+ };
1640
+ const next = entries.length >= DEBUG_BUFFER_CAPACITY ? entries.slice(entries.length - DEBUG_BUFFER_CAPACITY + 1) : entries.slice();
1641
+ next.push(entry);
1642
+ entries = next;
1643
+ const prefix = "[blink-sdk][debug]";
1644
+ const sink = level === "error" ? console.error : level === "warn" ? console.warn : console.info;
1645
+ if (data !== void 0) {
1646
+ sink(`${prefix} ${message}`, data);
1647
+ } else {
1648
+ sink(`${prefix} ${message}`);
1649
+ }
1650
+ notify();
1651
+ }
1652
+ function subscribeDebug(listener) {
1653
+ listeners.add(listener);
1654
+ return () => {
1655
+ listeners.delete(listener);
1656
+ };
1657
+ }
1658
+ function getDebugEntries() {
1659
+ return entries;
1660
+ }
1661
+ function clearDebugEntries() {
1662
+ entries = [];
1663
+ notify();
1664
+ }
1665
+ function useBlinkDebugLog() {
1666
+ return react.useSyncExternalStore(subscribeDebug, getDebugEntries, getDebugEntries);
1667
+ }
1668
+
1669
+ // src/fetchWithRetry.ts
1670
+ var DEFAULT_MAX_RETRIES = 3;
1671
+ var DEFAULT_BASE_DELAY_MS = 500;
1672
+ var DEFAULT_MAX_JITTER_MS = 200;
1673
+ function isNetworkTypeError(err) {
1674
+ return err instanceof TypeError && /fetch|network|load failed/i.test(err.message);
1675
+ }
1676
+ async function fetchWithRetry(input, init, options) {
1677
+ const maxRetries = DEFAULT_MAX_RETRIES;
1678
+ const baseDelayMs = DEFAULT_BASE_DELAY_MS;
1679
+ const maxJitterMs = DEFAULT_MAX_JITTER_MS;
1680
+ const label = String(input).replace(/https?:\/\/[^/]+/, "");
1681
+ let lastError;
1682
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
1683
+ try {
1684
+ return await fetch(input, init);
1685
+ } catch (err) {
1686
+ lastError = err;
1687
+ if (!isNetworkTypeError(err)) {
1688
+ throw err;
1689
+ }
1690
+ if (attempt < maxRetries) {
1691
+ const delay = baseDelayMs * Math.pow(2, attempt) + Math.random() * maxJitterMs;
1692
+ appendDebug("warn", `fetchWithRetry: network error, retrying ${label}`, {
1693
+ attempt: attempt + 1,
1694
+ maxRetries,
1695
+ delayMs: Math.round(delay),
1696
+ error: err instanceof Error ? err.message : String(err)
1697
+ });
1698
+ await new Promise((resolve) => setTimeout(resolve, delay));
1699
+ }
1700
+ }
1701
+ }
1702
+ throw lastError;
1703
+ }
1704
+
1705
+ // src/api.ts
1619
1706
  async function throwApiError(res) {
1620
1707
  const body = await res.json().catch(() => null);
1621
1708
  const detail = body?.error ?? body;
@@ -1628,13 +1715,13 @@ async function fetchProviders(apiBaseUrl, token) {
1628
1715
  if (token) {
1629
1716
  headers.Authorization = `Bearer ${token}`;
1630
1717
  }
1631
- const res = await fetch(`${apiBaseUrl}/v1/providers`, { headers });
1718
+ const res = await fetchWithRetry(`${apiBaseUrl}/v1/providers`, { headers });
1632
1719
  if (!res.ok) await throwApiError(res);
1633
1720
  const data = await res.json();
1634
1721
  return data.items;
1635
1722
  }
1636
1723
  async function fetchChains(apiBaseUrl, token) {
1637
- const res = await fetch(`${apiBaseUrl}/v1/chains`, {
1724
+ const res = await fetchWithRetry(`${apiBaseUrl}/v1/chains`, {
1638
1725
  headers: { Authorization: `Bearer ${token}` }
1639
1726
  });
1640
1727
  if (!res.ok) await throwApiError(res);
@@ -1643,7 +1730,7 @@ async function fetchChains(apiBaseUrl, token) {
1643
1730
  }
1644
1731
  async function fetchAccounts(apiBaseUrl, token, credentialId) {
1645
1732
  const params = new URLSearchParams({ credentialId });
1646
- const res = await fetch(`${apiBaseUrl}/v1/accounts?${params.toString()}`, {
1733
+ const res = await fetchWithRetry(`${apiBaseUrl}/v1/accounts?${params.toString()}`, {
1647
1734
  headers: { Authorization: `Bearer ${token}` }
1648
1735
  });
1649
1736
  if (!res.ok) await throwApiError(res);
@@ -1652,7 +1739,7 @@ async function fetchAccounts(apiBaseUrl, token, credentialId) {
1652
1739
  }
1653
1740
  async function fetchAccount(apiBaseUrl, token, accountId, credentialId) {
1654
1741
  const params = new URLSearchParams({ credentialId });
1655
- const res = await fetch(`${apiBaseUrl}/v1/accounts/${accountId}?${params.toString()}`, {
1742
+ const res = await fetchWithRetry(`${apiBaseUrl}/v1/accounts/${accountId}?${params.toString()}`, {
1656
1743
  headers: { Authorization: `Bearer ${token}` }
1657
1744
  });
1658
1745
  if (!res.ok) await throwApiError(res);
@@ -1794,7 +1881,7 @@ async function postTransferQuote(apiBaseUrl, bearerToken, params) {
1794
1881
  return await res.json();
1795
1882
  }
1796
1883
  async function fetchMerchantPublicKey(apiBaseUrl, merchantId) {
1797
- const res = await fetch(
1884
+ const res = await fetchWithRetry(
1798
1885
  `${apiBaseUrl}/v1/merchants/${encodeURIComponent(merchantId)}/public-key`
1799
1886
  );
1800
1887
  if (!res.ok) await throwApiError(res);
@@ -1804,7 +1891,7 @@ async function fetchTransfer(apiBaseUrl, token, transferId, authorizationSession
1804
1891
  if (!token && !authorizationSessionToken) {
1805
1892
  throw new Error("Missing auth credentials for transfer fetch.");
1806
1893
  }
1807
- const res = await fetch(`${apiBaseUrl}/v1/transfers/${transferId}`, {
1894
+ const res = await fetchWithRetry(`${apiBaseUrl}/v1/transfers/${transferId}`, {
1808
1895
  headers: {
1809
1896
  ...token ? { Authorization: `Bearer ${token}` } : {},
1810
1897
  ...authorizationSessionToken ? { "x-authorization-session-token": authorizationSessionToken } : {}
@@ -1832,14 +1919,14 @@ async function signTransfer(apiBaseUrl, token, transferId, signedTransfer, autho
1832
1919
  return await res.json();
1833
1920
  }
1834
1921
  async function fetchAuthorizationSession(apiBaseUrl, sessionId) {
1835
- const res = await fetch(
1922
+ const res = await fetchWithRetry(
1836
1923
  `${apiBaseUrl}/v1/authorization-sessions/${sessionId}`
1837
1924
  );
1838
1925
  if (!res.ok) await throwApiError(res);
1839
1926
  return await res.json();
1840
1927
  }
1841
1928
  async function fetchAuthorizationSessionByToken(apiBaseUrl, token) {
1842
- const res = await fetch(
1929
+ const res = await fetchWithRetry(
1843
1930
  `${apiBaseUrl}/v1/authorization-sessions?token=${encodeURIComponent(token)}`
1844
1931
  );
1845
1932
  if (!res.ok) await throwApiError(res);
@@ -1857,7 +1944,7 @@ async function registerPasskey(apiBaseUrl, token, credentialId, publicKey) {
1857
1944
  if (!res.ok) await throwApiError(res);
1858
1945
  }
1859
1946
  async function reportPasskeyActivity(apiBaseUrl, token, credentialId) {
1860
- const res = await fetch(`${apiBaseUrl}/v1/users/config/passkey`, {
1947
+ const res = await fetchWithRetry(`${apiBaseUrl}/v1/users/config/passkey`, {
1861
1948
  method: "PATCH",
1862
1949
  headers: {
1863
1950
  "Content-Type": "application/json",
@@ -1868,7 +1955,7 @@ async function reportPasskeyActivity(apiBaseUrl, token, credentialId) {
1868
1955
  if (!res.ok) await throwApiError(res);
1869
1956
  }
1870
1957
  async function fetchUserConfig(apiBaseUrl, token) {
1871
- const res = await fetch(`${apiBaseUrl}/v1/users/config`, {
1958
+ const res = await fetchWithRetry(`${apiBaseUrl}/v1/users/config`, {
1872
1959
  headers: { Authorization: `Bearer ${token}` }
1873
1960
  });
1874
1961
  if (!res.ok) await throwApiError(res);
@@ -1940,12 +2027,12 @@ async function createManualTransfer(apiBaseUrl, params) {
1940
2027
  return await res.json();
1941
2028
  }
1942
2029
  async function fetchManualTransferSession(apiBaseUrl, sessionId) {
1943
- const res = await fetch(`${apiBaseUrl}/v1/manual-transfers/${sessionId}`);
2030
+ const res = await fetchWithRetry(`${apiBaseUrl}/v1/manual-transfers/${sessionId}`);
1944
2031
  if (!res.ok) await throwApiError(res);
1945
2032
  return await res.json();
1946
2033
  }
1947
2034
  async function reportActionCompletion(apiBaseUrl, actionId, result) {
1948
- const res = await fetch(
2035
+ const res = await fetchWithRetry(
1949
2036
  `${apiBaseUrl}/v1/authorization-actions/${actionId}`,
1950
2037
  {
1951
2038
  method: "PATCH",
@@ -1969,7 +2056,7 @@ async function waitForActionTransactionReceipt(apiBaseUrl, actionId, txHash) {
1969
2056
  return await res.json();
1970
2057
  }
1971
2058
  async function probeActionCompletion(apiBaseUrl, actionId) {
1972
- const res = await fetch(
2059
+ const res = await fetchWithRetry(
1973
2060
  `${apiBaseUrl}/v1/authorization-actions/${actionId}`,
1974
2061
  {
1975
2062
  method: "PATCH",
@@ -2809,55 +2896,6 @@ async function pollWalletCallsStatus(walletClient, callsId, options = {}) {
2809
2896
  `Batch transaction did not confirm within ${maxAttempts * pollIntervalMs}ms. Last wallet status: ${lastStatusStr}. Please try again.`
2810
2897
  );
2811
2898
  }
2812
- var DEBUG_BUFFER_CAPACITY = 200;
2813
- var nextId = 1;
2814
- var entries = [];
2815
- var listeners = /* @__PURE__ */ new Set();
2816
- function notify() {
2817
- for (const listener of listeners) {
2818
- try {
2819
- listener();
2820
- } catch (err) {
2821
- console.error("[blink-sdk][debug-log] listener threw:", err);
2822
- }
2823
- }
2824
- }
2825
- function appendDebug(level, message, data) {
2826
- const entry = {
2827
- id: nextId++,
2828
- ts: Date.now(),
2829
- level,
2830
- message,
2831
- data
2832
- };
2833
- const next = entries.length >= DEBUG_BUFFER_CAPACITY ? entries.slice(entries.length - DEBUG_BUFFER_CAPACITY + 1) : entries.slice();
2834
- next.push(entry);
2835
- entries = next;
2836
- const prefix = "[blink-sdk][debug]";
2837
- const sink = level === "error" ? console.error : level === "warn" ? console.warn : console.info;
2838
- if (data !== void 0) {
2839
- sink(`${prefix} ${message}`, data);
2840
- } else {
2841
- sink(`${prefix} ${message}`);
2842
- }
2843
- notify();
2844
- }
2845
- function subscribeDebug(listener) {
2846
- listeners.add(listener);
2847
- return () => {
2848
- listeners.delete(listener);
2849
- };
2850
- }
2851
- function getDebugEntries() {
2852
- return entries;
2853
- }
2854
- function clearDebugEntries() {
2855
- entries = [];
2856
- notify();
2857
- }
2858
- function useBlinkDebugLog() {
2859
- return react.useSyncExternalStore(subscribeDebug, getDebugEntries, getDebugEntries);
2860
- }
2861
2899
 
2862
2900
  // src/withWatchdog.ts
2863
2901
  var DEFAULT_WATCHDOG_INTERVAL_MS = 2e4;
@@ -3560,6 +3598,10 @@ function advanceTrackedEvmNonce(nonceTracker, trackerKey, nextNonce) {
3560
3598
  nonceTracker.set(trackerKey, current == null ? nextNonce : Math.max(current, nextNonce));
3561
3599
  }
3562
3600
  async function waitForWalletClient(wagmiConfig, params = {}) {
3601
+ const initialAccount = core.getAccount(wagmiConfig);
3602
+ if (!initialAccount.isConnected) {
3603
+ await core.reconnect(wagmiConfig).catch(() => []);
3604
+ }
3563
3605
  for (let i = 0; i < WALLET_CLIENT_MAX_ATTEMPTS; i++) {
3564
3606
  try {
3565
3607
  const account = core.getAccount(wagmiConfig);
@@ -6153,7 +6195,7 @@ function assertLinkedTransferBridgeExecuted(params) {
6153
6195
  `Transfer session ${transferSessionId} has no EXECUTE_BRIDGE action. The bridge transaction was never presented to the wallet.`
6154
6196
  );
6155
6197
  }
6156
- if (!completedIds.has(bridgeAction.id)) {
6198
+ if (!completedIds.has(bridgeAction.id) && bridgeAction.status !== "COMPLETED") {
6157
6199
  throw new Error(
6158
6200
  `Deposit flow finished without executing the bridge transaction (action ${bridgeAction.id} on session ${transferSessionId}).`
6159
6201
  );
@@ -6161,6 +6203,47 @@ function assertLinkedTransferBridgeExecuted(params) {
6161
6203
  }
6162
6204
  }
6163
6205
 
6206
+ // src/authorizationOrchestratorOrdering.ts
6207
+ function getPendingActions2(session, completedIds) {
6208
+ return session.actions.filter((a) => a.status === "PENDING" && !completedIds.has(a.id)).sort((a, b) => a.orderIndex - b.orderIndex);
6209
+ }
6210
+ function isSvmSetupAction(action) {
6211
+ if (action.type === "APPROVE_SPL") {
6212
+ return true;
6213
+ }
6214
+ return action.type === "OPEN_PROVIDER" && action.metadata?.chainFamily === "svm";
6215
+ }
6216
+ function isSvmTransferBridgeAction(action) {
6217
+ return action.type === "EXECUTE_BRIDGE" && action.metadata?.chainFamily === "svm";
6218
+ }
6219
+ function isEvmBridgeAction(action) {
6220
+ return action.type === "EXECUTE_BRIDGE" && action.metadata?.chainFamily !== "svm";
6221
+ }
6222
+ function isEvmAccountAction(action) {
6223
+ return action.type === "SIGN_PERMIT2" || action.type === "APPROVE_PERMIT2";
6224
+ }
6225
+ function getMergedPending(sessions, completedIds) {
6226
+ const allActions = [];
6227
+ for (const { session } of sessions) {
6228
+ allActions.push(...getPendingActions2(session, completedIds));
6229
+ }
6230
+ const hasPendingSvmSetupAction = allActions.some((action) => isSvmSetupAction(action));
6231
+ const hasPendingEvmAccountAction = allActions.some((action) => isEvmAccountAction(action));
6232
+ return allActions.sort((a, b) => {
6233
+ const leftIsDeferredSvmBridge = hasPendingSvmSetupAction && isSvmTransferBridgeAction(a);
6234
+ const rightIsDeferredSvmBridge = hasPendingSvmSetupAction && isSvmTransferBridgeAction(b);
6235
+ if (leftIsDeferredSvmBridge !== rightIsDeferredSvmBridge) {
6236
+ return leftIsDeferredSvmBridge ? 1 : -1;
6237
+ }
6238
+ const leftIsDeferredEvmBridge = hasPendingEvmAccountAction && isEvmBridgeAction(a);
6239
+ const rightIsDeferredEvmBridge = hasPendingEvmAccountAction && isEvmBridgeAction(b);
6240
+ if (leftIsDeferredEvmBridge !== rightIsDeferredEvmBridge) {
6241
+ return leftIsDeferredEvmBridge ? 1 : -1;
6242
+ }
6243
+ return a.orderIndex - b.orderIndex;
6244
+ });
6245
+ }
6246
+
6164
6247
  // src/hooks/useAuthorizationOrchestrator.ts
6165
6248
  var ACTION_POLL_INTERVAL_MS2 = 500;
6166
6249
  var ACTION_POLL_MAX_RETRIES2 = 20;
@@ -6174,6 +6257,7 @@ function useAuthorizationOrchestrator(deps) {
6174
6257
  const { authExecutor } = deps;
6175
6258
  const pendingSessionIdsRef = react.useRef([]);
6176
6259
  const lastRunRef = react.useRef(null);
6260
+ const inflightRunRef = react.useRef(null);
6177
6261
  const [pendingSelectSourceAction, setPendingSelectSourceAction] = react.useState(null);
6178
6262
  const [pendingOneTapAction, setPendingOneTapAction] = react.useState(null);
6179
6263
  const [orchestratorCompleted, setOrchestratorCompleted] = react.useState(false);
@@ -6249,7 +6333,7 @@ function useAuthorizationOrchestrator(deps) {
6249
6333
  }
6250
6334
  oneTapPauseRequestedRef.current = false;
6251
6335
  }, []);
6252
- const run = react.useCallback(
6336
+ const runInternal = react.useCallback(
6253
6337
  async (sessionId, options) => {
6254
6338
  const apiBaseUrl = resolvedApiBaseUrl;
6255
6339
  if (!apiBaseUrl) {
@@ -6881,6 +6965,21 @@ function useAuthorizationOrchestrator(deps) {
6881
6965
  },
6882
6966
  [resolvedApiBaseUrl, authExecutor, waitForOneTapPause, waitForSourceSelection]
6883
6967
  );
6968
+ const run = react.useCallback(
6969
+ (sessionId, options) => {
6970
+ const promise = runInternal(sessionId, options);
6971
+ if (inflightRunRef.current === null) {
6972
+ inflightRunRef.current = promise;
6973
+ void promise.finally(() => {
6974
+ if (inflightRunRef.current === promise) {
6975
+ inflightRunRef.current = null;
6976
+ }
6977
+ });
6978
+ }
6979
+ return promise;
6980
+ },
6981
+ [runInternal]
6982
+ );
6884
6983
  const restart = react.useCallback(async () => {
6885
6984
  const lastRun = lastRunRef.current;
6886
6985
  if (!lastRun) {
@@ -6889,12 +6988,20 @@ function useAuthorizationOrchestrator(deps) {
6889
6988
  appendDebug("info", "orchestrator:restart", {
6890
6989
  sessionId: lastRun.sessionId
6891
6990
  });
6991
+ const inflight = inflightRunRef.current;
6992
+ if (inflight) {
6993
+ cancelPendingFlow();
6994
+ try {
6995
+ await inflight;
6996
+ } catch {
6997
+ }
6998
+ }
6892
6999
  authExecutor.setError(null);
6893
7000
  return run(lastRun.sessionId, {
6894
7001
  ...lastRun.options,
6895
7002
  probeBeforePrompt: true
6896
7003
  });
6897
- }, [authExecutor, run]);
7004
+ }, [authExecutor, run, cancelPendingFlow]);
6898
7005
  return {
6899
7006
  run,
6900
7007
  restart,
@@ -6984,30 +7091,6 @@ async function waitForBatchableActionsReady(options) {
6984
7091
  }
6985
7092
  return batchable.map((action) => updatedActions.get(action.id) ?? action);
6986
7093
  }
6987
- function getMergedPending(sessions, completedIds) {
6988
- const allActions = [];
6989
- for (const { session } of sessions) {
6990
- allActions.push(...getPendingActions(session, completedIds));
6991
- }
6992
- const hasPendingSvmSetupAction = allActions.some((action) => isSvmSetupAction(action));
6993
- return allActions.sort((a, b) => {
6994
- const leftIsDeferredSvmBridge = hasPendingSvmSetupAction && isSvmTransferBridgeAction(a);
6995
- const rightIsDeferredSvmBridge = hasPendingSvmSetupAction && isSvmTransferBridgeAction(b);
6996
- if (leftIsDeferredSvmBridge !== rightIsDeferredSvmBridge) {
6997
- return leftIsDeferredSvmBridge ? 1 : -1;
6998
- }
6999
- return a.orderIndex - b.orderIndex;
7000
- });
7001
- }
7002
- function isSvmSetupAction(action) {
7003
- if (action.type === "APPROVE_SPL") {
7004
- return true;
7005
- }
7006
- return action.type === "OPEN_PROVIDER" && action.metadata?.chainFamily === "svm";
7007
- }
7008
- function isSvmTransferBridgeAction(action) {
7009
- return action.type === "EXECUTE_BRIDGE" && action.metadata?.chainFamily === "svm";
7010
- }
7011
7094
  function getWalletConnectRuntimeKeyForAction(action, ownerSessionId, sessions) {
7012
7095
  const metadataKey = action?.metadata?.walletConnectAccountId;
7013
7096
  if (typeof metadataKey === "string" && metadataKey.length > 0) {
@@ -7536,6 +7619,7 @@ function createInitialState(config) {
7536
7619
  loginRequested: false,
7537
7620
  standardDesktopInlineOpenWallet: false,
7538
7621
  desktopWait: null,
7622
+ setupAuthorizationSessionId: null,
7539
7623
  mobileTokenAuthorizationPending: false,
7540
7624
  privyReady: false,
7541
7625
  privyAuthenticated: false,
@@ -7580,6 +7664,7 @@ function clearAuthenticatedSessionState(state) {
7580
7664
  loginRequested: false,
7581
7665
  standardDesktopInlineOpenWallet: false,
7582
7666
  desktopWait: null,
7667
+ setupAuthorizationSessionId: null,
7583
7668
  mobileTokenAuthorizationPending: false,
7584
7669
  setupDepositAmount: null,
7585
7670
  setupDepositToken: null,
@@ -7775,14 +7860,15 @@ function applyAction(state, action) {
7775
7860
  case "TRANSFER_CREATED":
7776
7861
  return { ...state, transfer: action.transfer, pendingTransferId: null };
7777
7862
  case "TRANSFER_SIGNED":
7778
- return { ...state, transfer: action.transfer };
7863
+ return { ...state, transfer: action.transfer, setupAuthorizationSessionId: null };
7779
7864
  case "TRANSFER_COMPLETED":
7780
7865
  return {
7781
7866
  ...state,
7782
7867
  transfer: action.transfer,
7783
7868
  pendingTransferId: null,
7784
7869
  mobileFlow: false,
7785
- deeplinkUri: null
7870
+ deeplinkUri: null,
7871
+ setupAuthorizationSessionId: null
7786
7872
  };
7787
7873
  case "TRANSFER_FAILED":
7788
7874
  return {
@@ -7828,7 +7914,8 @@ function applyAction(state, action) {
7828
7914
  deeplinkUri: null,
7829
7915
  mobileTokenAuthorizationPending: false,
7830
7916
  guestWalletPrepared: null,
7831
- guestWalletDeeplinksPreparing: false
7917
+ guestWalletDeeplinksPreparing: false,
7918
+ setupAuthorizationSessionId: null
7832
7919
  };
7833
7920
  case "MOBILE_SIGN_READY":
7834
7921
  return {
@@ -7949,6 +8036,10 @@ function applyAction(state, action) {
7949
8036
  walletName: action.walletName,
7950
8037
  walletLogoUrl: action.walletLogoUrl
7951
8038
  },
8039
+ // Mirror sessionId into the longer-lived slice so the wallet
8040
+ // account switch listener stays armed after `desktopWait` is
8041
+ // cleared by the inline-connect effect.
8042
+ setupAuthorizationSessionId: action.sessionId,
7952
8043
  standardDesktopInlineOpenWallet: true
7953
8044
  };
7954
8045
  case "DESKTOP_WAIT_CLEARED":
@@ -7978,6 +8069,7 @@ function applyAction(state, action) {
7978
8069
  oneTapLimitSavedDuringSetup: false,
7979
8070
  standardDesktopInlineOpenWallet: false,
7980
8071
  desktopWait: null,
8072
+ setupAuthorizationSessionId: null,
7981
8073
  savedSelection: null,
7982
8074
  setupDepositAmount: null,
7983
8075
  setupDepositToken: null,
@@ -17357,6 +17449,38 @@ function useMobileFlowHandlers(dispatch, polling, reloadAccounts, pollingTransfe
17357
17449
  };
17358
17450
  }
17359
17451
 
17452
+ // src/accountSwitchHelpers.ts
17453
+ var OPEN_PROVIDER_REPLACEMENT_CONFLICT_CODE = "OPEN_PROVIDER_REPLACEMENT_CONFLICT";
17454
+ var ACCOUNT_SWITCH_CONFLICT_MESSAGE = "You can't switch accounts after authorizing the source token. Please switch back to your previous account in your wallet.";
17455
+ async function replaceOpenProviderForAccountSwitch(input) {
17456
+ try {
17457
+ const session = await fetchAuthorizationSession(
17458
+ input.apiBaseUrl,
17459
+ input.sessionId
17460
+ );
17461
+ const openProvider = session.actions.find((a) => a.type === "OPEN_PROVIDER");
17462
+ if (!openProvider) {
17463
+ return { status: "no-open-provider" };
17464
+ }
17465
+ const result = { accounts: [...input.accounts] };
17466
+ if (input.chainId != null) {
17467
+ result.chainId = `0x${input.chainId.toString(16)}`;
17468
+ }
17469
+ const updated = await reportActionCompletion(
17470
+ input.apiBaseUrl,
17471
+ openProvider.id,
17472
+ result
17473
+ );
17474
+ return { status: "success", session: updated };
17475
+ } catch (err) {
17476
+ const error = err instanceof Error ? err : new Error(String(err));
17477
+ if (error.message.includes(OPEN_PROVIDER_REPLACEMENT_CONFLICT_CODE)) {
17478
+ return { status: "conflict" };
17479
+ }
17480
+ return { status: "error", error };
17481
+ }
17482
+ }
17483
+
17360
17484
  // src/hooks/providerSelectionGuards.ts
17361
17485
  function resolveSetupFlowDepositAmount({
17362
17486
  hasActiveWallet: hasActiveWallet2,
@@ -18606,6 +18730,33 @@ function useProviderHandlers(deps) {
18606
18730
  setupFlowDepositAmount,
18607
18731
  dispatch
18608
18732
  ]);
18733
+ const handleWalletAccountSwitch = react.useCallback(async (change, sessionId) => {
18734
+ const outcome = await replaceOpenProviderForAccountSwitch({
18735
+ apiBaseUrl,
18736
+ sessionId,
18737
+ accounts: change.accounts,
18738
+ chainId: change.chainId
18739
+ });
18740
+ if (outcome.status === "success") {
18741
+ dispatch({ type: "CLEAR_SETUP_DEPOSIT_TOKEN" });
18742
+ try {
18743
+ await orchestrator.restart();
18744
+ } catch (err) {
18745
+ captureException(err);
18746
+ onError?.(err instanceof Error ? err.message : "Failed to refresh authorization session.");
18747
+ }
18748
+ return;
18749
+ }
18750
+ if (outcome.status === "conflict") {
18751
+ onError?.(ACCOUNT_SWITCH_CONFLICT_MESSAGE);
18752
+ return;
18753
+ }
18754
+ if (outcome.status === "error") {
18755
+ captureException(outcome.error);
18756
+ onError?.(outcome.error.message);
18757
+ return;
18758
+ }
18759
+ }, [apiBaseUrl, dispatch, orchestrator, onError]);
18609
18760
  return {
18610
18761
  handlePrepareProvider,
18611
18762
  handleSelectProvider,
@@ -18618,7 +18769,8 @@ function useProviderHandlers(deps) {
18618
18769
  handleAuthorizeToken,
18619
18770
  handlePrepareTokenAuthorization,
18620
18771
  handleCommitTokenAuthorization,
18621
- handlePrepareGuestDeeplinks
18772
+ handlePrepareGuestDeeplinks,
18773
+ handleWalletAccountSwitch
18622
18774
  };
18623
18775
  }
18624
18776
  function useOneTapSetupHandlers(deps) {
@@ -19682,6 +19834,40 @@ function useDepositFeeEstimate({
19682
19834
  }, [fetchQuote]);
19683
19835
  return { quoteId, quoteFee, quoteLoading, quoteError };
19684
19836
  }
19837
+ function useWalletAccountSwitchEffect(deps) {
19838
+ const { enabled = true, isDesktop = true, onAccountChanged } = deps;
19839
+ const account = wagmi.useAccount();
19840
+ const address = account.address ?? null;
19841
+ const chainId = account.chainId ?? null;
19842
+ const connectorId = account.connector?.id ?? null;
19843
+ const addresses = account.addresses;
19844
+ const baselineRef = react.useRef(null);
19845
+ react.useEffect(() => {
19846
+ if (!enabled || !isDesktop) {
19847
+ baselineRef.current = null;
19848
+ return;
19849
+ }
19850
+ if (!address) {
19851
+ return;
19852
+ }
19853
+ if (baselineRef.current === null) {
19854
+ baselineRef.current = address;
19855
+ return;
19856
+ }
19857
+ if (baselineRef.current.toLowerCase() === address.toLowerCase()) {
19858
+ return;
19859
+ }
19860
+ const previous = baselineRef.current;
19861
+ baselineRef.current = address;
19862
+ void onAccountChanged({
19863
+ previousAddress: previous,
19864
+ nextAddress: address,
19865
+ connectorId: connectorId ?? "injected",
19866
+ chainId,
19867
+ accounts: addresses ?? [address]
19868
+ });
19869
+ }, [enabled, isDesktop, address, chainId, connectorId, addresses, onAccountChanged]);
19870
+ }
19685
19871
  function usePersistAmountToActiveSession({
19686
19872
  apiBaseUrl,
19687
19873
  accounts,
@@ -19981,6 +20167,17 @@ function BlinkPaymentInner({
19981
20167
  activeCredentialId: state.activeCredentialId ?? void 0,
19982
20168
  idempotencyKey
19983
20169
  });
20170
+ const accountSwitchSessionId = state.setupAuthorizationSessionId;
20171
+ const handleProviderWalletAccountSwitch = provider.handleWalletAccountSwitch;
20172
+ const onWalletAccountChanged = react.useCallback(async (change) => {
20173
+ if (!accountSwitchSessionId) return;
20174
+ await handleProviderWalletAccountSwitch(change, accountSwitchSessionId);
20175
+ }, [handleProviderWalletAccountSwitch, accountSwitchSessionId]);
20176
+ useWalletAccountSwitchEffect({
20177
+ enabled: accountSwitchSessionId != null,
20178
+ isDesktop,
20179
+ onAccountChanged: onWalletAccountChanged
20180
+ });
19984
20181
  const clearLocalSessionArtifacts = react.useCallback(() => {
19985
20182
  popupAuthRef.current = null;
19986
20183
  clearPopupAuth();
@@ -20417,6 +20614,7 @@ function getDeviceBiometricUnlockText() {
20417
20614
  return FALLBACK;
20418
20615
  }
20419
20616
 
20617
+ exports.ACCOUNT_SWITCH_CONFLICT_MESSAGE = ACCOUNT_SWITCH_CONFLICT_MESSAGE;
20420
20618
  exports.AdvancedSourceScreen = AdvancedSourceScreen;
20421
20619
  exports.AuthorizationSessionCancelledError = AuthorizationSessionCancelledError;
20422
20620
  exports.BLINK_ERROR_ILLUSTRATION = BLINK_ERROR_ILLUSTRATION;
@@ -20494,6 +20692,7 @@ exports.lightThemeNew = lightThemeNew;
20494
20692
  exports.lightTransparentTheme = lightTransparentTheme;
20495
20693
  exports.lightTransparentThemeNew = lightTransparentThemeNew;
20496
20694
  exports.mapGuestPickerEntries = mapGuestPickerEntries;
20695
+ exports.replaceOpenProviderForAccountSwitch = replaceOpenProviderForAccountSwitch;
20497
20696
  exports.resolvePasskeyRpId = resolvePasskeyRpId;
20498
20697
  exports.screenForPhase = screenForPhase;
20499
20698
  exports.subscribeDebug = subscribeDebug;