@turnkey/react-wallet-kit 1.0.0-beta.2 → 1.0.0-beta.5

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 (73) hide show
  1. package/README.MD +2 -1
  2. package/dist/components/auth/Wallet.js +3 -3
  3. package/dist/components/auth/Wallet.js.map +1 -1
  4. package/dist/components/auth/Wallet.mjs +6 -6
  5. package/dist/components/auth/Wallet.mjs.map +1 -1
  6. package/dist/components/export/Export.d.ts +2 -2
  7. package/dist/components/export/Export.d.ts.map +1 -1
  8. package/dist/components/export/Export.js +10 -3
  9. package/dist/components/export/Export.js.map +1 -1
  10. package/dist/components/export/Export.mjs +11 -4
  11. package/dist/components/export/Export.mjs.map +1 -1
  12. package/dist/components/export/ExportWarning.d.ts +2 -2
  13. package/dist/components/export/ExportWarning.d.ts.map +1 -1
  14. package/dist/components/export/ExportWarning.js +54 -14
  15. package/dist/components/export/ExportWarning.js.map +1 -1
  16. package/dist/components/export/ExportWarning.mjs +73 -22
  17. package/dist/components/export/ExportWarning.mjs.map +1 -1
  18. package/dist/components/import/Import.d.ts +0 -4
  19. package/dist/components/import/Import.d.ts.map +1 -1
  20. package/dist/components/import/Import.js +0 -5
  21. package/dist/components/import/Import.js.map +1 -1
  22. package/dist/components/import/Import.mjs +1 -6
  23. package/dist/components/import/Import.mjs.map +1 -1
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/providers/TurnkeyProvider.d.ts +1 -0
  27. package/dist/providers/TurnkeyProvider.d.ts.map +1 -1
  28. package/dist/providers/TurnkeyProvider.js +1 -0
  29. package/dist/providers/TurnkeyProvider.js.map +1 -1
  30. package/dist/providers/TurnkeyProvider.mjs +1 -0
  31. package/dist/providers/TurnkeyProvider.mjs.map +1 -1
  32. package/dist/providers/client/Hook.d.ts +1 -0
  33. package/dist/providers/client/Hook.d.ts.map +1 -1
  34. package/dist/providers/client/Hook.js +1 -0
  35. package/dist/providers/client/Hook.js.map +1 -1
  36. package/dist/providers/client/Hook.mjs +1 -0
  37. package/dist/providers/client/Hook.mjs.map +1 -1
  38. package/dist/providers/client/Provider.d.ts.map +1 -1
  39. package/dist/providers/client/Provider.js +428 -290
  40. package/dist/providers/client/Provider.js.map +1 -1
  41. package/dist/providers/client/Provider.mjs +2006 -1818
  42. package/dist/providers/client/Provider.mjs.map +1 -1
  43. package/dist/providers/client/Types.d.ts +96 -45
  44. package/dist/providers/client/Types.d.ts.map +1 -1
  45. package/dist/providers/client/Types.js +1 -0
  46. package/dist/providers/client/Types.js.map +1 -1
  47. package/dist/providers/client/Types.mjs +1 -0
  48. package/dist/providers/client/Types.mjs.map +1 -1
  49. package/dist/providers/modal/Hook.d.ts +1 -0
  50. package/dist/providers/modal/Hook.d.ts.map +1 -1
  51. package/dist/providers/modal/Hook.js +1 -0
  52. package/dist/providers/modal/Hook.js.map +1 -1
  53. package/dist/providers/modal/Hook.mjs +1 -0
  54. package/dist/providers/modal/Hook.mjs.map +1 -1
  55. package/dist/providers/modal/Root.d.ts.map +1 -1
  56. package/dist/providers/modal/Root.js +40 -24
  57. package/dist/providers/modal/Root.js.map +1 -1
  58. package/dist/providers/modal/Root.mjs +39 -27
  59. package/dist/providers/modal/Root.mjs.map +1 -1
  60. package/dist/styles.css +1 -1
  61. package/dist/types/base.d.ts +59 -1
  62. package/dist/types/base.d.ts.map +1 -1
  63. package/dist/types/base.js +13 -0
  64. package/dist/types/base.js.map +1 -1
  65. package/dist/types/base.mjs +13 -0
  66. package/dist/types/base.mjs.map +1 -1
  67. package/dist/utils.d.ts +1 -0
  68. package/dist/utils.d.ts.map +1 -1
  69. package/dist/utils.js +31 -2
  70. package/dist/utils.js.map +1 -1
  71. package/dist/utils.mjs +38 -4
  72. package/dist/utils.mjs.map +1 -1
  73. package/package.json +12 -4
