@openfort/react 1.1.2 → 1.1.4

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 (29) hide show
  1. package/build/components/Common/ErrorFallbackPage/index.d.ts +7 -0
  2. package/build/components/Common/ErrorFallbackPage/index.js +17 -0
  3. package/build/components/Common/ErrorFallbackPage/index.js.map +1 -0
  4. package/build/components/Common/NotFoundFallback/index.d.ts +6 -0
  5. package/build/components/Common/NotFoundFallback/index.js +11 -0
  6. package/build/components/Common/NotFoundFallback/index.js.map +1 -0
  7. package/build/components/Common/WalletConnectNotConfigured/index.d.ts +9 -0
  8. package/build/components/Common/WalletConnectNotConfigured/index.js +26 -0
  9. package/build/components/Common/WalletConnectNotConfigured/index.js.map +1 -0
  10. package/build/components/ConnectModal/ConnectWithMobile.js +5 -1
  11. package/build/components/ConnectModal/ConnectWithMobile.js.map +1 -1
  12. package/build/components/ConnectModal/ConnectWithQRCode.js +7 -1
  13. package/build/components/ConnectModal/ConnectWithQRCode.js.map +1 -1
  14. package/build/components/Pages/LoadWallets/index.js +9 -0
  15. package/build/components/Pages/LoadWallets/index.js.map +1 -1
  16. package/build/components/Pages/Loading/index.js +8 -0
  17. package/build/components/Pages/Loading/index.js.map +1 -1
  18. package/build/components/Pages/MobileConnectors/index.js +5 -0
  19. package/build/components/Pages/MobileConnectors/index.js.map +1 -1
  20. package/build/components/Pages/SendConfirmation/index.js +16 -4
  21. package/build/components/Pages/SendConfirmation/index.js.map +1 -1
  22. package/build/hooks/openfort/useUI.js +16 -20
  23. package/build/hooks/openfort/useUI.js.map +1 -1
  24. package/build/hooks/useTimedOut.d.ts +2 -0
  25. package/build/hooks/useTimedOut.js +14 -0
  26. package/build/hooks/useTimedOut.js.map +1 -0
  27. package/build/version.d.ts +1 -1
  28. package/build/version.js +1 -1
  29. package/package.json +2 -2
@@ -0,0 +1,7 @@
1
+ type ErrorFallbackPageProps = {
2
+ header: string;
3
+ description: string;
4
+ };
5
+ /** Shared error page with a single way out: back to the providers (sign-in) screen. */
6
+ declare const ErrorFallbackPage: ({ header, description }: ErrorFallbackPageProps) => import("react/jsx-runtime").JSX.Element;
7
+ export default ErrorFallbackPage;
@@ -0,0 +1,17 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
3
+ import { routes } from '../../Openfort/types.js';
4
+ import { useOpenfort } from '../../Openfort/useOpenfort.js';
5
+ import { PageContent } from '../../PageContent/index.js';
6
+ import Button from '../Button/index.js';
7
+ import Loader from '../Loading/index.js';
8
+
9
+ /** Shared error page with a single way out: back to the providers (sign-in) screen. */
10
+ const ErrorFallbackPage = ({ header, description }) => {
11
+ const { setRoute } = useOpenfort();
12
+ const { user } = useOpenfortCore();
13
+ return (jsxs(PageContent, { onBack: routes.PROVIDERS, children: [jsx(Loader, { header: header, isError: true, description: description }), jsx(Button, { onClick: () => setRoute(routes.PROVIDERS), children: user ? 'Go back' : 'Back to sign in' })] }));
14
+ };
15
+
16
+ export { ErrorFallbackPage as default };
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Catch-all page for flows that would otherwise spin forever
3
+ * (loading watchdog timeouts, unreachable states).
4
+ */
5
+ declare const NotFoundFallback: () => import("react/jsx-runtime").JSX.Element;
6
+ export default NotFoundFallback;
@@ -0,0 +1,11 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import ErrorFallbackPage from '../ErrorFallbackPage/index.js';
3
+
4
+ /**
5
+ * Catch-all page for flows that would otherwise spin forever
6
+ * (loading watchdog timeouts, unreachable states).
7
+ */
8
+ const NotFoundFallback = () => (jsx(ErrorFallbackPage, { header: "This is taking longer than expected", description: "We couldn't load this screen. Go back and try again." }));
9
+
10
+ export { NotFoundFallback as default };
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}
@@ -0,0 +1,9 @@
1
+ /** True when a WalletConnect connector is configured (i.e. a projectId was provided). */
2
+ export declare function useHasWalletConnect(): boolean;
3
+ /**
4
+ * Shown when a WalletConnect-dependent flow is opened but no WalletConnect
5
+ * projectId was configured. End users get neutral copy; the actionable
6
+ * config hint goes to the developer console.
7
+ */
8
+ declare const WalletConnectNotConfigured: () => import("react/jsx-runtime").JSX.Element;
9
+ export default WalletConnectNotConfigured;
@@ -0,0 +1,26 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useEffect } from 'react';
3
+ import { useEthereumBridge } from '../../../ethereum/OpenfortEthereumBridgeContext.js';
4
+ import { isWalletConnectConnector } from '../../../utils/index.js';
5
+ import ErrorFallbackPage from '../ErrorFallbackPage/index.js';
6
+
7
+ /** True when a WalletConnect connector is configured (i.e. a projectId was provided). */
8
+ function useHasWalletConnect() {
9
+ const bridge = useEthereumBridge();
10
+ return !!(bridge === null || bridge === void 0 ? void 0 : bridge.connectors.some((c) => isWalletConnectConnector(c.id)));
11
+ }
12
+ /**
13
+ * Shown when a WalletConnect-dependent flow is opened but no WalletConnect
14
+ * projectId was configured. End users get neutral copy; the actionable
15
+ * config hint goes to the developer console.
16
+ */
17
+ const WalletConnectNotConfigured = () => {
18
+ useEffect(() => {
19
+ // biome-ignore lint/suspicious/noConsole: config error must reach developers without debug mode
20
+ console.warn('[Openfort-React] WalletConnect is not configured: pass walletConnectProjectId to getDefaultConnectors (e.g. via your WalletConnect env variable) to enable external wallet connections.');
21
+ }, []);
22
+ return (jsx(ErrorFallbackPage, { header: "Wallet connections unavailable", description: "External wallet connections aren't available right now. Please use another sign-in method." }));
23
+ };
24
+
25
+ export { WalletConnectNotConfigured as default, useHasWalletConnect };
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,4 +1,4 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { useState, useEffect } from 'react';
3
3
  import { embeddedWalletId } from '../../constants/openfort.js';
4
4
  import { useEthereumBridge } from '../../ethereum/OpenfortEthereumBridgeContext.js';
@@ -11,6 +11,7 @@ import { walletConfigs } from '../../wallets/walletConfigs.js';
11
11
  import Button from '../Common/Button/index.js';
12
12
  import FitText from '../Common/FitText/index.js';
13
13
  import Loader from '../Common/Loading/index.js';
14
+ import WalletConnectNotConfigured, { useHasWalletConnect } from '../Common/WalletConnectNotConfigured/index.js';
14
15
  import { routes } from '../Openfort/types.js';
15
16
  import { useOpenfort } from '../Openfort/useOpenfort.js';
16
17
  import { PageContent } from '../PageContent/index.js';
@@ -36,6 +37,7 @@ const ConnectWithMobile = () => {
36
37
  .indexOf(connector.id) !== -1);
37
38
  const wallet = useExternalConnector(connector.id) || (walletId && walletConfigs[walletId]) || {};
38
39
  const bridge = useEthereumBridge();
40
+ const hasWalletConnect = useHasWalletConnect();
39
41
  // Only consider external wallets as "connected" — ignore the embedded wallet connector