@@ -62,12 +62,14 @@ const ClientProvider = ({
62
62
  }) => {
63
63
  const [client, setClient] = react.useState(undefined);
64
64
  const [session, setSession] = react.useState(undefined);
65
- const [autoRefreshSession, setAutoRefreshSession] = react.useState(false);
66
65
  const [masterConfig, setMasterConfig] = react.useState(undefined);
67
66
  const [wallets, setWallets] = react.useState([]);
68
67
  const [user, setUser] = react.useState(undefined);
69
68
  const [clientState, setClientState] = react.useState();
70
69
  const [authState, setAuthState] = react.useState(base.AuthState.Unauthenticated);
70
+ // we use this custom hook to only update the state if the value is different
71
+ // this is so our useEffect that calls `initializeWalletProviderListeners()` only runs when it needs to
72
+ const [walletProviders, setWalletProviders] = utils.useWalletProviderState();
71
73
  const expiryTimeoutsRef = react.useRef({});
72
74
  const proxyAuthConfigRef = react.useRef(null);
73
75
  const [allSessions, setAllSessions] = react.useState(undefined);
@@ -75,78 +77,6 @@ const ClientProvider = ({
75
77
  pushPage,
76
78
  closeModal
77
79
  } = Hook.useModal();
78
- react.useEffect(() => {
79
- if (proxyAuthConfigRef.current) return;
80
- // Only fetch the proxy auth config once. Use that to build the master config.
81
- const fetchProxyAuthConfig = async () => {
82
- try {
83
- let proxyAuthConfig;
84
- if (config.authProxyConfigId) {
85
- // Only fetch the proxy auth config if we have an authProxyId. This is a way for devs to explicitly disable the proxy auth.
86
- proxyAuthConfig = await core.getAuthProxyConfig(config.authProxyConfigId, config.authProxyUrl);
87
- proxyAuthConfigRef.current = proxyAuthConfig;
88
- }
89
- setMasterConfig(buildConfig(proxyAuthConfig));
90
- } catch {
91
- setClientState(base.ClientState.Error);
92
- }
93
- };
94
- fetchProxyAuthConfig();
95
- }, []);
96
- react.useEffect(() => {
97
- // Start the client initialization process once we have the master config.
98
- if (!masterConfig) return;
99
- initializeClient();
100
- }, [masterConfig]);
101
- react.useEffect(() => {
102
- // Handle changes to the passed in config prop -- update the master config
103
- // If the proxyAuthConfigRef is already set, we don't need to fetch it again. Rebuild the master config with the updated config and stored proxyAuthConfig
104
- if (!proxyAuthConfigRef.current && config.authProxyConfigId) return;
105
- setMasterConfig(buildConfig(proxyAuthConfigRef.current ?? undefined));
106
- }, [config, proxyAuthConfigRef.current]);
107
- /**
108
- * @internal
109
- * we use debouncedFetchWallets() to prevent multiple rapid wallet events
110
- * like accountsChanged and disconnect from triggering fetchWallets repeatedly
111
- * it must be defined outside the useEffect so all event listeners share the same
112
- * debounced function instance - otherwise, a new one would be created on every render
113
- */
114
- const debouncedFetchWallets = utils.useDebouncedCallback(fetchWallets, 100);
115
- react.useEffect(() => {
116
- if (!client) return;
117
- let cleanup = () => {};
118
- initializeProviders(getWalletProviders, debouncedFetchWallets).then(fn => {
119
- cleanup = fn;
120
- }).catch(err => {
121
- console.error("Failed to init providers:", err);
122
- });
123
- return () => {
124
- cleanup();
125
- };
126
- }, [client, debouncedFetchWallets]);
127
- react.useEffect(() => {
128
- // authState must be consistent with session state. We found during testing that there are cases where the session and authState can be out of sync in very rare edge cases.
129
- // This will ensure that they are always in sync and remove the need to setAuthState manually in other places.
130
- if (session) {
131
- setAuthState(base.AuthState.Authenticated);
132
- } else {
133
- setAuthState(base.AuthState.Unauthenticated);
134
- }
135
- }, [session]);
136
- react.useEffect(() => {
137
- // This will handle any redirect based oAuth. It then initializes the session. This is the last step before client is considered "ready"
138
- if (!client || !masterConfig) return;
139
- completeRedirectOauth().finally(() => {
140
- clearSessionTimeouts();
141
- initializeSessions().finally(() => {
142
- // Set the client state to ready only after all initializations are done.
143
- setClientState(base.ClientState.Ready);
144
- });
145
- });
146
- return () => {
147
- clearSessionTimeouts();
148
- };
149
- }, [client]);
150
80
  const completeRedirectOauth = async () => {
151
81
  // Check for either hash or search parameters that could indicate an OAuth redirect
152
82
  if (window.location.hash || window.location.search) {
@@ -312,7 +242,8 @@ const ClientProvider = ({
312
242
  },
313
243
  sessionExpirationSeconds: proxyAuthConfig?.sessionExpirationSeconds,
314
244
  methodOrder,
315
- oauthOrder
245
+ oauthOrder,
246
+ autoRefreshSession: config.auth?.autoRefreshSession ?? true
316
247
  },
317
248
  walletConfig: {
318
249
  ...config.walletConfig,
@@ -327,11 +258,13 @@ const ClientProvider = ({
327
258
  ...config.walletConfig?.chains,
328
259
  ethereum: {
329
260
  ...config.walletConfig?.chains?.ethereum,
330
- native: true // Always enable native Ethereum support
261
+ // keep user's value if provided; default only when undefined
262
+ native: config.walletConfig?.chains?.ethereum?.native ?? true
331
263
  },
332
264
  solana: {
333
265
  ...config.walletConfig?.chains?.solana,
334
- native: true // Always enable native Solana support
266
+ // keep user's value if provided; default only when undefined
267
+ native: config.walletConfig?.chains?.solana?.native ?? true
335
268
  }
336
269
  }
337
270
  },
@@ -375,7 +308,6 @@ const ClientProvider = ({
375
308
  })
376
309
  }
377
310
  });
378
- setAutoRefreshSession(masterConfig?.auth?.autoRefreshSession ?? false);
379
311
  await turnkeyClient.init();
380
312
  setClient(turnkeyClient);
381
313
  // Don't set clientState to ready until we fetch the proxy auth config (See other fetchProxyAuthConfig useEffect)
@@ -393,17 +325,21 @@ const ClientProvider = ({
393
325
  * @internal
394
326
  */
395
327
  const initializeSessions = async () => {
328
+ setSession(undefined);
329
+ setAllSessions(undefined);
396
330
  try {
397
- const allSessions = await getAllSessions();
398
- if (!allSessions) {
399
- return;
400
- }
401
- await Promise.all(Object.keys(allSessions).map(async sessionKey => {
402
- const session = allSessions?.[sessionKey];
331
+ const allLocalStorageSessions = await getAllSessions();
332
+ if (!allLocalStorageSessions) return;
333
+ await Promise.all(Object.keys(allLocalStorageSessions).map(async sessionKey => {
334
+ const session = allLocalStorageSessions?.[sessionKey];
403
335
  if (!utils.isValidSession(session)) {
404
336
  await clearSession({
405
337
  sessionKey
406
338
  });
339
+ if (sessionKey === (await getActiveSessionKey())) {
340
+ setSession(undefined);
341
+ }
342
+ delete allLocalStorageSessions[sessionKey];
407
343
  return;
408
344
  }
409
345
  scheduleSessionExpiration({
@@ -411,10 +347,14 @@ const ClientProvider = ({
411
347
  expiry: session.expiry
412
348
  });
413
349
  }));
414
- setAllSessions(allSessions);
350
+ setAllSessions(allLocalStorageSessions || undefined);
415
351
  const activeSessionKey = await client?.getActiveSessionKey();
416
352
  if (activeSessionKey) {
417
- setSession(allSessions?.[activeSessionKey]);
353
+ // If we have an active session key, set
354
+ if (!allLocalStorageSessions[activeSessionKey]) {
355
+ return;
356
+ }
357
+ setSession(allLocalStorageSessions[activeSessionKey]);
418
358
  await refreshUser();
419
359
  await refreshWallets();
420
360
  return;
@@ -427,6 +367,79 @@ const ClientProvider = ({
427
367
  }
428
368
  }
429
369
  };
370
+ /**
371
+ * @internal
372
+ * Attach listeners for connected wallet providers so we can refresh state on changes.
373
+ *
374
+ * - Ethereum: listens for disconnect and chain switches to trigger a refresh.
375
+ * - Solana: listens for disconnect via Wallet Standard `change` events to trigger a refresh.
376
+ * - WalletConnect: listens for disconnect via our custom wrapper’s `change` event to trigger a refresh.
377
+ *
378
+ * Notes:
379
+ * - Only providers that are connected are bound.
380
+ * - WalletConnect is excluded from the “native” paths and handled via its unified `change` event.
381
+ *
382
+ * @param walletProviders - Discovered providers; only connected ones are bound.
383
+ * @param onWalletsChanged - Invoked when a relevant provider event occurs.
384
+ * @returns Cleanup function that removes all listeners registered by this call.
385
+ */
386
+ async function initializeWalletProviderListeners(walletProviders, onWalletsChanged) {
387
+ if (walletProviders.length === 0) return () => {};
388
+ const cleanups = [];
389
+ // we only want to initialize these listeners for connected walletProviders
390
+ const nativeOnly = provider => provider.interfaceType !== core.WalletInterfaceType.WalletConnect;
391
+ const ethProviders = masterConfig?.walletConfig?.chains.ethereum?.native ? walletProviders.filter(provider => provider.chainInfo.namespace === core.Chain.Ethereum && nativeOnly(provider) && provider.connectedAddresses.length > 0) : [];
392
+ const solProviders = masterConfig?.walletConfig?.chains.solana?.native ? walletProviders.filter(provider => provider.chainInfo.namespace === core.Chain.Solana && nativeOnly(provider) && provider.connectedAddresses.length > 0) : [];
393
+ // we exclude WalletConnect from the native event wiring
394
+ // this is because WC is handled separately with a custom wrapper’s
395
+ // `change` event
396
+ const wcProviders = walletProviders.filter(p => p.interfaceType === core.WalletInterfaceType.WalletConnect && p.connectedAddresses.length > 0);
397
+ function attachEthereumListeners(provider, onWalletsChanged) {
398
+ if (typeof provider.on !== "function") return;
399
+ const handleChainChanged = _chainId => onWalletsChanged();
400
+ const handleAccountsChanged = accounts => {
401
+ if (accounts.length === 0) onWalletsChanged();
402
+ };
403
+ const handleDisconnect = () => onWalletsChanged();
404
+ provider.on("chainChanged", handleChainChanged);
405
+ provider.on("accountsChanged", handleAccountsChanged);
406
+ provider.on("disconnect", handleDisconnect);
407
+ return () => {
408
+ provider.removeListener("chainChanged", handleChainChanged);
409
+ provider.removeListener("accountsChanged", handleAccountsChanged);
410
+ provider.removeListener("disconnect", handleDisconnect);
411
+ };
412
+ }
413
+ function attachSolanaListeners(provider, onWalletsChanged) {
414
+ const cleanups = [];
415
+ const walletEvents = provider?.features?.["standard:events"];
416
+ if (walletEvents?.on) {
417
+ const offChange = walletEvents.on("change", _evt => {
418
+ onWalletsChanged();
419
+ });
420
+ cleanups.push(offChange);
421
+ }
422
+ return () => cleanups.forEach(fn => fn());
423
+ }
424
+ ethProviders.forEach(p => {
425
+ const cleanup = attachEthereumListeners(p.provider, onWalletsChanged);
426
+ if (cleanup) cleanups.push(cleanup);
427
+ });
428
+ solProviders.forEach(p => {
429
+ const cleanup = attachSolanaListeners(p.provider, onWalletsChanged);
430
+ if (cleanup) cleanups.push(cleanup);
431
+ });
432
+ wcProviders.forEach(p => {
433
+ const standardEvents = p.provider?.features?.["standard:events"];
434
+ if (standardEvents?.on) {
435
+ const unsubscribe = standardEvents.on("change", onWalletsChanged);
436
+ cleanups.push(unsubscribe);
437
+ }
438
+ });
439
+ return () => {
440
+ cleanups.forEach(remove => remove());
441
+ };
442
+ }
430
443
  /**
431
444
  * @internal
432
445
  * Schedules a session expiration and warning timeout for the given session key.
@@ -469,7 +482,7 @@ const ClientProvider = ({
469
482
  callbacks?.beforeSessionExpiry?.({
470
483
  sessionKey
471
484
  });
472
- if (autoRefreshSession) {
485
+ if (masterConfig?.auth?.autoRefreshSession) {
473
486
  await refreshSession({
474
487
  expirationSeconds: session.expirationSeconds,
475
488
  sessionKey
@@ -484,6 +497,17 @@ const ClientProvider = ({
484
497
  callbacks?.onSessionExpired?.({
485
498
  sessionKey
486
499
  });
500
+ if ((await getActiveSessionKey()) === sessionKey) {
501
+ setSession(undefined);
502
+ }
503
+ setAllSessions(prevSessions => {
504
+ if (!prevSessions) return prevSessions;
505
+ const newSessions = {
506
+ ...prevSessions
507
+ };
508
+ delete newSessions[sessionKey];
509
+ return newSessions;
510
+ });
487
511
  await clearSession({
488
512
  sessionKey
489
513
  });
@@ -589,23 +613,23 @@ const ClientProvider = ({
589
613
  callbacks?.onError?.(new sdkTypes.TurnkeyError(`Failed to initialize sessions`, sdkTypes.TurnkeyErrorCodes.HANDLE_POST_LOGOUT_ERROR, error));
590
614
  }
591
615
  };
592
- async function createPasskey(params) {
616
+ const createPasskey = react.useCallback(async params => {
593
617
  if (!client) {
594
618
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
595
619
  }
596
620
  return utils.withTurnkeyErrorHandling(() => client.createPasskey({
597
621
  ...params
598
622
  }), callbacks, "Failed to create passkey");
599
- }
600
- async function logout(params) {
623
+ }, [client, callbacks]);
624
+ const logout = react.useCallback(async params => {
601
625
  if (!client) {
602
626
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
603
627
  }
604
- utils.withTurnkeyErrorHandling(() => client.logout(params), callbacks, "Failed to logout");
628
+ await utils.withTurnkeyErrorHandling(() => client.logout(params), callbacks, "Failed to logout");
605
629
  handlePostLogout();
606
630
  return;
607
- }
608
- async function loginWithPasskey(params) {
631
+ }, [client, callbacks]);
632
+ const loginWithPasskey = react.useCallback(async params => {
609
633
  if (!client) {
610
634
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
611
635
  }
@@ -618,8 +642,8 @@ const ClientProvider = ({
618
642
  await handlePostAuth();
619
643
  }
620
644
  return res;
621
- }
622
- async function signUpWithPasskey(params) {
645
+ }, [client, callbacks]);
646
+ const signUpWithPasskey = react.useCallback(async params => {
623
647
  if (!client) {
624
648
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
625
649
  }
@@ -653,88 +677,54 @@ const ClientProvider = ({
653
677
  await handlePostAuth();
654
678
  }
655
679
  return res;
656
- }
657
- async function getWalletProviders(chain) {
680
+ }, [client, callbacks]);
681
+ const getWalletProviders = react.useCallback(async chain => {
658
682
  if (!client) {
659
683
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
660
684
  }
661
- return await client.getWalletProviders(chain);
662
- }
663
- async function connectWalletAccount(walletProvider) {
685
+ const newProviders = await client.getWalletProviders(chain);
686
+ // we update state with the latest providers
687
+ // we keep this state so that initializeWalletProviderListeners() re-runs
688
+ // whenever the list of connected providers changes
689
+ // this ensures we attach disconnect listeners for each connected provider
690
+ setWalletProviders(newProviders);
691
+ return newProviders;
692
+ }, [client, callbacks]);
693
+ const connectWalletAccount = react.useCallback(async walletProvider => {
664
694
  if (!client) {
665
695
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
666
696
  }
667
697
  await client.connectWalletAccount(walletProvider);
698
+ // this will update our walletProvider state
668
699
  await refreshWallets();
669
- }
670
- async function disconnectWalletAccount(walletProvider) {
700
+ }, [client, callbacks]);
701
+ const disconnectWalletAccount = react.useCallback(async walletProvider => {
671
702
  if (!client) {
672
703
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
673
704
  }
674
705
  await client.disconnectWalletAccount(walletProvider);
675
- // we only refresh the wallets if there is an active session
676
- // this is needed because for WalletConnect you can unlink a wallet before
677
- // actually being logged in
678
- if (session) {
706
+ // we only refresh the wallets if:
707
+ // 1. there is an active session. This is needed because for WalletConnect
708
+ // you can unlink a wallet before actually being logged in
709
+ //
710
+ // 2. it was a WalletConnect provider that we just disconnected. Since
711
+ // native providers emit a disconnect event which will already refresh
712
+ // the wallets. This event is triggered in `initializeWalletProviderListeners()`
713
+ if (session && walletProvider.interfaceType === core.WalletInterfaceType.WalletConnect) {
714
+ // this will update our walletProvider state
679
715
  await refreshWallets();
680
716
  }
681
- }
682
- async function switchWalletProviderChain(walletProvider, chainOrId) {
717
+ }, [client, callbacks]);
718
+ const switchWalletAccountChain = react.useCallback(async params => {
683
719
  if (!client) {
684
720
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
685
721
  }
686
- await client.switchWalletProviderChain(walletProvider, chainOrId);
687
- }
688
- // TODO: MOE PLEASE COMMENT THESE
689
- async function initializeProviders(getWalletProviders, onWalletsChanged) {
690
- const cleanups = [];
691
- const [ethProviders, solProviders] = await Promise.all([getWalletProviders(core.Chain.Ethereum), getWalletProviders(core.Chain.Solana)]);
692
- function attachEthereumListeners(provider, onWalletsChanged) {
693
- if (typeof provider.on !== "function") return;
694
- const handleAccountsChanged = accounts => {
695
- if (accounts.length === 0) onWalletsChanged();
696
- };
697
- const handleDisconnect = () => onWalletsChanged();
698
- provider.on("accountsChanged", handleAccountsChanged);
699
- provider.on("disconnect", handleDisconnect);
700
- return () => {
701
- provider.removeListener("accountsChanged", handleAccountsChanged);
702
- provider.removeListener("disconnect", handleDisconnect);
703
- };
704
- }
705
- function attachSolanaListeners(provider, onWalletsChanged) {
706
- const cleanups = [];
707
- const walletEvents = provider.features?.["standard:events"];
708
- if (walletEvents?.on) {
709
- const handleChange = event => {
710
- if (event.type === "change" || event.type === "accountsChanged") {
711
- onWalletsChanged();
712
- }
713
- };
714
- walletEvents.on("change", handleChange);
715
- walletEvents.on("accountsChanged", handleChange);
716
- cleanups.push(() => {
717
- walletEvents.off?.("change", handleChange);
718
- walletEvents.off?.("accountsChanged", handleChange);
719
- });
720
- }
721
- return cleanups.length > 0 ? () => {
722
- cleanups.forEach(fn => fn());
723
- } : () => {};
724
- }
725
- ethProviders.forEach(p => {
726
- const cleanup = attachEthereumListeners(p.provider, onWalletsChanged);
727
- if (cleanup) cleanups.push(cleanup);
728
- });
729
- solProviders.forEach(p => {
730
- const cleanup = attachSolanaListeners(p.provider, onWalletsChanged);
731
- if (cleanup) cleanups.push(cleanup);
722
+ await client.switchWalletAccountChain({
723
+ ...params,
724
+ walletProviders
732
725
  });
733
- return () => {
734
- cleanups.forEach(remove => remove());
735
- };
736
- }
737
- async function loginWithWallet(params) {
726
+ }, [client, callbacks]);
727
+ const loginWithWallet = react.useCallback(async params => {
738
728
  if (!client) {
739
729
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
740
730
  }
@@ -747,8 +737,8 @@ const ClientProvider = ({
747
737
  await handlePostAuth();
748
738
  }
749
739
  return res;
750
- }
751
- async function signUpWithWallet(params) {
740
+ }, [client, callbacks]);
741
+ const signUpWithWallet = react.useCallback(async params => {
752
742
  if (!client) {
753
743
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
754
744
  }
@@ -772,8 +762,8 @@ const ClientProvider = ({
772
762
  await handlePostAuth();
773
763
  }
774
764
  return res;
775
- }
776
- async function loginOrSignupWithWallet(params) {
765
+ }, [client, callbacks, masterConfig]);
766
+ const loginOrSignupWithWallet = react.useCallback(async params => {
777
767
  if (!client) {
778
768
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
779
769
  }
@@ -797,20 +787,20 @@ const ClientProvider = ({
797
787
  await handlePostAuth();
798
788
  }
799
789
  return res;
800
- }
801
- async function initOtp(params) {
790
+ }, [client, callbacks, masterConfig]);
791
+ const initOtp = react.useCallback(async params => {
802
792
  if (!client) {
803
793
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
804
794
  }
805
795
  return utils.withTurnkeyErrorHandling(() => client.initOtp(params), callbacks, "Failed to initialize OTP");
806
- }
807
- async function verifyOtp(params) {
796
+ }, [client, callbacks]);
797
+ const verifyOtp = react.useCallback(async params => {
808
798
  if (!client) {
809
799
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
810
800
  }
811
801
  return utils.withTurnkeyErrorHandling(() => client.verifyOtp(params), callbacks, "Failed to verify OTP");
812
- }
813
- async function loginWithOtp(params) {
802
+ }, [client, callbacks]);
803
+ const loginWithOtp = react.useCallback(async params => {
814
804
  if (!client) {
815
805
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
816
806
  }
@@ -819,8 +809,8 @@ const ClientProvider = ({
819
809
  await handlePostAuth();
820
810
  }
821
811
  return res;
822
- }
823
- async function signUpWithOtp(params) {
812
+ }, [client, callbacks]);
813
+ const signUpWithOtp = react.useCallback(async params => {
824
814
  if (!client) {
825
815
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
826
816
  }
@@ -847,8 +837,8 @@ const ClientProvider = ({
847
837
  await handlePostAuth();
848
838
  }
849
839
  return res;
850
- }
851
- async function completeOtp(params) {
840
+ }, [client, callbacks, masterConfig]);
841
+ const completeOtp = react.useCallback(async params => {
852
842
  if (!client) {
853
843
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
854
844
  }
@@ -875,8 +865,8 @@ const ClientProvider = ({
875
865
  await handlePostAuth();
876
866
  }
877
867
  return res;
878
- }
879
- async function completeOauth(params) {
868
+ }, [client, callbacks, masterConfig]);
869
+ const completeOauth = react.useCallback(async params => {
880
870
  if (!client) {
881
871
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
882
872
  }
@@ -896,8 +886,8 @@ const ClientProvider = ({
896
886
  await handlePostAuth();
897
887
  }
898
888
  return res;
899
- }
900
- async function loginWithOauth(params) {
889
+ }, [client, callbacks, masterConfig]);
890
+ const loginWithOauth = react.useCallback(async params => {
901
891
  if (!client) {
902
892
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
903
893
  }
@@ -906,8 +896,8 @@ const ClientProvider = ({
906
896
  await handlePostAuth();
907
897
  }
908
898
  return res;
909
- }
910
- async function signUpWithOauth(params) {
899
+ }, [client, callbacks]);
900
+ const signUpWithOauth = react.useCallback(async params => {
911
901
  if (!client) {
912
902
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
913
903
  }
@@ -927,24 +917,24 @@ const ClientProvider = ({
927
917
  await handlePostAuth();
928
918
  }
929
919
  return res;
930
- }
931
- async function fetchWallets(params) {
920
+ }, [client, callbacks, masterConfig]);
921
+ const fetchWallets = react.useCallback(async params => {
932
922
  if (!client) {
933
923
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
934
924
  }
935
925
  return utils.withTurnkeyErrorHandling(() => client.fetchWallets(params), callbacks, "Failed to fetch wallets");
936
- }
937
- async function fetchWalletAccounts(params) {
926
+ }, [client, callbacks]);
927
+ const fetchWalletAccounts = react.useCallback(async params => {
938
928
  if (!client) {
939
929
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
940
930
  }
941
931
  return utils.withTurnkeyErrorHandling(() => client.fetchWalletAccounts(params), callbacks, "Failed to fetch wallet accounts");
942
- }
943
- async function signMessage(params) {
932
+ }, [client, callbacks]);
933
+ const signMessage = react.useCallback(async params => {
944
934
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
945
935
  return utils.withTurnkeyErrorHandling(() => client.signMessage(params), callbacks, "Failed to sign message");
946
- }
947
- async function handleSignMessage(params) {
936
+ }, [client, callbacks]);
937
+ const handleSignMessage = react.useCallback(async params => {
948
938
  const {
949
939
  successPageDuration = 2000
950
940
  } = params;
@@ -976,128 +966,146 @@ const ClientProvider = ({
976
966
  })
977
967
  });
978
968
  });
979
- }
980
- async function signTransaction(params) {
969
+ }, [client, callbacks]);
970
+ const signTransaction = react.useCallback(async params => {
981
971
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
982
972
  return utils.withTurnkeyErrorHandling(() => client.signTransaction(params), callbacks, "Failed to sign transaction");
983
- }
984
- async function signAndSendTransaction(params) {
973
+ }, [client, callbacks]);
974
+ const signAndSendTransaction = react.useCallback(async params => {
985
975
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
986
976
  return utils.withTurnkeyErrorHandling(() => client.signAndSendTransaction(params), callbacks, "Failed to sign transaction");
987
- }
988
- async function fetchUser(params) {
977
+ }, [client, callbacks]);
978
+ const fetchUser = react.useCallback(async params => {
989
979
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
990
980
  return utils.withTurnkeyErrorHandling(() => client.fetchUser(params), callbacks, "Failed to fetch user");
991
- }
992
- async function updateUserEmail(params) {
981
+ }, [client, callbacks]);
982
+ const updateUserEmail = react.useCallback(async params => {
993
983
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
994
984
  const res = await utils.withTurnkeyErrorHandling(() => client.updateUserEmail(params), callbacks, "Failed to update user email");
995
985
  if (res) await refreshUser({
996
986
  stampWith: params?.stampWith
997
987
  });
998
988
  return res;
999
- }
1000
- async function removeUserEmail(params) {
989
+ }, [client, callbacks]);
990
+ const removeUserEmail = react.useCallback(async params => {
1001
991
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1002
992
  const res = await utils.withTurnkeyErrorHandling(() => client.removeUserEmail(params), callbacks, "Failed to remove user email");
1003
993
  if (res) await refreshUser({
1004
994
  stampWith: params?.stampWith
1005
995
  });
1006
996
  return res;
1007
- }
1008
- async function updateUserPhoneNumber(params) {
997
+ }, [client, callbacks]);
998
+ const updateUserPhoneNumber = react.useCallback(async params => {
1009
999
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1010
1000
  const res = await utils.withTurnkeyErrorHandling(() => client.updateUserPhoneNumber(params), callbacks, "Failed to update user phone number");
1011
1001
  if (res) await refreshUser({
1012
1002
  stampWith: params?.stampWith
1013
1003
  });
1014
1004
  return res;
1015
- }
1016
- async function removeUserPhoneNumber(params) {
1005
+ }, [client, callbacks]);
1006
+ const removeUserPhoneNumber = react.useCallback(async params => {
1017
1007
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1018
1008
  const res = await utils.withTurnkeyErrorHandling(() => client.removeUserPhoneNumber(params), callbacks, "Failed to remove user phone number");
1019
1009
  if (res) await refreshUser({
1020
1010
  stampWith: params?.stampWith
1021
1011
  });
1022
1012
  return res;
1023
- }
1024
- async function updateUserName(params) {
1013
+ }, [client, callbacks]);
1014
+ const updateUserName = react.useCallback(async params => {
1025
1015
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1026
1016
  const res = await utils.withTurnkeyErrorHandling(() => client.updateUserName(params), callbacks, "Failed to update user name");
1027
1017
  if (res) await refreshUser({
1028
1018
  stampWith: params?.stampWith
1029
1019
  });
1030
1020
  return res;
1031
- }
1032
- async function addOauthProvider(params) {
1021
+ }, [client, callbacks]);
1022
+ const addOauthProvider = react.useCallback(async params => {
1033
1023
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1034
1024
  const res = await utils.withTurnkeyErrorHandling(() => client.addOauthProvider(params), callbacks, "Failed to add OAuth provider");
1035
1025
  if (res) await refreshUser({
1036
1026
  stampWith: params?.stampWith
1037
1027
  });
1038
1028
  return res;
1039
- }
1040
- async function removeOauthProviders(params) {
1029
+ }, [client, callbacks]);
1030
+ const removeOauthProviders = react.useCallback(async params => {
1041
1031
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1042
1032
  const res = await utils.withTurnkeyErrorHandling(() => client.removeOauthProviders(params), callbacks, "Failed to remove OAuth providers");
1043
1033
  if (res) await refreshUser({
1044
1034
  stampWith: params?.stampWith
1045
1035
  });
1046
1036
  return res;
1047
- }
1048
- async function addPasskey(params) {
1037
+ }, [client, callbacks]);
1038
+ const addPasskey = react.useCallback(async params => {
1049
1039
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1050
1040
  const res = await utils.withTurnkeyErrorHandling(() => client.addPasskey(params), callbacks, "Failed to add passkey");
1051
1041
  if (res) await refreshUser({
1052
1042
  stampWith: params?.stampWith
1053
1043
  });
1054
1044
  return res;
1055
- }
1056
- async function removePasskeys(params) {
1045
+ }, [client, callbacks]);
1046
+ const removePasskeys = react.useCallback(async params => {
1057
1047
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1058
1048
  const res = await utils.withTurnkeyErrorHandling(() => client.removePasskeys(params), callbacks, "Failed to remove passkeys");
1059
1049
  if (res) await refreshUser({
1060
1050
  stampWith: params?.stampWith
1061
1051
  });
1062
1052
  return res;
1063
- }
1064
- async function createWallet(params) {
1053
+ }, [client, callbacks]);
1054
+ const createWallet = react.useCallback(async params => {
1065
1055
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1066
1056
  const res = await utils.withTurnkeyErrorHandling(() => client.createWallet(params), callbacks, "Failed to create wallet");
1067
1057
  if (res) await refreshWallets({
1068
1058
  stampWith: params?.stampWith
1069
1059
  });
1070
1060
  return res;
1071
- }
1072
- async function createWalletAccounts(params) {
1061
+ }, [client, callbacks]);
1062
+ const createWalletAccounts = react.useCallback(async params => {
1073
1063
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1074
1064
  const res = await utils.withTurnkeyErrorHandling(() => client.createWalletAccounts(params), callbacks, "Failed to create wallet accounts");
1075
1065
  if (res) await refreshWallets({
1076
1066
  stampWith: params?.stampWith
1077
1067
  });
1078
1068
  return res;
1079
- }
1080
- async function exportWallet(params) {
1069
+ }, [client, callbacks]);
1070
+ const exportWallet = react.useCallback(async params => {
1081
1071
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1082
1072
  const res = await utils.withTurnkeyErrorHandling(() => client.exportWallet(params), callbacks, "Failed to export wallet");
1083
1073
  if (res) await refreshWallets({
1084
1074
  stampWith: params?.stampWith
1085
1075
  });
1086
1076
  return res;
1087
- }
1088
- async function importWallet(params) {
1077
+ }, [client, callbacks]);
1078
+ const exportPrivateKey = react.useCallback(async params => {
1079
+ if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1080
+ const res = await utils.withTurnkeyErrorHandling(() => client.exportPrivateKey(params), callbacks, "Failed to export private key");
1081
+ return res;
1082
+ }, [client, callbacks]);
1083
+ const exportWalletAccount = react.useCallback(async params => {
1084
+ if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1085
+ const res = await utils.withTurnkeyErrorHandling(() => client.exportWalletAccount(params), callbacks, "Failed to export wallet accounts");
1086
+ if (res) await refreshWallets({
1087
+ stampWith: params?.stampWith
1088
+ });
1089
+ return res;
1090
+ }, [client, callbacks]);
1091
+ const importWallet = react.useCallback(async params => {
1089
1092
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1090
1093
  const res = await utils.withTurnkeyErrorHandling(() => client.importWallet(params), callbacks, "Failed to import wallet");
1091
1094
  if (res) await refreshWallets({
1092
1095
  stampWith: params?.stampWith
1093
1096
  });
1094
1097
  return res;
1095
- }
1096
- async function deleteSubOrganization(params) {
1098
+ }, [client, callbacks]);
1099
+ const importPrivateKey = react.useCallback(async params => {
1100
+ if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1101
+ const res = await utils.withTurnkeyErrorHandling(() => client.importPrivateKey(params), callbacks, "Failed to import private key");
1102
+ return res;
1103
+ }, [client, callbacks]);
1104
+ const deleteSubOrganization = react.useCallback(async params => {
1097
1105
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1098
1106
  return utils.withTurnkeyErrorHandling(() => client.deleteSubOrganization(params), callbacks, "Failed to delete sub-organization");
1099
- }
1100
- async function storeSession(params) {
1107
+ }, [client, callbacks]);
1108
+ const storeSession = react.useCallback(async params => {
1101
1109
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1102
1110
  await utils.withTurnkeyErrorHandling(() => client.storeSession(params), callbacks, "Failed to store session");
1103
1111
  const sessionKey = await getActiveSessionKey();
@@ -1114,8 +1122,8 @@ const ClientProvider = ({
1114
1122
  setSession(session);
1115
1123
  setAllSessions(allSessions);
1116
1124
  return;
1117
- }
1118
- async function clearSession(params) {
1125
+ }, [client, callbacks]);
1126
+ const clearSession = react.useCallback(async params => {
1119
1127
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1120
1128
  await utils.withTurnkeyErrorHandling(() => client.clearSession(params), callbacks, "Failed to clear session");
1121
1129
  const session = await getSession();
@@ -1123,14 +1131,14 @@ const ClientProvider = ({
1123
1131
  setSession(session);
1124
1132
  setAllSessions(allSessions);
1125
1133
  return;
1126
- }
1127
- async function clearAllSessions() {
1134
+ }, [client, callbacks]);
1135
+ const clearAllSessions = react.useCallback(async () => {
1128
1136
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1129
1137
  setSession(undefined);
1130
1138
  setAllSessions(undefined);
1131
1139
  return await utils.withTurnkeyErrorHandling(() => client.clearAllSessions(), callbacks, "Failed to clear all sessions");
1132
- }
1133
- async function refreshSession(params) {
1140
+ }, [client, callbacks]);
1141
+ const refreshSession = react.useCallback(async params => {
1134
1142
  if (!client) {
1135
1143
  throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1136
1144
  }
@@ -1158,16 +1166,16 @@ const ClientProvider = ({
1158
1166
  setSession(session);
1159
1167
  setAllSessions(allSessions);
1160
1168
  return res;
1161
- }
1162
- async function getSession(params) {
1169
+ }, [client, callbacks]);
1170
+ const getSession = react.useCallback(async params => {
1163
1171
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1164
1172
  return utils.withTurnkeyErrorHandling(() => client.getSession(params), callbacks, "Failed to get session");
1165
- }
1166
- async function getAllSessions() {
1173
+ }, [client, callbacks]);
1174
+ const getAllSessions = react.useCallback(async () => {
1167
1175
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1168
1176
  return utils.withTurnkeyErrorHandling(() => client.getAllSessions(), callbacks, "Failed to get all sessions");
1169
- }
1170
- async function setActiveSession(params) {
1177
+ }, [client, callbacks]);
1178
+ const setActiveSession = react.useCallback(async params => {
1171
1179
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1172
1180
  const session = await utils.withTurnkeyErrorHandling(() => client.getSession({
1173
1181
  sessionKey: params.sessionKey
@@ -1178,24 +1186,24 @@ const ClientProvider = ({
1178
1186
  await utils.withTurnkeyErrorHandling(() => client.setActiveSession(params), callbacks, "Failed to set active session");
1179
1187
  setSession(session);
1180
1188
  return;
1181
- }
1182
- async function getActiveSessionKey() {
1189
+ }, [client, callbacks]);
1190
+ const getActiveSessionKey = react.useCallback(async () => {
1183
1191
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1184
1192
  return utils.withTurnkeyErrorHandling(() => client.getActiveSessionKey(), callbacks, "Failed to get active session key");
1185
- }
1186
- async function clearUnusedKeyPairs() {
1193
+ }, [client, callbacks]);
1194
+ const clearUnusedKeyPairs = react.useCallback(async () => {
1187
1195
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1188
1196
  return utils.withTurnkeyErrorHandling(() => client.clearUnusedKeyPairs(), callbacks, "Failed to clear unused key pairs");
1189
- }
1190
- async function createApiKeyPair(params) {
1197
+ }, [client, callbacks]);
1198
+ const createApiKeyPair = react.useCallback(async params => {
1191
1199
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1192
1200
  return utils.withTurnkeyErrorHandling(() => client.createApiKeyPair(params), callbacks, "Failed to create API key pair");
1193
- }
1194
- async function getProxyAuthConfig() {
1201
+ }, [client, callbacks]);
1202
+ const getProxyAuthConfig = react.useCallback(async () => {
1195
1203
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1196
1204
  return utils.withTurnkeyErrorHandling(() => client.getProxyAuthConfig(), callbacks, "Failed to get proxy auth config");
1197
- }
1198
- async function refreshUser(params) {
1205
+ }, [client, callbacks]);
1206
+ const refreshUser = react.useCallback(async params => {
1199
1207
  const {
1200
1208
  stampWith
1201
1209
  } = params || {};
@@ -1206,20 +1214,22 @@ const ClientProvider = ({
1206
1214
  if (user) {
1207
1215
  setUser(user);
1208
1216
  }
1209
- }
1210
- async function refreshWallets(params) {
1217
+ }, [client, callbacks]);
1218
+ const refreshWallets = react.useCallback(async params => {
1211
1219
  const {
1212
1220
  stampWith
1213
1221
  } = params || {};
1214
1222
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
1223
+ const walletProviders = await utils.withTurnkeyErrorHandling(() => getWalletProviders(), callbacks, "Failed to refresh wallets");
1215
1224
  const wallets = await utils.withTurnkeyErrorHandling(() => fetchWallets({
1216
- stampWith
1225
+ stampWith,
1226
+ walletProviders
1217
1227
  }), callbacks, "Failed to refresh wallets");
1218
1228
  if (wallets) {
1219
1229
  setWallets(wallets);
1220
1230
  }
1221
- }
1222
- async function handleGoogleOauth(params) {
1231
+ }, [client, callbacks, getWalletProviders, fetchWallets]);
1232
+ const handleGoogleOauth = react.useCallback(async params => {
1223
1233
  const {
1224
1234
  clientId = masterConfig?.auth?.oauthConfig?.googleClientId,
1225
1235
  openInPage = masterConfig?.auth?.oauthConfig?.openOauthInPage ?? false,
@@ -1335,8 +1345,8 @@ const ClientProvider = ({
1335
1345
  } catch (error) {
1336
1346
  throw error;
1337
1347
  }
1338
- }
1339
- async function handleAppleOauth(params) {
1348
+ }, [client, callbacks]);
1349
+ const handleAppleOauth = react.useCallback(async params => {
1340
1350
  const {
1341
1351
  clientId = masterConfig?.auth?.oauthConfig?.appleClientId,
1342
1352
  openInPage = masterConfig?.auth?.oauthConfig?.openOauthInPage ?? false,
@@ -1448,8 +1458,8 @@ const ClientProvider = ({
1448
1458
  } catch (error) {
1449
1459
  throw error;
1450
1460
  }
1451
- }
1452
- async function handleFacebookOauth(params) {
1461
+ }, [client, callbacks]);
1462
+ const handleFacebookOauth = react.useCallback(async params => {
1453
1463
  const {
1454
1464
  clientId = masterConfig?.auth?.oauthConfig?.facebookClientId,
1455
1465
  openInPage = masterConfig?.auth?.oauthConfig?.openOauthInPage ?? false,
@@ -1580,25 +1590,24 @@ const ClientProvider = ({
1580
1590
  } catch (error) {
1581
1591
  throw error;
1582
1592
  }
1583
- }
1584
- const handleLogin = async () => {
1593
+ }, [client, callbacks]);
1594
+ const handleLogin = react.useCallback(async () => {
1585
1595
  pushPage({
1586
1596
  key: "Log in or sign up",
1587
1597
  content: jsxRuntime.jsx(index.AuthComponent, {})
1588
1598
  });
1589
- };
1590
- const handleExport = async params => {
1599
+ }, [pushPage]);
1600
+ const handleExportWallet = react.useCallback(async params => {
1591
1601
  const {
1592
1602
  walletId,
1593
- exportType,
1594
1603
  targetPublicKey,
1595
1604
  stampWith
1596
1605
  } = params;
1597
1606
  pushPage({
1598
1607
  key: "Export Wallet",
1599
1608
  content: jsxRuntime.jsx(Export.ExportComponent, {
1600
- walletId: walletId ?? wallets[0]?.walletId,
1601
- exportType: exportType ?? base.ExportType.Wallet,
1609
+ target: walletId,
1610
+ exportType: base.ExportType.Wallet,
1602
1611
  ...(targetPublicKey !== undefined ? {
1603
1612
  targetPublicKey
1604
1613
  } : {}),
@@ -1607,8 +1616,48 @@ const ClientProvider = ({
1607
1616
  } : {})
1608
1617
  })
1609
1618
  });
1610
- };
1611
- const handleImport = async params => {
1619
+ }, [pushPage]);
1620
+ const handleExportPrivateKey = react.useCallback(async params => {
1621
+ const {
1622
+ privateKeyId,
1623
+ targetPublicKey,
1624
+ stampWith
1625
+ } = params;
1626
+ pushPage({
1627
+ key: "Export Private Key",
1628
+ content: jsxRuntime.jsx(Export.ExportComponent, {
1629
+ target: privateKeyId,
1630
+ exportType: base.ExportType.PrivateKey,
1631
+ ...(targetPublicKey !== undefined ? {
1632
+ targetPublicKey
1633
+ } : {}),
1634
+ ...(stampWith !== undefined ? {
1635
+ stampWith
1636
+ } : {})
1637
+ })
1638
+ });
1639
+ }, [pushPage]);
1640
+ const handleExportWalletAccount = react.useCallback(async params => {
1641
+ const {
1642
+ address,
1643
+ targetPublicKey,
1644
+ stampWith
1645
+ } = params;
1646
+ pushPage({
1647
+ key: "Export Wallet Account",
1648
+ content: jsxRuntime.jsx(Export.ExportComponent, {
1649
+ target: address,
1650
+ exportType: base.ExportType.WalletAccount,
1651
+ ...(targetPublicKey !== undefined ? {
1652
+ targetPublicKey
1653
+ } : {}),
1654
+ ...(stampWith !== undefined ? {
1655
+ stampWith
1656
+ } : {})
1657
+ })
1658
+ });
1659
+ }, [pushPage]);
1660
+ const handleImportWallet = react.useCallback(async params => {
1612
1661
  const {
1613
1662
  defaultWalletAccounts,
1614
1663
  successPageDuration = 2000,
@@ -1639,8 +1688,8 @@ const ClientProvider = ({
1639
1688
  }
1640
1689
  throw new sdkTypes.TurnkeyError("Failed to import wallet.", sdkTypes.TurnkeyErrorCodes.IMPORT_WALLET_ERROR, error);
1641
1690
  }
1642
- };
1643
- const handleUpdateUserName = async params => {
1691
+ }, [pushPage]);
1692
+ const handleUpdateUserName = react.useCallback(async params => {
1644
1693
  const {
1645
1694
  successPageDuration = 2000,
1646
1695
  subTitle,
@@ -1705,8 +1754,8 @@ const ClientProvider = ({
1705
1754
  }
1706
1755
  throw new sdkTypes.TurnkeyError("Failed to update user name.", sdkTypes.TurnkeyErrorCodes.UPDATE_USER_NAME_ERROR, error);
1707
1756
  }
1708
- };
1709
- const handleUpdateUserPhoneNumber = async params => {
1757
+ }, [pushPage]);
1758
+ const handleUpdateUserPhoneNumber = react.useCallback(async params => {
1710
1759
  const {
1711
1760
  successPageDuration = 2000,
1712
1761
  subTitle,
@@ -1809,8 +1858,8 @@ const ClientProvider = ({
1809
1858
  }
1810
1859
  throw new sdkTypes.TurnkeyError("Failed to initialize OTP for sms verification.", sdkTypes.TurnkeyErrorCodes.INIT_OTP_ERROR, error);
1811
1860
  }
1812
- };
1813
- const handleUpdateUserEmail = async params => {
1861
+ }, [pushPage]);
1862
+ const handleUpdateUserEmail = react.useCallback(async params => {
1814
1863
  const {
1815
1864
  successPageDuration = 2000,
1816
1865
  subTitle,
@@ -1906,8 +1955,8 @@ const ClientProvider = ({
1906
1955
  }
1907
1956
  throw new sdkTypes.TurnkeyError("Failed to initialize OTP for email verification.", sdkTypes.TurnkeyErrorCodes.INIT_OTP_ERROR, error);
1908
1957
  }
1909
- };
1910
- const handleAddEmail = async params => {
1958
+ }, [pushPage]);
1959
+ const handleAddEmail = react.useCallback(async params => {
1911
1960
  const {
1912
1961
  successPageDuration = 2000,
1913
1962
  subTitle,
@@ -2003,8 +2052,8 @@ const ClientProvider = ({
2003
2052
  }
2004
2053
  throw new sdkTypes.TurnkeyError("Failed to initialize OTP for email verification.", sdkTypes.TurnkeyErrorCodes.INIT_OTP_ERROR, error);
2005
2054
  }
2006
- };
2007
- const handleAddPhoneNumber = async params => {
2055
+ }, [pushPage]);
2056
+ const handleAddPhoneNumber = react.useCallback(async params => {
2008
2057
  const {
2009
2058
  successPageDuration = 2000,
2010
2059
  subTitle,
@@ -2111,8 +2160,8 @@ const ClientProvider = ({
2111
2160
  }
2112
2161
  throw new sdkTypes.TurnkeyError("Failed to initialize OTP for sms verification.", sdkTypes.TurnkeyErrorCodes.INIT_OTP_ERROR, error);
2113
2162
  }
2114
- };
2115
- const handleRemovePasskey = async params => {
2163
+ }, [pushPage]);
2164
+ const handleRemovePasskey = react.useCallback(async params => {
2116
2165
  const {
2117
2166
  authenticatorId,
2118
2167
  successPageDuration = 2000,
@@ -2152,8 +2201,8 @@ const ClientProvider = ({
2152
2201
  preventBack: true
2153
2202
  });
2154
2203
  }), callbacks, "Failed to remove passkey");
2155
- };
2156
- const handleAddPasskey = async params => {
2204
+ }, [pushPage]);
2205
+ const handleAddPasskey = react.useCallback(async params => {
2157
2206
  const {
2158
2207
  name,
2159
2208
  displayName,
@@ -2197,8 +2246,8 @@ const ClientProvider = ({
2197
2246
  }
2198
2247
  throw new sdkTypes.TurnkeyError("Failed to add passkey in handler.", sdkTypes.TurnkeyErrorCodes.ADD_PASSKEY_ERROR, error);
2199
2248
  }
2200
- };
2201
- const handleRemoveOauthProvider = async params => {
2249
+ }, [pushPage]);
2250
+ const handleRemoveOauthProvider = react.useCallback(async params => {
2202
2251
  const {
2203
2252
  providerId,
2204
2253
  successPageDuration = 2000,
@@ -2241,8 +2290,8 @@ const ClientProvider = ({
2241
2290
  }
2242
2291
  throw new sdkTypes.TurnkeyError("Failed to remove OAuth provider in handler.", sdkTypes.TurnkeyErrorCodes.REMOVE_OAUTH_PROVIDER_ERROR, error);
2243
2292
  }
2244
- };
2245
- const handleAddOauthProvider = async params => {
2293
+ }, [pushPage]);
2294
+ const handleAddOauthProvider = react.useCallback(async params => {
2246
2295
  if (!client) throw new sdkTypes.TurnkeyError("Client is not initialized.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
2247
2296
  if (!session) {
2248
2297
  throw new sdkTypes.TurnkeyError("No active session found.", sdkTypes.TurnkeyErrorCodes.NO_SESSION_FOUND);
@@ -2300,8 +2349,8 @@ const ClientProvider = ({
2300
2349
  throw new sdkTypes.TurnkeyError(`Unsupported OAuth provider: ${providerName}`, sdkTypes.TurnkeyErrorCodes.NOT_FOUND);
2301
2350
  }
2302
2351
  }
2303
- };
2304
- const handleLinkExternalWallet = async params => {
2352
+ }, [pushPage]);
2353
+ const handleLinkExternalWallet = react.useCallback(async params => {
2305
2354
  const {
2306
2355
  successPageDuration = 2000
2307
2356
  } = params || {};
@@ -2320,8 +2369,8 @@ const ClientProvider = ({
2320
2369
  successPageDuration: successPageDuration
2321
2370
  })
2322
2371
  });
2323
- };
2324
- const handleRemoveUserEmail = async params => {
2372
+ }, [pushPage]);
2373
+ const handleRemoveUserEmail = react.useCallback(async params => {
2325
2374
  const {
2326
2375
  successPageDuration = 2000,
2327
2376
  stampWith,
@@ -2359,8 +2408,8 @@ const ClientProvider = ({
2359
2408
  }
2360
2409
  throw new sdkTypes.TurnkeyError("Failed to remove user email.", sdkTypes.TurnkeyErrorCodes.UPDATE_USER_EMAIL_ERROR, error);
2361
2410
  }
2362
- };
2363
- const handleRemoveUserPhoneNumber = async params => {
2411
+ }, [pushPage]);
2412
+ const handleRemoveUserPhoneNumber = react.useCallback(async params => {
2364
2413
  const {
2365
2414
  successPageDuration = 2000,
2366
2415
  stampWith,
@@ -2398,7 +2447,91 @@ const ClientProvider = ({
2398
2447
  }
2399
2448
  throw new sdkTypes.TurnkeyError("Failed to remove user phone number.", sdkTypes.TurnkeyErrorCodes.UPDATE_USER_PHONE_NUMBER_ERROR, error);
2400
2449
  }
2401
- };
2450
+ }, [pushPage]);
2451
+ react.useEffect(() => {
2452
+ if (proxyAuthConfigRef.current) return;
2453
+ // Only fetch the proxy auth config once. Use that to build the master config.
2454
+ const fetchProxyAuthConfig = async () => {
2455
+ try {
2456
+ let proxyAuthConfig;
2457
+ if (config.authProxyConfigId) {
2458
+ // Only fetch the proxy auth config if we have an authProxyId. This is a way for devs to explicitly disable the proxy auth.
2459
+ proxyAuthConfig = await core.getAuthProxyConfig(config.authProxyConfigId, config.authProxyUrl);
2460
+ proxyAuthConfigRef.current = proxyAuthConfig;
2461
+ }
2462
+ setMasterConfig(buildConfig(proxyAuthConfig));
2463
+ } catch {
2464
+ setClientState(base.ClientState.Error);
2465
+ }
2466
+ };
2467
+ fetchProxyAuthConfig();
2468
+ }, []);
2469
+ react.useEffect(() => {
2470
+ // Start the client initialization process once we have the master config.
2471
+ if (!masterConfig) return;
2472
+ initializeClient();
2473
+ }, [masterConfig]);
2474
+ react.useEffect(() => {
2475
+ // Handle changes to the passed in config prop -- update the master config
2476
+ // If the proxyAuthConfigRef is already set, we don't need to fetch it again. Rebuild the master config with the updated config and stored proxyAuthConfig
2477
+ if (!proxyAuthConfigRef.current && config.authProxyConfigId) return;
2478
+ setMasterConfig(buildConfig(proxyAuthConfigRef.current ?? undefined));
2479
+ }, [config, proxyAuthConfigRef.current]);
2480
+ /**
2481
+ * @internal
2482
+ * We create `debouncedRefreshWallets()` so that multiple rapid wallet events
2483
+ * (for example, on Solana a single disconnect can emit several events we listen for)
2484
+ * only trigger `refreshWallets()` once.
2485
+ *
2486
+ * Defining the debounced function outside of the `useEffect` ensures all event
2487
+ * listeners in `initializeProviders` share the same instance, instead of creating
2488
+ * a new one on every render.
2489
+ */
2490
+ const debouncedRefreshWallets = utils.useDebouncedCallback(refreshWallets, 100);
2491
+ react.useEffect(() => {
2492
+ if (!client) return;
2493
+ const handleRefreshWallets = async () => {
2494
+ // we only refresh the wallets if there is an active session
2495
+ // this is needed because a disconnect event can occur
2496
+ // while the user is unauthenticated
2497
+ if (session) {
2498
+ // this will update our walletProvider state
2499
+ await debouncedRefreshWallets();
2500
+ }
2501
+ };
2502
+ let cleanup = () => {};
2503
+ initializeWalletProviderListeners(walletProviders, handleRefreshWallets).then(fn => {
2504
+ cleanup = fn;
2505
+ }).catch(err => {
2506
+ console.error("Failed to init providers:", err);
2507
+ });
2508
+ return () => {
2509
+ cleanup();
2510
+ };
2511
+ }, [client, walletProviders]);
2512
+ react.useEffect(() => {
2513
+ // authState must be consistent with session state. We found during testing that there are cases where the session and authState can be out of sync in very rare edge cases.
2514
+ // This will ensure that they are always in sync and remove the need to setAuthState manually in other places.
2515
+ if (session && utils.isValidSession(session)) {
2516
+ setAuthState(base.AuthState.Authenticated);
2517
+ } else {
2518
+ setAuthState(base.AuthState.Unauthenticated);
2519
+ }
2520
+ }, [session]);
2521
+ react.useEffect(() => {
2522
+ // This will handle any redirect based oAuth. It then initializes the session. This is the last step before client is considered "ready"
2523
+ if (!client || !masterConfig) return;
2524
+ completeRedirectOauth().finally(() => {
2525
+ clearSessionTimeouts();
2526
+ initializeSessions().finally(() => {
2527
+ // Set the client state to ready only after all initializations are done.
2528
+ setClientState(base.ClientState.Ready);
2529
+ });
2530
+ });
2531
+ return () => {
2532
+ clearSessionTimeouts();
2533
+ };
2534
+ }, [client]);
2402
2535
  return jsxRuntime.jsx(Types.ClientContext.Provider, {
2403
2536
  value: {
2404
2537
  session,
@@ -2416,7 +2549,7 @@ const ClientProvider = ({
2416
2549
  getWalletProviders,
2417
2550
  connectWalletAccount,
2418
2551
  disconnectWalletAccount,
2419
- switchWalletProviderChain,
2552
+ switchWalletAccountChain,
2420
2553
  loginWithWallet,
2421
2554
  signUpWithWallet,
2422
2555
  loginOrSignupWithWallet,
@@ -2448,7 +2581,10 @@ const ClientProvider = ({
2448
2581
  createWallet,
2449
2582
  createWalletAccounts,
2450
2583
  exportWallet,
2584
+ exportPrivateKey,
2585
+ exportWalletAccount,
2451
2586
  importWallet,
2587
+ importPrivateKey,
2452
2588
  deleteSubOrganization,
2453
2589
  storeSession,
2454
2590
  clearSession,
@@ -2465,8 +2601,10 @@ const ClientProvider = ({
2465
2601
  handleGoogleOauth,
2466
2602
  handleAppleOauth,
2467
2603
  handleFacebookOauth,
2468
- handleExport,
2469
- handleImport,
2604
+ handleExportWallet,
2605
+ handleExportPrivateKey,
2606
+ handleExportWalletAccount,
2607
+ handleImportWallet,
2470
2608
  handleUpdateUserEmail,
2471
2609
  handleUpdateUserPhoneNumber,
2472
2610
  handleUpdateUserName,