40
42
  const isExternalConnected = (_d = (((_a = bridge === null || bridge === void 0 ? void 0 : bridge.account) === null || _a === void 0 ? void 0 : _a.isConnected) && ((_c = (_b = bridge === null || bridge === void 0 ? void 0 : bridge.account) === null || _b === void 0 ? void 0 : _b.connector) === null || _c === void 0 ? void 0 : _c.id) !== embeddedWalletId)) !== null && _d !== void 0 ? _d : false;
41
43
  const [status, setStatus] = useState(isExternalConnected ? states.CONNECTING : states.INIT);
@@ -87,6 +89,8 @@ const ConnectWithMobile = () => {
87
89
  break;
88
90
  }
89
91
  }, [status]);
92
+ if (!hasWalletConnect)
93
+ return jsx(WalletConnectNotConfigured, {});
90
94
  return (jsxs(PageContent, { children: [jsx(Loader, { header: `Connecting with ${connector.id.split(',')[0]}`, icon: wallet === null || wallet === void 0 ? void 0 : wallet.icon, isError: status === states.ERROR, description: description, onRetry: () => {
91
95
  setStatus(isExternalConnected ? states.CONNECTING : states.INIT);
92
96
  setDescription('');
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectWithMobile.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"ConnectWithMobile.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -9,6 +9,7 @@ import { useExternalConnector } from '../../wallets/useExternalConnectors.js';
9
9
  import { CopyText } from '../Common/CopyToClipboard/CopyText.js';
10
10
  import Loader from '../Common/Loading/index.js';
11
11
  import { ModalBody } from '../Common/Modal/styles.js';
12
+ import WalletConnectNotConfigured, { useHasWalletConnect } from '../Common/WalletConnectNotConfigured/index.js';
12
13
  import { routes } from '../Openfort/types.js';
13
14
  import { useOpenfort } from '../Openfort/useOpenfort.js';
14
15
  import { PageContent } from '../PageContent/index.js';
@@ -45,6 +46,7 @@ const ConnectWithWalletConnect = () => {
45
46
  const { connector } = useOpenfort();
46
47
  const wallet = useExternalConnector(connector.id);
47
48
  const { open: openWalletConnectModal } = useWalletConnectModal();
49
+ const hasWalletConnect = useHasWalletConnect();
48
50
  const [error, setError] = useState(undefined);
49
51
  const hasOpenedRef = useRef(false);
50
52
  const openModal = useCallback(async () => {
@@ -54,11 +56,15 @@ const ConnectWithWalletConnect = () => {
54
56
  setError(error);
55
57
  }, [openWalletConnectModal]);
56
58
  useEffect(() => {
59
+ if (!hasWalletConnect)
60
+ return;
57
61
  if (hasOpenedRef.current)
58
62
  return;
59
63
  hasOpenedRef.current = true;
60
64
  openModal();
61
- }, [openModal]);
65
+ }, [openModal, hasWalletConnect]);
66
+ if (!hasWalletConnect)
67
+ return jsx(WalletConnectNotConfigured, {});
62
68
  return (jsx(PageContent, { children: jsx(Loader, { header: error ? 'Error connecting wallet.' : `Connecting...`, icon: wallet === null || wallet === void 0 ? void 0 : wallet.icon, isError: !!error, description: error, onRetry: openModal }) }));
63
69
  };
64
70
  const ConnectWithQRCode = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectWithQRCode.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"ConnectWithQRCode.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -3,10 +3,12 @@ import { ChainTypeEnum, RecoveryMethod } from '@openfort/openfort-js';
3
3
  import { useState, useEffect } from 'react';
4
4
  import { useEthereumEmbeddedWallet } from '../../../ethereum/hooks/useEthereumEmbeddedWallet.js';
5
5
  import { toSolanaUserWallet } from '../../../hooks/openfort/walletTypes.js';
6
+ import { useTimedOut } from '../../../hooks/useTimedOut.js';
6
7
  import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
7
8
  import { useSolanaEmbeddedWallet } from '../../../solana/hooks/useSolanaEmbeddedWallet.js';
8
9
  import { logger } from '../../../utils/logger.js';
9
10
  import Loader from '../../Common/Loading/index.js';
11
+ import NotFoundFallback from '../../Common/NotFoundFallback/index.js';
10
12
  import { createRoute, recoverRoute } from '../../Openfort/routeHelpers.js';
11
13
  import { routes } from '../../Openfort/types.js';
12
14
  import { useOpenfort } from '../../Openfort/useOpenfort.js';
@@ -32,6 +34,9 @@ const errorForChainRegistry = {
32
34
  message: (errorWallets === null || errorWallets === void 0 ? void 0 : errorWallets.message) || 'There was an error loading wallets',
33
35
  }),
34
36
  };
37
+ // Watchdog: if wallet loading never settles (hung fetch, unreachable state),
38
+ // bail out to the not-found fallback instead of spinning forever.
39
+ const LOADING_TIMEOUT_MS = 10000;
35
40
  const LoadWallets = () => {
36
41
  var _a;
37
42
  const { chainType, user, isLoadingAccounts } = useOpenfortCore();
@@ -41,6 +46,7 @@ const LoadWallets = () => {
41
46
  const embeddedWallet = chainType === ChainTypeEnum.EVM ? ethereumWallet : solanaWallet;
42
47
  const connectOnLogin = (_a = walletConfig === null || walletConfig === void 0 ? void 0 : walletConfig.connectOnLogin) !== null && _a !== void 0 ? _a : true;
43
48
  const [loadingUX, setLoadingUX] = useState(true);
49
+ const timedOut = useTimedOut(LOADING_TIMEOUT_MS);
44
50
  const wallets = embeddedWallet.wallets;
45
51
  const isLoadingWallets = embeddedWallet.status === 'fetching-wallets' ||
46
52
  embeddedWallet.status === 'connecting' ||
@@ -98,6 +104,9 @@ const LoadWallets = () => {
98
104
  const { isError: isErrorFromChain, message: errorMessageFromChain } = errorForChainRegistry[chainType](errorWallets);
99
105
  const isError = !user || isErrorFromChain;
100
106
  const errorMessage = !user ? undefined : errorMessageFromChain;
107
+ // Only fall back while still spinning — real errors keep their own message
108
+ if (timedOut && !isError)
109
+ return jsx(NotFoundFallback, {});
101
110
  return (jsx(PageContent, { onBack: !user ? 'back' : null, children: jsx(Loader, { header: "Setting up wallet", isError: isError, description: isError ? errorMessage : 'Setting up wallets' }) }));
102
111
  };
103
112
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -3,13 +3,18 @@ import { ChainTypeEnum, EmbeddedState } from '@openfort/openfort-js';
3
3
  import React, { useEffect } from 'react';
4
4
  import { useEthereumEmbeddedWallet } from '../../../ethereum/hooks/useEthereumEmbeddedWallet.js';
5
5
  import { useEthereumBridge } from '../../../ethereum/OpenfortEthereumBridgeContext.js';
6
+ import { useTimedOut } from '../../../hooks/useTimedOut.js';
6
7
  import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
7
8
  import { useSolanaEmbeddedWallet } from '../../../solana/hooks/useSolanaEmbeddedWallet.js';
8
9
  import Loader from '../../Common/Loading/index.js';
10
+ import NotFoundFallback from '../../Common/NotFoundFallback/index.js';
9
11
  import { routes } from '../../Openfort/types.js';
10
12
  import { useOpenfort } from '../../Openfort/useOpenfort.js';
11
13
  import { PageContent } from '../../PageContent/index.js';
12
14
 
15
+ // Watchdog: if no state transition routes us away within this window, the modal
16
+ // would otherwise spin forever (e.g. opened while signed out, or a misconfigured SDK).
17
+ const LOADING_TIMEOUT_MS = 10000;
13
18
  const Loading = () => {
14
19
  const { setRoute, walletConfig } = useOpenfort();
15
20
  const { user, isLoadingAccounts, isLoading, needsRecovery, embeddedState } = useOpenfortCore();
@@ -25,6 +30,7 @@ const Loading = () => {
25
30
  const address = embeddedConnected ? wallet.address : bridgeConnected ? bridge === null || bridge === void 0 ? void 0 : bridge.account.address : undefined;
26
31
  const [isFirstFrame, setIsFirstFrame] = React.useState(true);
27
32
  const [retryCount, setRetryCount] = React.useState(0);
33
+ const timedOut = useTimedOut(LOADING_TIMEOUT_MS);
28
34
  useEffect(() => {
29
35
  if (isFirstFrame)
30
36
  return;
@@ -65,6 +71,8 @@ const Loading = () => {
65
71
  // UX: Wait a bit before showing the next page
66
72
  setTimeout(() => setIsFirstFrame(false), 400);
67
73
  }, []);
74
+ if (timedOut)
75
+ return jsx(NotFoundFallback, {});
68
76
  return (jsx(PageContent, { children: jsx(Loader, { header: "Redirecting" }) }));
69
77
  };
70
78
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -7,6 +7,7 @@ import { CopyButton } from '../../Common/CopyToClipboard/CopyButton.js';
7
7
  import { ModalContent } from '../../Common/Modal/styles.js';
8
8
  import { ScrollArea } from '../../Common/ScrollArea/index.js';
9
9
  import { Spinner } from '../../Common/Spinner/index.js';
10
+ import WalletConnectNotConfigured, { useHasWalletConnect } from '../../Common/WalletConnectNotConfigured/index.js';
10
11
  import { routes } from '../../Openfort/types.js';
11
12
  import { useOpenfort } from '../../Openfort/useOpenfort.js';
12
13
  import { PageContent } from '../../PageContent/index.js';
@@ -19,6 +20,7 @@ const MobileConnectors = () => {
19
20
  const locales = useLocales();
20
21
  const { open: openW3M, isOpen: isOpenW3M } = useWalletConnectModal();
21
22
  const wallets = useExternalConnectors();
23
+ const hasWalletConnect = useHasWalletConnect();
22
24
  // filter out installed wallets
23
25
  const walletsIdsToDisplay = (_a = Object.keys(walletConfigs).filter((walletId) => {
24
26
  const wallet = walletConfigs[walletId];
@@ -32,6 +34,9 @@ const MobileConnectors = () => {
32
34
  context.setRoute(routes.CONNECT_WITH_MOBILE);
33
35
  context.setConnector({ id: walletId });
34
36
  };
37
+ // Every wallet on this page connects through WalletConnect deeplinks
38
+ if (!hasWalletConnect)
39
+ return jsx(WalletConnectNotConfigured, {});
35
40
  return (jsx(PageContent, { width: 312, onBack: routes.PROVIDERS, children: jsxs(Container, { children: [jsx(ModalContent, { style: { paddingBottom: 0 }, children: jsx(ScrollArea, { height: 340, children: jsxs(WalletList, { children: [walletsIdsToDisplay
36
41
  .sort(
37
42
  // sort by name
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -256,7 +256,10 @@ const SendConfirmation = () => {
256
256
  }
257
257
  }, [isPollingBalance, currentBalance]);
258
258
  const handleConfirm = async () => {
259
- if (submittingRef.current)
259
+ // Block re-entry while submitting, and never submit when a tx already
260
+ // exists for this send — a second `eth_sendTransaction` is the duplicate
261
+ // transaction the customer hit after the wallet was slow to respond.
262
+ if (submittingRef.current || transactionHash)
260
263
  return;
261
264
  if (!recipientAddress || !parsedAmount || parsedAmount <= BigInt(0) || insufficientBalance)
262
265
  return;
@@ -279,8 +282,10 @@ const SendConfirmation = () => {
279
282
  });
280
283
  }
281
284
  }
282
- catch (_error) {
283
- // Errors are surfaced through mutation hooks
285
+ catch {
286
+ // The error is already recorded in nativeError/erc20Error (which drive
287
+ // firstError and the error UI) before being re-thrown — we only catch
288
+ // here to stop it becoming an unhandled rejection.
284
289
  }
285
290
  finally {
286
291
  submittingRef.current = false;
@@ -331,7 +336,14 @@ const SendConfirmation = () => {
331
336
  width: '100%',
332
337
  color: 'var(--ck-body-color-valid)',
333
338
  fontSize: '12px',
334
- }, children: "Sponsored transaction" }))] })] }), insufficientBalance && !isSuccess && (jsx(StatusMessage, { "$status": "error", children: "Insufficient balance for this transfer." })), errorDetails && (jsxs(ErrorContainer, { children: [jsx(ErrorTitle, { children: errorDetails.title }), jsx(ErrorMessage, { children: errorDetails.message }), errorDetails.action && jsx(ErrorAction, { children: errorDetails.action })] })), jsxs(ButtonRow, { children: [jsx(Button, { variant: "primary", onClick: isSuccess ? handleOpenBlockExplorer : handleConfirm, disabled: isSuccess ? false : !recipientAddress || !parsedAmount || parsedAmount <= BigInt(0) || insufficientBalance, waiting: isLoading, icon: isSuccess ? jsx(TickIcon, { style: { width: 18, height: 18 } }) : undefined, children: isSuccess ? 'Confirmed' : isLoading ? 'Confirming...' : 'Confirm' }), isSuccess ? (jsx(Button, { variant: "secondary", onClick: handleFinish, children: "Back to profile" })) : (jsx(Button, { variant: "secondary", onClick: handleCancel, disabled: isLoading, children: "Cancel" }))] })] }));
339
+ }, children: "Sponsored transaction" }))] })] }), insufficientBalance && !isSuccess && (jsx(StatusMessage, { "$status": "error", children: "Insufficient balance for this transfer." })), errorDetails && (jsxs(ErrorContainer, { children: [jsx(ErrorTitle, { children: errorDetails.title }), jsx(ErrorMessage, { children: errorDetails.message }), errorDetails.action && jsx(ErrorAction, { children: errorDetails.action })] })), jsxs(ButtonRow, { children: [jsx(Button, { variant: "primary", onClick: isSuccess ? handleOpenBlockExplorer : handleConfirm, disabled: isSuccess
340
+ ? false
341
+ : isLoading ||
342
+ Boolean(transactionHash) ||
343
+ !recipientAddress ||
344
+ !parsedAmount ||
345
+ parsedAmount <= BigInt(0) ||
346
+ insufficientBalance, waiting: isLoading, icon: isSuccess ? jsx(TickIcon, { style: { width: 18, height: 18 } }) : undefined, children: isSuccess ? 'Confirmed' : isLoading ? 'Confirming...' : 'Confirm' }), isSuccess ? (jsx(Button, { variant: "secondary", onClick: handleFinish, children: "Back to profile" })) : (jsx(Button, { variant: "secondary", onClick: handleCancel, disabled: isLoading, children: "Cancel" }))] })] }));
335
347
  };
336
348
 
337
349
  export { SendConfirmation as default };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -22,7 +22,12 @@ const safeRoutes = {
22
22
  routes.PROVIDERS,
23
23
  ],
24
24
  };
25
- const allRoutes = [...safeRoutes.connected, ...safeRoutes.disconnected];
25
+ /** Route can be selected by string (route name) or by object with `route` property */
26
+ function routeMatches(a, b) {
27
+ const aRoute = typeof a === 'object' && a !== null && 'route' in a ? a.route : a;
28
+ const bRoute = typeof b === 'object' && b !== null && 'route' in b ? b.route : b;
29
+ return aRoute === bRoute;
30
+ }
26
31
  /** Connector id must be a connector (e.g. injected, walletConnect), not an Openfort account id. */
27
32
  function isAccountId(id) {
28
33
  return id.startsWith('acc_');
@@ -84,27 +89,18 @@ function useUI() {
84
89
  setRoute(routes.CONNECTED);
85
90
  }
86
91
  const gotoAndOpen = (route) => {
87
- let validRoute = route;
88
- if (!allRoutes.includes(route)) {
89
- validRoute = isConnected ? routes.CONNECTED : routes.PROVIDERS;
90
- logger.log(`Route ${route} is not a valid route, navigating to ${validRoute} instead.`);
91
- }
92
- else {
93
- if (isConnected) {
94
- if (!safeRoutes.connected.includes(route)) {
95
- validRoute = routes.CONNECTED;
96
- logger.log(`Route ${route} is not a valid route when connected, navigating to ${validRoute} instead.`);
97
- }
98
- }
99
- else {
100
- if (!safeRoutes.disconnected.includes(route)) {
101
- validRoute = routes.PROVIDERS;
102
- logger.log(`Route ${route} is not a valid route when disconnected, navigating to ${validRoute} instead.`);
103
- }
104
- }
92
+ const safeList = isConnected ? safeRoutes.connected : safeRoutes.disconnected;
93
+ const fallback = isConnected ? routes.CONNECTED : routes.PROVIDERS;
94
+ // Navigate using the allowlisted spec so vetted options (e.g. connectType) are enforced,
95
+ // not whatever the caller passed alongside a matching route name.
96
+ const match = safeList.find((r) => routeMatches(r, route));
97
+ if (!match) {
98
+ logger.log(`Route ${JSON.stringify(route)} is not valid when ${isConnected ? 'connected' : 'disconnected'}, navigating to ${fallback} instead.`);
105
99
  }
106
- setRoute(validRoute);
100
+ // setOpen(true) resets route/history/connector for a clean session, so it MUST run
101
+ // before setRoute — otherwise it clobbers the requested route back to LOADING.
107
102
  setOpen(true);
103
+ setRoute(match !== null && match !== void 0 ? match : fallback);
108
104
  };
109
105
  return {
110
106
  isOpen: open,
@@ -1 +1 @@
1
- {"version":3,"file":"useUI.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"useUI.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,2 @@
1
+ /** Returns true once `ms` milliseconds have elapsed since mount. */
2
+ export declare function useTimedOut(ms: number): boolean;
@@ -0,0 +1,14 @@
1
+ import { useState, useEffect } from 'react';
2
+
3
+ /** Returns true once `ms` milliseconds have elapsed since mount. */
4
+ function useTimedOut(ms) {
5
+ const [timedOut, setTimedOut] = useState(false);
6
+ useEffect(() => {
7
+ const timeout = setTimeout(() => setTimedOut(true), ms);
8
+ return () => clearTimeout(timeout);
9
+ }, [ms]);
10
+ return timedOut;
11
+ }
12
+
13
+ export { useTimedOut };
14
+ //# sourceMappingURL=useTimedOut.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTimedOut.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
@@ -1 +1 @@
1
- export declare const OPENFORT_VERSION = "1.1.2";
1
+ export declare const OPENFORT_VERSION = "1.1.4";
package/build/version.js CHANGED
@@ -1,4 +1,4 @@
1
- const OPENFORT_VERSION = '1.1.2';
1
+ const OPENFORT_VERSION = '1.1.4';
2
2
 
3
3
  export { OPENFORT_VERSION };
4
4
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfort/react",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "author": "Openfort (https://www.openfort.io)",
5
5
  "license": "BSD-2-Clause license",
6
6
  "description": "The easiest way to integrate Openfort to your project.",
@@ -65,7 +65,7 @@
65
65
  "react"
66
66
  ],
67
67
  "dependencies": {
68
- "@openfort/openfort-js": "^1.3.6",
68
+ "@openfort/openfort-js": "^1.3.9",
69
69
  "buffer": "^6.0.3",
70
70
  "detect-browser": "^5.3.0",
71
71
  "fast-password-entropy": "^1.1.1",