@openfort/react 0.0.5 → 0.0.6

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/build/index.es.js CHANGED
@@ -1,13 +1,13 @@
1
- import { Openfort as Openfort$1, RecoveryMethod, EmbeddedState, AuthActionRequiredActions, OAuthProvider, MissingRecoveryPasswordError, AccountTypeEnum, ChainTypeEnum } from '@openfort/openfort-js';
1
+ import { Openfort as Openfort$1, EmbeddedState, AuthActionRequiredActions, OAuthProvider, RecoveryMethod, MissingRecoveryPasswordError, AccountTypeEnum, ChainTypeEnum } from '@openfort/openfort-js';
2
2
  export { RecoveryMethod, ThirdPartyOAuthProvider } from '@openfort/openfort-js';
3
- import { http, useConfig, useConnectors as useConnectors$1, useConnect as useConnect$1, useAccount, useDisconnect, useSwitchChain, createConfig, useEnsAddress, useEnsName, useEnsAvatar, useBalance, useChainId, WagmiContext, useBlockNumber } from 'wagmi';
3
+ import { http, useConfig, useConnectors as useConnectors$1, useConnect as useConnect$1, useAccount, useDisconnect, useChainId, useSwitchChain, createConfig, useEnsAddress, useEnsName, useEnsAvatar, useBalance, WagmiContext, useBlockNumber } from 'wagmi';
4
4
  import { mainnet, polygon, optimism, arbitrum, sepolia } from 'wagmi/chains';
5
5
  import { safe, injected, coinbaseWallet, walletConnect } from '@wagmi/connectors';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
- import React, { useEffect, createContext, useState, useMemo, useRef, useCallback, createElement, useLayoutEffect } from 'react';
7
+ import React, { useEffect, createContext, useState, useMemo, useRef, useCallback, createElement, useLayoutEffect, useContext } from 'react';
8
8
  import { detect } from 'detect-browser';
9
9
  import { Buffer } from 'buffer';
10
- import { polygonAmoy } from 'viem/chains';
10
+ import { useQueryClient, useQuery } from '@tanstack/react-query';
11
11
  import { motion, AnimatePresence, MotionConfig } from 'framer-motion';
12
12
  import styled$1, { css, keyframes } from 'styled-components';
13
13
  import { createPortal } from 'react-dom';
@@ -20,9 +20,9 @@ import { normalize } from 'viem/ens';
20
20
  import { AxiosError } from 'axios';
21
21
  import { createSiweMessage } from 'viem/siwe';
22
22
  import { signMessage } from '@wagmi/core';
23
- import { useQuery, useQueryClient } from '@tanstack/react-query';
23
+ import calculateEntropy from 'fast-password-entropy';
24
24
 
25
- const OPENFORT_VERSION = '0.0.5';
25
+ const OPENFORT_VERSION = '0.0.6';
26
26
 
27
27
  var OpenfortErrorType;
28
28
  (function (OpenfortErrorType) {
@@ -292,7 +292,6 @@ var Logos = {
292
292
  };
293
293
 
294
294
  const truncateRegex = /^(0x[a-zA-Z0-9]{4})[a-zA-Z0-9]+([a-zA-Z0-9]{4})$/;
295
- const playerRegex = /^(pla_[a-zA-Z0-9]{4})[a-zA-Z0-9-]+([a-zA-Z0-9]{4})$/;
296
295
  const truncateEthAddress = (address, separator = '••••') => {
297
296
  if (!address)
298
297
  return '';
@@ -301,14 +300,6 @@ const truncateEthAddress = (address, separator = '••••') => {
301
300
  return address;
302
301
  return `${match[1]}${separator}${match[2]}`;
303
302
  };
304
- const truncateUserId = (playerId, separator = '••••') => {
305
- if (!playerId)
306
- return '';
307
- const match = playerId.match(playerRegex);
308
- if (!match)
309
- return playerId;
310
- return `${match[1]}${separator}${match[2]}`;
311
- };
312
303
  const nFormatter = (num, digits = 2) => {
313
304
  if (num < 10000)
314
305
  return num.toFixed(2);
@@ -991,9 +982,8 @@ const CoreOpenfortProvider = ({ children, debugMode, onConnect, onDisconnect, ..
991
982
  const { connectors, connect, reset } = useConnect();
992
983
  const { address } = useAccount();
993
984
  const [user, setUser] = useState(null);
994
- const { disconnect } = useDisconnect();
985
+ const { disconnectAsync } = useDisconnect();
995
986
  const { walletConfig } = useOpenfort();
996
- const automaticRecovery = walletConfig && walletConfig.recoveryMethod === RecoveryMethod.AUTOMATIC;
997
987
  // ---- Openfort instance ----
998
988
  const openfort = useMemo(() => {
999
989
  log('Creating Openfort instance.', openfortProps);
@@ -1075,21 +1065,27 @@ const CoreOpenfortProvider = ({ children, debugMode, onConnect, onDisconnect, ..
1075
1065
  return null;
1076
1066
  }
1077
1067
  }, [openfort]);
1068
+ const chainId = useChainId();
1078
1069
  useEffect(() => {
1079
- if (!openfort)
1080
- return;
1081
- if (!walletConfig)
1070
+ if (!openfort || !walletConfig)
1082
1071
  return;
1083
- log("Getting ethereum provider");
1084
- openfort.embeddedWallet.getEthereumProvider(walletConfig.ethereumProviderPolicyId ?
1085
- {
1086
- policy: walletConfig.ethereumProviderPolicyId,
1087
- chains: {
1088
- [polygonAmoy.id]: "https://rpc-amoy.polygon.technology",
1089
- }
1072
+ log("Getting ethereum provider", chainId);
1073
+ const resolvePolicy = () => {
1074
+ const { ethereumProviderPolicyId } = walletConfig;
1075
+ if (!ethereumProviderPolicyId)
1076
+ return undefined;
1077
+ if (typeof ethereumProviderPolicyId === "string") {
1078
+ return { policy: ethereumProviderPolicyId };
1090
1079
  }
1091
- : undefined);
1092
- }, [openfort]);
1080
+ const policy = ethereumProviderPolicyId[chainId];
1081
+ if (!policy) {
1082
+ log(`No policy found for chainId ${chainId}.`);
1083
+ return undefined;
1084
+ }
1085
+ return { policy };
1086
+ };
1087
+ openfort.embeddedWallet.getEthereumProvider(resolvePolicy());
1088
+ }, [openfort, walletConfig, chainId]);
1093
1089
  const [isConnectedWithEmbeddedSigner, setIsConnectedWithEmbeddedSigner] = useState(false);
1094
1090
  useEffect(() => {
1095
1091
  if (!openfort)
@@ -1127,7 +1123,7 @@ const CoreOpenfortProvider = ({ children, debugMode, onConnect, onDisconnect, ..
1127
1123
  default:
1128
1124
  throw new Error(`Unknown embedded state: ${embeddedState}`);
1129
1125
  }
1130
- }, [embeddedState, openfort, automaticRecovery]);
1126
+ }, [embeddedState, openfort]);
1131
1127
  useEffect(() => {
1132
1128
  // Connect to wagmi with Embedded signer
1133
1129
  if (address || !user)
@@ -1144,13 +1140,15 @@ const CoreOpenfortProvider = ({ children, debugMode, onConnect, onDisconnect, ..
1144
1140
  connect({ connector });
1145
1141
  }, [connectors, embeddedState, address, user]);
1146
1142
  // ---- Auth functions ----
1147
- const logout = useCallback(() => {
1143
+ const queryClient = useQueryClient();
1144
+ const logout = useCallback(async () => {
1148
1145
  if (!openfort)
1149
1146
  return;
1150
- log('Logging out...');
1151
- openfort.auth.logout();
1152
1147
  setUser(null);
1153
- disconnect();
1148
+ log('Logging out...');
1149
+ await openfort.auth.logout();
1150
+ await disconnectAsync();
1151
+ queryClient.resetQueries({ queryKey: ['openfortEmbeddedWalletList'] });
1154
1152
  reset();
1155
1153
  startPollingEmbeddedState();
1156
1154
  }, [openfort]);
@@ -1174,7 +1172,7 @@ const CoreOpenfortProvider = ({ children, debugMode, onConnect, onDisconnect, ..
1174
1172
  return true;
1175
1173
  case EmbeddedState.UNAUTHENTICATED:
1176
1174
  if (user)
1177
- return true; // If user is set in unauthenticated state, it means that the embedded state is not up to date, so we should wait
1175
+ return true; // If user i<s set in unauthenticated state, it means that the embedded state is not up to date, so we should wait
1178
1176
  return false;
1179
1177
  case EmbeddedState.EMBEDDED_SIGNER_NOT_CONFIGURED:
1180
1178
  if (!user)
@@ -1191,7 +1189,7 @@ const CoreOpenfortProvider = ({ children, debugMode, onConnect, onDisconnect, ..
1191
1189
  return true;
1192
1190
  }
1193
1191
  }, [embeddedState, address, user]);
1194
- const needsRecovery = !automaticRecovery && (embeddedState === EmbeddedState.EMBEDDED_SIGNER_NOT_CONFIGURED) && (!address);
1192
+ const needsRecovery = (embeddedState === EmbeddedState.EMBEDDED_SIGNER_NOT_CONFIGURED) && (!address);
1195
1193
  const value = {
1196
1194
  signUpGuest,
1197
1195
  embeddedState,
@@ -2853,7 +2851,7 @@ const InfoButton = styled(motion.button) `
2853
2851
  }
2854
2852
  }
2855
2853
  `;
2856
- const Container$7 = styled(motion.div) `
2854
+ const Container$8 = styled(motion.div) `
2857
2855
  --ease: cubic-bezier(0.25, 0.1, 0.25, 1);
2858
2856
  --duration: 200ms;
2859
2857
  --transition: height var(--duration) var(--ease),
@@ -4921,7 +4919,7 @@ const Modal = ({ open, pages, pageId, positionInside, inline, demo, onClose, onB
4921
4919
  const Content = (jsx(ResetContainer, { "$useTheme": (_e = demo === null || demo === void 0 ? void 0 : demo.theme) !== null && _e !== void 0 ? _e : themeContext.theme, "$useMode": (_f = demo === null || demo === void 0 ? void 0 : demo.mode) !== null && _f !== void 0 ? _f : themeContext.mode, "$customTheme": (_g = demo === null || demo === void 0 ? void 0 : demo.customTheme) !== null && _g !== void 0 ? _g : themeContext.customTheme, children: jsxs(ModalContainer, { role: "dialog", style: {
4922
4920
  pointerEvents: rendered ? 'auto' : 'none',
4923
4921
  position: positionInside ? 'absolute' : undefined,
4924
- }, children: [!inline && (jsx(BackgroundOverlay, { "$active": rendered, onClick: onClose, "$blur": (_h = context.uiConfig) === null || _h === void 0 ? void 0 : _h.overlayBlur })), jsxs(Container$7, { style: dimensionsCSS, initial: false, children: [jsx("div", { style: {
4922
+ }, children: [!inline && (jsx(BackgroundOverlay, { "$active": rendered, onClick: onClose, "$blur": (_h = context.uiConfig) === null || _h === void 0 ? void 0 : _h.overlayBlur })), jsxs(Container$8, { style: dimensionsCSS, initial: false, children: [jsx("div", { style: {
4925
4923
  pointerEvents: inTransition ? 'all' : 'none', // Block interaction while transitioning
4926
4924
  position: 'absolute',
4927
4925
  top: 0,
@@ -6466,7 +6464,7 @@ function useWalletConnectUri({ enabled } = {
6466
6464
  };
6467
6465
  }
6468
6466
 
6469
- const Web3Context = React.createContext({
6467
+ const Web3Context = createContext({
6470
6468
  connect: {
6471
6469
  getUri: () => '',
6472
6470
  },
@@ -6501,7 +6499,7 @@ const Web3ContextProvider = ({ enabled, children, }) => {
6501
6499
  };
6502
6500
  return jsx(Web3Context.Provider, { value: value, children: children });
6503
6501
  };
6504
- const useWeb3 = () => React.useContext(Web3Context);
6502
+ const useWeb3 = () => useContext(Web3Context);
6505
6503
 
6506
6504
  const AlertContainer = styled(motion.div) `
6507
6505
  display: flex;
@@ -7348,7 +7346,7 @@ const WalletList = styled.div `
7348
7346
  }
7349
7347
  `}
7350
7348
  `;
7351
- const Container$6 = styled.div ``;
7349
+ const Container$7 = styled.div ``;
7352
7350
 
7353
7351
  function useWalletConnectModal() {
7354
7352
  const { log } = useOpenfort();
@@ -7455,7 +7453,7 @@ const CopyToClipboardIcon = ({ copied, small, }) => (jsx(IconContainer$3, { "$cl
7455
7453
  opacity: small || copied ? 1 : 0.3,
7456
7454
  } }) }));
7457
7455
 
7458
- const Container$5 = styled.div `
7456
+ const Container$6 = styled.div `
7459
7457
  --color: var(--ck-copytoclipboard-stroke);
7460
7458
  --bg: var(--ck-body-background);
7461
7459
  transition: all 220ms cubic-bezier(0.175, 0.885, 0.32, 1.1);
@@ -7505,7 +7503,7 @@ const CopyToClipboard = ({ string, children, variant }) => {
7505
7503
  };
7506
7504
  if (variant === 'button')
7507
7505
  return (jsx(Button, { disabled: !string, onClick: onCopy, icon: jsx(CopyToClipboardIcon, { copied: clipboard }), children: children }));
7508
- return (jsx(Container$5, { onClick: onCopy, "$disabled": !string, children: jsxs(OffsetContainer, { children: [children, jsx(CopyToClipboardIcon, { copied: clipboard, small: true })] }) }));
7506
+ return (jsx(Container$6, { onClick: onCopy, "$disabled": !string, children: jsxs(OffsetContainer, { children: [children, jsx(CopyToClipboardIcon, { copied: clipboard, small: true })] }) }));
7509
7507
  };
7510
7508
 
7511
7509
  const MoreIcon = (jsx("svg", { width: "60", height: "60", viewBox: "0 0 60 60", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M30 42V19M19 30.5H42", stroke: "var(--ck-body-color-muted)", strokeWidth: "3", strokeLinecap: "round" }) }));
@@ -7533,7 +7531,7 @@ const MobileConnectors = () => {
7533
7531
  window.location.href = uri;
7534
7532
  //if (uri) window.open(uri, '_blank');
7535
7533
  };
7536
- return (jsx(PageContent, { style: { width: 312 }, children: jsxs(Container$6, { children: [jsx(ModalContent, { style: { paddingBottom: 0 }, children: jsx(ScrollArea, { height: 340, children: jsxs(WalletList, { "$disabled": !wcUri, children: [walletsIdsToDisplay
7534
+ return (jsx(PageContent, { style: { width: 312 }, children: jsxs(Container$7, { children: [jsx(ModalContent, { style: { paddingBottom: 0 }, children: jsx(ScrollArea, { height: 340, children: jsxs(WalletList, { "$disabled": !wcUri, children: [walletsIdsToDisplay
7537
7535
  .sort(
7538
7536
  // sort by name
7539
7537
  (a, b) => {
@@ -8986,7 +8984,7 @@ const ChainSelectDropdown = ({ children, open, onClose, offsetX = 0, offsetY = 8
8986
8984
  }, children: [jsx(DropdownHeading, { children: locales.switchNetworks }), jsx(ChainSelectList, {})] })] }) }) }) })) })] }));
8987
8985
  };
8988
8986
 
8989
- const Container$4 = styled(motion.div) ``;
8987
+ const Container$5 = styled(motion.div) ``;
8990
8988
  const SwitchChainButton = styled(motion.button) `
8991
8989
  --color: var(
8992
8990
  --ck-dropdown-button-color,
@@ -9095,7 +9093,7 @@ const ChainSelector = () => {
9095
9093
  setIsOpen(false);
9096
9094
  }, [context.open]);
9097
9095
  const disabled = chains.length <= 1;
9098
- return (jsx(Fragment, { children: jsx(Container$4, { children: jsx(ChainSelectDropdown, { offsetX: -12, open: !mobile && isOpen, onClose: () => setIsOpen(false), children: jsxs(SwitchChainButton, { "aria-label": flattenChildren(locales.switchNetworks).toString(), disabled: disabled, onClick: () => {
9096
+ return (jsx(Fragment, { children: jsx(Container$5, { children: jsx(ChainSelectDropdown, { offsetX: -12, open: !mobile && isOpen, onClose: () => setIsOpen(false), children: jsxs(SwitchChainButton, { "aria-label": flattenChildren(locales.switchNetworks).toString(), disabled: disabled, onClick: () => {
9099
9097
  if (mobile) {
9100
9098
  context.setRoute(routes.SWITCHNETWORKS);
9101
9099
  }
@@ -9108,7 +9106,7 @@ const ChainSelector = () => {
9108
9106
  const PoweredByFooter = ({ showDisclaimer }) => {
9109
9107
  var _a, _b;
9110
9108
  const { uiConfig: options } = useOpenfort();
9111
- return (jsxs(Container$3, { children: [showDisclaimer && (jsx(Disclaimer, { children: (options === null || options === void 0 ? void 0 : options.disclaimer) ? (jsx(Fragment, { children: options.disclaimer })) : (jsxs("div", { children: ["By logging in, you agree to our ", jsx("a", { href: (_a = options === null || options === void 0 ? void 0 : options.termsOfServiceUrl) !== null && _a !== void 0 ? _a : "https://www.openfort.xyz/terms", target: "_blank", rel: "noopener noreferrer", children: "Terms of Service" }), " & ", jsx("a", { href: (_b = options === null || options === void 0 ? void 0 : options.privacyPolicyUrl) !== null && _b !== void 0 ? _b : "https://www.openfort.xyz/privacy", target: "_blank", rel: "noopener noreferrer", children: "Privacy Policy" }), "."] })) })), jsxs(TextButton, { onClick: () => {
9109
+ return (jsxs(Container$4, { children: [showDisclaimer && (jsx(Disclaimer, { children: (options === null || options === void 0 ? void 0 : options.disclaimer) ? (jsx(Fragment, { children: options.disclaimer })) : (jsxs("div", { children: ["By logging in, you agree to our ", jsx("a", { href: (_a = options === null || options === void 0 ? void 0 : options.termsOfServiceUrl) !== null && _a !== void 0 ? _a : "https://www.openfort.xyz/terms", target: "_blank", rel: "noopener noreferrer", children: "Terms of Service" }), " & ", jsx("a", { href: (_b = options === null || options === void 0 ? void 0 : options.privacyPolicyUrl) !== null && _b !== void 0 ? _b : "https://www.openfort.xyz/privacy", target: "_blank", rel: "noopener noreferrer", children: "Privacy Policy" }), "."] })) })), jsxs(TextButton, { onClick: () => {
9112
9110
  window.open("https://www.openfort.xyz/", "_blank");
9113
9111
  }, children: [jsx("span", { children: "Powered by" }), jsx(IconContainer$2, { children: jsx(Logos.Openfort, {}) }), jsx("span", { children: "Openfort" })] })] }));
9114
9112
  };
@@ -9157,7 +9155,7 @@ const IconContainer$2 = styled.div `
9157
9155
  border-radius: 0;
9158
9156
  }
9159
9157
  `;
9160
- const Container$3 = styled(motion.div) `
9158
+ const Container$4 = styled(motion.div) `
9161
9159
  text-align: center;
9162
9160
  margin-top: 4px;
9163
9161
  margin-bottom: -16px;
@@ -9350,10 +9348,7 @@ const Profile = ({ closeModal }) => {
9350
9348
  //watch: true,
9351
9349
  });
9352
9350
  const [shouldDisconnect, setShouldDisconnect] = useState(false);
9353
- const { logout, user } = useOpenfortCore();
9354
- useEffect(() => {
9355
- // if (!isConnected) context.setOpen(false);
9356
- }, [isConnected]);
9351
+ const { logout } = useOpenfortCore();
9357
9352
  useEffect(() => {
9358
9353
  if (!shouldDisconnect)
9359
9354
  return;
@@ -9411,7 +9406,7 @@ const outlineKeyframes = keyframes `
9411
9406
  0%{ opacity:1; }
9412
9407
  100%{ opacity:0; }
9413
9408
  `;
9414
- const Container$2 = styled(motion.div) `
9409
+ const Container$3 = styled(motion.div) `
9415
9410
  /*
9416
9411
  background: var(
9417
9412
  --ck-body-background
@@ -10012,14 +10007,14 @@ const ConnectWithInjector = ({ switchConnectMethod, forceState }) => {
10012
10007
  }, [status, expiryTimer]);
10013
10008
  */
10014
10009
  if (!wallet) {
10015
- return (jsx(PageContent, { children: jsxs(Container$2, { children: [jsx(ModalHeading, { children: "Invalid State" }), jsx(ModalContent, { children: jsx(Alert, { children: "No connectors match the id given. This state should never happen." }) })] }) }));
10010
+ return (jsx(PageContent, { children: jsxs(Container$3, { children: [jsx(ModalHeading, { children: "Invalid State" }), jsx(ModalContent, { children: jsx(Alert, { children: "No connectors match the id given. This state should never happen." }) })] }) }));
10016
10011
  }
10017
10012
  // OLD_TODO: Make this more generic
10018
10013
  if (isWalletConnectConnector(wallet === null || wallet === void 0 ? void 0 : wallet.connector.id)) {
10019
- return (jsx(PageContent, { children: jsxs(Container$2, { children: [jsx(ModalHeading, { children: "Invalid State" }), jsx(ModalContent, { children: jsx(Alert, { children: "WalletConnect does not have an injection flow. This state should never happen." }) })] }) }));
10014
+ return (jsx(PageContent, { children: jsxs(Container$3, { children: [jsx(ModalHeading, { children: "Invalid State" }), jsx(ModalContent, { children: jsx(Alert, { children: "WalletConnect does not have an injection flow. This state should never happen." }) })] }) }));
10020
10015
  }
10021
10016
  const hasError = status === states$2.FAILED || status === states$2.REJECTED || status === states$2.DUPLICATED;
10022
- return (jsx(PageContent, { children: jsxs(Container$2, { children: [jsx(ConnectingContainer$1, { children: jsxs(ConnectingAnimation$1, { "$shake": hasError, "$circle": walletInfo.iconShape === 'circle', children: [jsx(AnimatePresence, { children: (hasError) && (jsx(RetryButton, { "aria-label": "Retry", initial: { opacity: 0, scale: 0.8 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.8 }, whileTap: { scale: 0.9 }, transition: { duration: 0.1 }, onClick: runConnect, children: jsx(RetryIconContainer, { children: jsx(Tooltip, { open: showTryAgainTooltip &&
10017
+ return (jsx(PageContent, { children: jsxs(Container$3, { children: [jsx(ConnectingContainer$1, { children: jsxs(ConnectingAnimation$1, { "$shake": hasError, "$circle": walletInfo.iconShape === 'circle', children: [jsx(AnimatePresence, { children: (hasError) && (jsx(RetryButton, { "aria-label": "Retry", initial: { opacity: 0, scale: 0.8 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.8 }, whileTap: { scale: 0.9 }, transition: { duration: 0.1 }, onClick: runConnect, children: jsx(RetryIconContainer, { children: jsx(Tooltip, { open: showTryAgainTooltip &&
10023
10018
  (hasError), message: locales.tryAgainQuestion, xOffset: -6, children: jsx(RetryIconCircle, {}) }) }) })) }), walletInfo.iconShape === 'circle' ? (jsx(CircleSpinner, { logo: status === states$2.UNAVAILABLE ? (jsx("div", { style: {
10024
10019
  transform: 'scale(1.14)',
10025
10020
  position: 'relative',
@@ -11020,12 +11015,13 @@ function useUser() {
11020
11015
  };
11021
11016
  }
11022
11017
 
11023
- const createOpenfortWallet = ({ address, }) => ({
11018
+ const parseOpenfortWallet = ({ address, recoveryMethod, }) => ({
11024
11019
  connectorType: "embedded",
11025
11020
  walletClientType: "openfort",
11026
11021
  address,
11027
11022
  id: embeddedWalletId,
11028
11023
  isAvailable: true,
11024
+ recoveryMethod,
11029
11025
  });
11030
11026
  const mapWalletStatus = (status) => {
11031
11027
  return {
@@ -11086,9 +11082,6 @@ function useWallets(hookOptions = {}) {
11086
11082
  refetchOnMount: false,
11087
11083
  refetchOnWindowFocus: false,
11088
11084
  });
11089
- // useEffect(() => {
11090
- // queryClient.resetQueries({ queryKey: ['openfortEmbeddedWalletList'] })
11091
- // }, [!!user, refetch]);
11092
11085
  const getEncryptionSession = useCallback(async () => {
11093
11086
  if (!walletConfig || !walletConfig.createEncryptedSessionEndpoint) {
11094
11087
  throw new Error("No createEncryptedSessionEndpoint set in walletConfig");
@@ -11122,8 +11115,9 @@ function useWallets(hookOptions = {}) {
11122
11115
  // Remove duplicates (different chain ids)
11123
11116
  if (userWallets.find(w => w.address === (wallet.address)))
11124
11117
  return;
11125
- userWallets.push(createOpenfortWallet({
11118
+ userWallets.push(parseOpenfortWallet({
11126
11119
  address: wallet.address,
11120
+ recoveryMethod: wallet.recoveryMethod,
11127
11121
  }));
11128
11122
  });
11129
11123
  return userWallets;
@@ -11250,13 +11244,12 @@ function useWallets(hookOptions = {}) {
11250
11244
  walletAddress = walletToRecover.address;
11251
11245
  }
11252
11246
  else {
11253
- const wallet = await createWallet({
11254
- password,
11247
+ // Here it should check if there is a wallet that can recover in another chain and recover it in the current chain (its a different account so its not supported yet)
11248
+ return onError({
11249
+ error: new OpenfortError("No embedded wallet found for the current chain", OpenfortErrorType.WALLET_ERROR),
11250
+ options: optionsObject,
11251
+ hookOptions
11255
11252
  });
11256
- if (!wallet.wallet) {
11257
- return { error: wallet.error || new OpenfortError("Failed to create embedded wallet", OpenfortErrorType.WALLET_ERROR) };
11258
- }
11259
- walletAddress = wallet.wallet.address;
11260
11253
  }
11261
11254
  }
11262
11255
  setStatus({
@@ -11264,8 +11257,9 @@ function useWallets(hookOptions = {}) {
11264
11257
  });
11265
11258
  return onSuccess({
11266
11259
  data: {
11267
- wallet: createOpenfortWallet({
11260
+ wallet: parseOpenfortWallet({
11268
11261
  address: walletAddress,
11262
+ recoveryMethod: recoveryParams.recoveryMethod,
11269
11263
  }),
11270
11264
  },
11271
11265
  options: optionsObject,
@@ -11365,8 +11359,9 @@ function useWallets(hookOptions = {}) {
11365
11359
  refetch();
11366
11360
  return onSuccess({
11367
11361
  data: {
11368
- wallet: createOpenfortWallet({
11362
+ wallet: parseOpenfortWallet({
11369
11363
  address: wallet.address,
11364
+ recoveryMethod: wallet.recoveryMethod,
11370
11365
  })
11371
11366
  }
11372
11367
  });
@@ -11399,8 +11394,9 @@ function useWallets(hookOptions = {}) {
11399
11394
  hookOptions,
11400
11395
  options: params,
11401
11396
  data: {
11402
- wallet: createOpenfortWallet({
11397
+ wallet: parseOpenfortWallet({
11403
11398
  address: embeddedAccount.address,
11399
+ recoveryMethod: embeddedAccount.recoveryMethod,
11404
11400
  }),
11405
11401
  }
11406
11402
  });
@@ -11429,19 +11425,202 @@ function useWallets(hookOptions = {}) {
11429
11425
  };
11430
11426
  }
11431
11427
 
11428
+ /**
11429
+ * Password Utilities Module
11430
+ * Provides functions for password strength calculation, passphrase generation,
11431
+ * and password validation.
11432
+ */
11433
+ // ============================================================================
11434
+ // Constants and Regular Expressions
11435
+ // ============================================================================
11436
+ /** Regular expression to match lowercase letters */
11437
+ const LOWERCASE_REGEX = /[a-z]/;
11438
+ /** Regular expression to match uppercase letters */
11439
+ const UPPERCASE_REGEX = /[A-Z]/;
11440
+ /** Regular expression to match digits */
11441
+ const DIGIT_REGEX = /[0-9]/;
11442
+ /** Special characters allowed in passwords */
11443
+ const SPECIAL_CHARACTERS = '!@#$%^&()\\-*+.';
11444
+ /** Regular expression to match special characters */
11445
+ const SPECIAL_CHARACTER_REGEX = new RegExp(`[${SPECIAL_CHARACTERS}]`);
11446
+ /** Maximum entropy score for normalization */
11447
+ const MAX_ENTROPY_SCORE = 95;
11448
+ /** Minimum password length for security */
11449
+ const MIN_PASSWORD_LENGTH = 8;
11450
+ /** Weight for diversity score in overall strength calculation */
11451
+ const DIVERSITY_WEIGHT = 0.3;
11452
+ const ENTROPY_WEIGHT = 0.7;
11453
+ const MEDIUM_SCORE_THRESHOLD = 0.5;
11454
+ const STRONG_SCORE_THRESHOLD = 0.75;
11455
+ const VERY_STRONG_SCORE_THRESHOLD = 0.9;
11456
+ /**
11457
+ * Converts a numeric password strength score to a human-readable label.
11458
+ *
11459
+ * @param score - The strength score (0-1)
11460
+ * @returns The corresponding strength label
11461
+ */
11462
+ function getPasswordStrengthLabel(score) {
11463
+ if (score > VERY_STRONG_SCORE_THRESHOLD) {
11464
+ return 'Very Strong';
11465
+ }
11466
+ else if (score > STRONG_SCORE_THRESHOLD) {
11467
+ return 'Strong';
11468
+ }
11469
+ else if (score > MEDIUM_SCORE_THRESHOLD) {
11470
+ return 'Medium';
11471
+ }
11472
+ else {
11473
+ return 'Weak';
11474
+ }
11475
+ }
11476
+ /**
11477
+ * Calculates the diversity score of a password based on character types used.
11478
+ * Considers lowercase, uppercase, digits, and special characters.
11479
+ *
11480
+ * @param password - The password to analyze
11481
+ * @returns A score between 0 and 1 representing character diversity
11482
+ */
11483
+ function calculatePasswordDiversityScore(password) {
11484
+ // Passwords shorter than minimum length get a score of 0
11485
+ if (password.length < MIN_PASSWORD_LENGTH) {
11486
+ return 0;
11487
+ }
11488
+ let characterTypesUsed = 0;
11489
+ if (LOWERCASE_REGEX.test(password)) {
11490
+ characterTypesUsed += 1;
11491
+ }
11492
+ if (UPPERCASE_REGEX.test(password)) {
11493
+ characterTypesUsed += 1;
11494
+ }
11495
+ if (DIGIT_REGEX.test(password)) {
11496
+ characterTypesUsed += 1;
11497
+ }
11498
+ if (SPECIAL_CHARACTER_REGEX.test(password)) {
11499
+ characterTypesUsed += 1;
11500
+ }
11501
+ return Math.max(0, Math.min(1, characterTypesUsed / 4));
11502
+ }
11503
+ /**
11504
+ * Calculates the overall password strength combining diversity and entropy.
11505
+ *
11506
+ * @param password - The password to analyze
11507
+ * @returns A strength score between 0 and 1
11508
+ */
11509
+ function getPasswordStrength(password = '') {
11510
+ const diversityScore = calculatePasswordDiversityScore(password);
11511
+ const entropyScore = calculateEntropy(password) / MAX_ENTROPY_SCORE;
11512
+ return Math.min((diversityScore * DIVERSITY_WEIGHT +
11513
+ entropyScore * ENTROPY_WEIGHT), 1);
11514
+ }
11515
+
11516
+ const Container$2 = styled.div `
11517
+ display: flex;
11518
+ flex-direction: column;
11519
+ gap: 0.5rem;
11520
+ margin-top: 0.5rem;
11521
+ margin-bottom: 0.5rem;
11522
+ text-align: left;
11523
+ `;
11524
+ const BarWrapper = styled.div `
11525
+ width: 100%;
11526
+ height: 4px;
11527
+ background: var(--ck-secondary-button-background);
11528
+ border-radius: 4px;
11529
+ overflow: hidden;
11530
+ `;
11531
+ const Progress = styled(motion.div) `
11532
+ height: 100%;
11533
+ background: ${({ color }) => color};
11534
+ border-radius: 4px;
11535
+ `;
11536
+ const Label = styled.div `
11537
+ font-size: 0.875rem;
11538
+ font-weight: 500;
11539
+ color: var(--ck-body-color-muted);
11540
+ `;
11541
+ const LabelColor = styled.span `
11542
+ color: ${({ color }) => color};
11543
+ `;
11544
+ const PasswordStrengthIndicator = ({ password, showPasswordIsTooWeakError }) => {
11545
+ const passwordStrength = getPasswordStrength(password); // should return a number between 0 and 1
11546
+ const label = getPasswordStrengthLabel(passwordStrength);
11547
+ const color = useMemo(() => {
11548
+ switch (label) {
11549
+ case "Weak":
11550
+ return "#ef4444"; // red-500
11551
+ case "Medium":
11552
+ return "#f59e0b"; // amber-500
11553
+ case "Strong":
11554
+ return "#10b981"; // emerald-500
11555
+ case "Very Strong":
11556
+ return "#3b82f6"; // blue-500
11557
+ default:
11558
+ return "#d1d5db"; // gray-300
11559
+ }
11560
+ }, [label]);
11561
+ return (jsxs(Container$2, { children: [jsx(BarWrapper, { children: jsx(Progress, { color: color, initial: { width: 0 }, animate: { width: `${passwordStrength * 100}%` }, transition: { ease: "easeOut", duration: 0.5 } }) }), jsxs("div", { style: { position: 'relative' }, children: [jsx(motion.div, { initial: { opacity: 1 }, animate: {
11562
+ opacity: showPasswordIsTooWeakError ? 0 : 1,
11563
+ y: showPasswordIsTooWeakError ? 5 : 0
11564
+ }, transition: { duration: 0.3 }, children: jsxs(Label, { children: ["Password strength: ", jsx(LabelColor, { color: color, children: label })] }) }), jsx(motion.div, { initial: { opacity: 0 }, animate: {
11565
+ opacity: showPasswordIsTooWeakError ? 1 : 0,
11566
+ y: showPasswordIsTooWeakError ? 0 : -5
11567
+ }, transition: { duration: 0.3 }, style: { color: '#ef4444', fontSize: '0.875rem', fontWeight: 500, position: 'absolute', top: '0' }, children: "Password is too weak" })] })] }));
11568
+ };
11569
+
11570
+ const TickListContainer = styled.ul `
11571
+ display: flex;
11572
+ flex-direction: column;
11573
+ gap: 8px;
11574
+ padding-top: 8px;
11575
+ padding-bottom: 8px;
11576
+ `;
11577
+ const TickItem = styled.li `
11578
+ display: flex;
11579
+ align-items: center;
11580
+ text-align: left;
11581
+ gap: 8px;
11582
+ font-size: 16px;
11583
+ line-height: 24px;
11584
+ `;
11585
+ const TickIconWrapper = styled.span `
11586
+ display: flex;
11587
+ align-items: center;
11588
+ justify-content: center;
11589
+ width: 16px;
11590
+ height: 16px;
11591
+ flex-shrink: 0;
11592
+ `;
11593
+
11594
+ const TickList = ({ items }) => {
11595
+ return (jsx(TickListContainer, { children: items.map((item, index) => (jsxs(TickItem, { children: [jsx(TickIconWrapper, { children: jsx(TickIcon, {}) }), jsx("span", { children: item })] }, index))) }));
11596
+ };
11597
+ TickList.displayName = 'TickList';
11598
+
11599
+ const OtherMethodButton = styled.button `
11600
+ width: 100%;
11601
+ color: var(--ck-body-color-muted);
11602
+ transition: color 0.2s;
11603
+ font-size: 14px;
11604
+ margin-top: 10px;
11605
+
11606
+ &:hover {
11607
+ color: var(--ck-body-color);
11608
+ }
11609
+ `;
11610
+
11432
11611
  // TODO: Localize
11433
- const Recover = () => {
11434
- const [recoveryPhrase, setRecoveryPhrase] = React.useState("");
11435
- const [recoveryError, setRecoveryError] = React.useState(false);
11612
+ const RecoverPasswordWallet = ({ wallet }) => {
11613
+ const [recoveryPhrase, setRecoveryPhrase] = useState("");
11614
+ const [recoveryError, setRecoveryError] = useState(false);
11436
11615
  const { triggerResize, uiConfig: options, log } = useOpenfort();
11437
- useChainId();
11438
- const [loading, setLoading] = React.useState(false);
11616
+ const [loading, setLoading] = useState(false);
11439
11617
  const { setActiveWallet } = useWallets();
11440
11618
  const handleSubmit = async () => {
11441
11619
  setLoading(true);
11442
11620
  const { error } = await setActiveWallet({
11443
11621
  connector: embeddedWalletId,
11444
11622
  password: recoveryPhrase,
11623
+ address: wallet.address,
11445
11624
  });
11446
11625
  setLoading(false);
11447
11626
  if (error) {
@@ -11455,34 +11634,172 @@ const Recover = () => {
11455
11634
  if (recoveryError)
11456
11635
  triggerResize();
11457
11636
  }, [recoveryError]);
11458
- return (jsxs(PageContent, { children: [jsxs(Graphic, { "$height": "110px", children: [jsxs(LogoGroup, { children: [jsx(Logo$2, { children: jsx(LogoPosition, { children: jsx(LogoInner, { children: jsx(FloatWrapper, { children: jsx(RotateWrapper, { children: jsx(LogoGraphic, { style: { transform: "scale(1.2)" }, children: jsx(KeyIcon, {}) }) }) }) }) }) }), jsx(Logo$2, { children: jsx(LogoPosition, { children: jsx(LogoInner, { children: jsx(FloatWrapper, { children: jsx(RotateWrapper, { children: jsx(LogoGraphic, { style: { transform: "scale(0.75)" }, children: jsx(ShieldIcon, {}) }) }) }) }) }) }), jsx(Logo$2, {}), jsx(Logo$2, {}), jsx(Logo$2, { children: jsx(LogoPosition, { children: jsx(LogoInner, { children: jsx(FloatWrapper, { children: jsx(RotateWrapper, { children: jsx(LogoGraphic, { style: { transform: "scale(0.5)" }, children: jsx(LockIcon, {}) }) }) }) }) }) })] }), jsx(GraphicBackground, { children: wave })] }), jsx(ModalHeading, { children: "Secure your account" }), jsx(ModalBody, { style: { textAlign: "center" }, children: jsx(FitText, { children: "Set or enter your password to secure your account." }) }), jsxs("form", { onSubmit: (e) => {
11637
+ const ensFallbackConfig = useEnsFallbackConfig();
11638
+ const { data: ensName } = useEnsName({
11639
+ chainId: 1,
11640
+ address: wallet.address,
11641
+ config: ensFallbackConfig,
11642
+ });
11643
+ const separator = '....';
11644
+ return (jsxs(PageContent, { children: [jsxs(Graphic, { "$height": "130px", children: [jsxs(LogoGroup, { children: [jsx(Logo$2, { children: jsx(LogoPosition, { children: jsx(LogoInner, { children: jsx(FloatWrapper, { children: jsx(RotateWrapper, { children: jsx(LogoGraphic, { style: { transform: "scale(1.2)" }, children: jsx(KeyIcon, {}) }) }) }) }) }) }), jsx(Logo$2, { children: jsx(LogoPosition, { children: jsx(LogoInner, { children: jsx(FloatWrapper, { children: jsx(RotateWrapper, { children: jsx(LogoGraphic, { style: { transform: "scale(0.75)" }, children: jsx(ShieldIcon, {}) }) }) }) }) }) }), jsx(Logo$2, {}), jsx(Logo$2, {}), jsx(Logo$2, { children: jsx(LogoPosition, { children: jsx(LogoInner, { children: jsx(FloatWrapper, { children: jsx(RotateWrapper, { children: jsx(LogoGraphic, { style: { transform: "scale(0.5)" }, children: jsx(LockIcon, {}) }) }) }) }) }) })] }), jsx(GraphicBackground, { children: wave })] }), jsx(ModalHeading, { children: "Recover wallet" }), jsxs(ModalBody, { style: { textAlign: "center" }, children: ["Please enter the recovery password to recover wallet", " ", jsx(CopyToClipboard, { string: wallet.address, children: ensName !== null && ensName !== void 0 ? ensName : truncateEthAddress(wallet.address, separator) })] }), jsxs("form", { onSubmit: (e) => {
11459
11645
  e.preventDefault();
11460
11646
  handleSubmit();
11461
- }, children: [jsx(Input, { value: recoveryPhrase, onChange: (e) => setRecoveryPhrase(e.target.value), type: "password", placeholder: "Enter your password", autoComplete: "off" }), recoveryError && (jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: jsx(ModalBody, { style: { height: 24, marginTop: 12 }, "$error": true, children: jsx(FitText, { children: recoveryError }) }) }, recoveryError)), jsx(Button, { onClick: handleSubmit, waiting: loading, disabled: loading, children: "Enter" })] })] }));
11647
+ }, children: [jsx(Input, { value: recoveryPhrase, onChange: (e) => setRecoveryPhrase(e.target.value), type: "password", placeholder: "Enter your password", autoComplete: "off" }), recoveryError && (jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: jsx(ModalBody, { style: { height: 24, marginTop: 12 }, "$error": true, children: jsx(FitText, { children: recoveryError }) }) }, recoveryError)), jsx(Button, { onClick: handleSubmit, waiting: loading, disabled: loading, children: "Recover wallet" })] })] }));
11462
11648
  };
11463
- const AutomaticRecovery = () => {
11464
- const { needsRecovery } = useOpenfortCore();
11649
+ const RecoverAutomaticWallet = ({ walletAddress }) => {
11650
+ const { embeddedState } = useOpenfortCore();
11465
11651
  const { setActiveWallet } = useWallets();
11466
11652
  const { log } = useOpenfort();
11467
- const [hasRecoveryMethod, setHasRecoveryMethod] = React.useState(false);
11653
+ const [error, setError] = useState(false);
11468
11654
  useEffect(() => {
11469
11655
  (async () => {
11470
- if (!needsRecovery) {
11471
- log("Automatic recovery enabled, configuring embedded signer");
11656
+ if (embeddedState === EmbeddedState.EMBEDDED_SIGNER_NOT_CONFIGURED) {
11657
+ log("Automatically recovering wallet", walletAddress);
11472
11658
  const response = await setActiveWallet({
11473
11659
  connector: embeddedWalletId,
11474
11660
  });
11475
- // TODO: Handle error properly
11476
- if (response.error && response.error.message === "Missing recovery password") {
11477
- setHasRecoveryMethod(true);
11661
+ if (response.error) {
11662
+ setError(response.error.message || "There was an error recovering your account");
11663
+ log("Error recovering wallet", response.error);
11478
11664
  }
11479
11665
  }
11480
11666
  })();
11481
- }, [needsRecovery]);
11482
- if (hasRecoveryMethod) {
11483
- return jsx(Recover, {});
11667
+ }, [embeddedState]);
11668
+ if (error) {
11669
+ jsx(PageContent, { children: jsx(ModalBody, { style: { textAlign: "center" }, "$error": true, children: jsx(FitText, { children: error }) }) });
11670
+ }
11671
+ return (jsx(PageContent, { children: jsx(Loader, { reason: `Recovering wallet...` }) }));
11672
+ };
11673
+ const CreateWalletAutomaticRecovery = () => {
11674
+ const { embeddedState } = useOpenfortCore();
11675
+ const { createWallet } = useWallets();
11676
+ const [shouldCreateWallet, setShouldCreateWallet] = useState(false);
11677
+ const { log } = useOpenfort();
11678
+ useEffect(() => {
11679
+ // To ensure the wallet is created only once
11680
+ if (shouldCreateWallet) {
11681
+ (async () => {
11682
+ log("Creating wallet Automatic recover");
11683
+ const response = await createWallet();
11684
+ if (response.error) {
11685
+ log("Error creating wallet", response.error);
11686
+ }
11687
+ })();
11688
+ }
11689
+ }, [shouldCreateWallet]);
11690
+ useEffect(() => {
11691
+ if (embeddedState === EmbeddedState.EMBEDDED_SIGNER_NOT_CONFIGURED) {
11692
+ setShouldCreateWallet(true);
11693
+ }
11694
+ }, [embeddedState]);
11695
+ return (jsx(PageContent, { children: jsx(Loader, { reason: "Creating wallet..." }) }));
11696
+ };
11697
+ const OtherMethod = ({ currentMethod, onChangeMethod }) => {
11698
+ const { uiConfig } = useOpenfort();
11699
+ const otherMethods = useMemo(() => {
11700
+ const allowedMethods = uiConfig.walletRecovery.allowedMethods;
11701
+ const otherMethods = allowedMethods.filter((method) => method !== currentMethod);
11702
+ return otherMethods;
11703
+ }, [uiConfig, currentMethod]);
11704
+ if (otherMethods.length === 0)
11705
+ return null;
11706
+ if (otherMethods.length === 1) {
11707
+ const method = otherMethods[0];
11708
+ let text;
11709
+ switch (method) {
11710
+ case RecoveryMethod.PASSWORD:
11711
+ text = "Use password recovery";
11712
+ break;
11713
+ case RecoveryMethod.AUTOMATIC:
11714
+ text = "Skip for now";
11715
+ break;
11716
+ default:
11717
+ text = method;
11718
+ }
11719
+ return (jsx(OtherMethodButton, { onClick: () => {
11720
+ onChangeMethod(method);
11721
+ }, children: text }));
11722
+ }
11723
+ return (jsx(OtherMethodButton, { onClick: () => onChangeMethod("other"), children: "Choose another recovery method" }));
11724
+ };
11725
+ const CreateWalletPasswordRecovery = ({ onChangeMethod }) => {
11726
+ const [recoveryPhrase, setRecoveryPhrase] = useState("");
11727
+ const [recoveryError, setRecoveryError] = useState(false);
11728
+ const { triggerResize, uiConfig: options, log } = useOpenfort();
11729
+ const [showPasswordIsTooWeakError, setShowPasswordIsTooWeakError] = useState(false);
11730
+ const [loading, setLoading] = useState(false);
11731
+ const { createWallet } = useWallets();
11732
+ const handleSubmit = async () => {
11733
+ if (getPasswordStrength(recoveryPhrase) < MEDIUM_SCORE_THRESHOLD) {
11734
+ setShowPasswordIsTooWeakError(true);
11735
+ return;
11736
+ }
11737
+ setLoading(true);
11738
+ const { error } = await createWallet({
11739
+ password: recoveryPhrase,
11740
+ });
11741
+ setLoading(false);
11742
+ if (error) {
11743
+ setRecoveryError(error.message || "There was an error recovering your account");
11744
+ }
11745
+ else {
11746
+ log("Recovery success");
11747
+ }
11748
+ };
11749
+ useEffect(() => {
11750
+ if (recoveryError)
11751
+ triggerResize();
11752
+ }, [recoveryError]);
11753
+ return (jsxs(PageContent, { children: [jsxs(Graphic, { "$height": "80px", children: [jsxs(LogoGroup, { children: [jsx(Logo$2, { children: jsx(LogoPosition, { children: jsx(LogoInner, { children: jsx(FloatWrapper, { children: jsx(RotateWrapper, { children: jsx(LogoGraphic, { style: { transform: "scale(1.2)" }, children: jsx(KeyIcon, {}) }) }) }) }) }) }), jsx(Logo$2, { children: jsx(LogoPosition, { children: jsx(LogoInner, { children: jsx(FloatWrapper, { children: jsx(RotateWrapper, { children: jsx(LogoGraphic, { style: { transform: "scale(0.75)" }, children: jsx(ShieldIcon, {}) }) }) }) }) }) }), jsx("div", {}), jsx("div", {}), jsx(Logo$2, { children: jsx(LogoPosition, { children: jsx(LogoInner, { children: jsx(FloatWrapper, { children: jsx(RotateWrapper, { children: jsx(LogoGraphic, { style: { transform: "scale(0.5)" }, children: jsx(LockIcon, {}) }) }) }) }) }) })] }), jsx(GraphicBackground, { children: wave })] }), jsx(ModalHeading, { children: "Secure your wallet" }), jsxs(ModalBody, { style: { textAlign: "center" }, children: [jsx(FitText, { children: "Set a password for your wallet." }), jsxs("form", { onSubmit: (e) => {
11754
+ e.preventDefault();
11755
+ handleSubmit();
11756
+ }, children: [jsx(Input, { value: recoveryPhrase, onChange: (e) => {
11757
+ if (showPasswordIsTooWeakError)
11758
+ setShowPasswordIsTooWeakError(false);
11759
+ setRecoveryPhrase(e.target.value);
11760
+ }, type: "password", placeholder: "Enter your password", autoComplete: "off" }), jsx(PasswordStrengthIndicator, { password: recoveryPhrase, showPasswordIsTooWeakError: showPasswordIsTooWeakError }), jsx(TickList, { items: [
11761
+ "You will use this password to access your wallet",
11762
+ "Make sure it's strong and memorable",
11763
+ ] }), recoveryError && (jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: jsx(ModalBody, { style: { height: 24, marginTop: 12 }, "$error": true, children: jsx(FitText, { children: recoveryError }) }) }, recoveryError)), jsx(Button, { onClick: handleSubmit, waiting: loading, disabled: loading, children: "Create wallet" })] }), jsx(OtherMethod, { currentMethod: RecoveryMethod.PASSWORD, onChangeMethod: onChangeMethod })] })] }));
11764
+ };
11765
+ const ChooseRecoveryMethod = ({ onChangeMethod }) => {
11766
+ return (jsxs(PageContent, { children: [jsx(ModalHeading, { children: "Choose a recovery method" }), jsx(Button, { onClick: () => onChangeMethod(RecoveryMethod.PASSWORD), children: "Password" }), jsx(Button, { onClick: () => onChangeMethod(RecoveryMethod.AUTOMATIC), children: "Automatic" }), jsx(Button, { onClick: () => { }, children: "Passkey (coming soon)" })] }));
11767
+ };
11768
+ const RecoverWallet = ({ wallet }) => {
11769
+ switch (wallet.recoveryMethod) {
11770
+ case RecoveryMethod.PASSWORD:
11771
+ return jsx(RecoverPasswordWallet, { wallet: wallet });
11772
+ case RecoveryMethod.AUTOMATIC:
11773
+ return jsx(RecoverAutomaticWallet, { walletAddress: wallet.address });
11774
+ default:
11775
+ console.error("Unsupported recovery method: " + wallet.recoveryMethod + ", defaulting to automatic.");
11776
+ return jsx(RecoverAutomaticWallet, { walletAddress: wallet.address });
11777
+ }
11778
+ };
11779
+ const CreateWallet = () => {
11780
+ const { uiConfig } = useOpenfort();
11781
+ const [userSelectedMethod, setUserSelectedMethod] = useState(null);
11782
+ if (userSelectedMethod) {
11783
+ switch (userSelectedMethod) {
11784
+ case RecoveryMethod.PASSWORD:
11785
+ return jsx(CreateWalletPasswordRecovery, { onChangeMethod: setUserSelectedMethod });
11786
+ case RecoveryMethod.AUTOMATIC:
11787
+ return jsx(CreateWalletAutomaticRecovery, {});
11788
+ case "other":
11789
+ return jsx(ChooseRecoveryMethod, { onChangeMethod: setUserSelectedMethod });
11790
+ default:
11791
+ throw new Error("Unsupported recovery method: " + userSelectedMethod);
11792
+ }
11793
+ }
11794
+ // Default recovery method configured
11795
+ switch (uiConfig.walletRecovery.defaultMethod) {
11796
+ case RecoveryMethod.PASSWORD:
11797
+ return jsx(CreateWalletPasswordRecovery, { onChangeMethod: setUserSelectedMethod });
11798
+ case RecoveryMethod.AUTOMATIC:
11799
+ return jsx(CreateWalletAutomaticRecovery, {});
11800
+ default:
11801
+ throw new Error("Unsupported recovery method: " + uiConfig.walletRecovery.defaultMethod);
11484
11802
  }
11485
- return (jsx(PageContent, { children: jsx(Loader, { reason: "Setting up signer" }) }));
11486
11803
  };
11487
11804
  const Connected = () => {
11488
11805
  const { setOpen } = useOpenfort();
@@ -11494,49 +11811,81 @@ const Connected = () => {
11494
11811
  }, []);
11495
11812
  return (jsx(PageContent, { children: jsx(Loader, { isLoading: false, reason: "Connected" }) }));
11496
11813
  };
11497
- const CreateEmbeddedSigner = () => {
11814
+ const RecoverPage = () => {
11498
11815
  const { needsRecovery, user } = useOpenfortCore();
11499
11816
  const { triggerResize, uiConfig, walletConfig, setRoute } = useOpenfort();
11500
- const [loading, setLoading] = React.useState(true);
11501
- const [embeddedSignerLoading, setEmbeddedSignerLoading] = React.useState(true);
11817
+ const { wallets, isLoadingWallets } = useWallets();
11818
+ // const [loading, setLoading] = useState(true);
11819
+ const [embeddedSignerLoading, setEmbeddedSignerLoading] = useState(true);
11502
11820
  const { isConnected } = useAccount();
11503
11821
  useEffect(() => {
11504
- setTimeout(() => {
11505
- setEmbeddedSignerLoading(false);
11506
- triggerResize();
11507
- }, 500);
11508
- }, []);
11509
- useEffect(() => {
11510
- if (!user)
11511
- return;
11512
- if ((uiConfig === null || uiConfig === void 0 ? void 0 : uiConfig.linkWalletOnSignUp) || !walletConfig) {
11513
- if (!user.linkedAccounts.find((account) => account.provider === "wallet")) {
11514
- setRoute(routes.CONNECTORS);
11515
- return;
11516
- }
11517
- if (!walletConfig) {
11518
- // Logged in without a wallet
11519
- setRoute(routes.PROFILE);
11520
- return;
11521
- }
11822
+ let timeout;
11823
+ if (!isLoadingWallets) {
11824
+ timeout = setTimeout(() => {
11825
+ setEmbeddedSignerLoading(false);
11826
+ triggerResize();
11827
+ }, 500);
11522
11828
  }
11523
- setLoading(false);
11524
- }, [user]);
11525
- if (embeddedSignerLoading || loading) {
11526
- return (jsx(PageContent, { children: jsx(Loader, { reason: "Setting up signer" }) }));
11829
+ return () => { clearTimeout(timeout); };
11830
+ }, [isLoadingWallets]);
11831
+ const openfortWallets = useMemo(() => {
11832
+ return wallets.filter((wallet) => wallet.id === embeddedWalletId);
11833
+ }, [wallets]);
11834
+ // useEffect(() => {
11835
+ // if (!user) return;
11836
+ // if (uiConfig?.linkWalletOnSignUp || !walletConfig) {
11837
+ // if (!user.linkedAccounts.find((account) => account.provider === "wallet")) {
11838
+ // setRoute(routes.CONNECTORS);
11839
+ // return;
11840
+ // }
11841
+ // if (!walletConfig) {
11842
+ // // Logged in without a wallet
11843
+ // setRoute(routes.PROFILE);
11844
+ // return;
11845
+ // }
11846
+ // }
11847
+ // setLoading(false);
11848
+ // }, [user])
11849
+ if (embeddedSignerLoading) {
11850
+ return (jsx(PageContent, { children: jsx(Loader, { reason: "Setting up wallet" }) }));
11527
11851
  }
11528
11852
  if (isConnected && user) {
11529
11853
  return jsx(Connected, {});
11530
11854
  }
11531
- if (walletConfig && walletConfig.recoveryMethod === RecoveryMethod.AUTOMATIC) {
11532
- return jsx(AutomaticRecovery, {});
11533
- }
11534
- if (needsRecovery) {
11535
- return jsx(Recover, {});
11855
+ if (!openfortWallets) {
11856
+ // Here wallets should be loaded, so if we don't have them something went wrong
11857
+ // TODO: add error logs
11858
+ return (jsx(PageContent, { children: "An unexpected error occurred. Please try again later." }));
11536
11859
  }
11537
- else {
11538
- return (jsx(PageContent, { children: jsx(Loader, { reason: "Setting up signer" }) }));
11860
+ if (openfortWallets.length === 0) {
11861
+ return (jsx(CreateWallet, {}));
11539
11862
  }
11863
+ // if (wallets.length === 1) {
11864
+ return (jsx(RecoverWallet, { wallet: openfortWallets[0] }));
11865
+ // }
11866
+ // return (
11867
+ // <PageContent>
11868
+ // <div style={{ flexDirection: "column", display: "flex", gap: 8 }}>
11869
+ // {wallets.map((wallet) => (
11870
+ // <div key={wallet.address}>
11871
+ // {wallet.address} - {wallet.recoveryMethod} recover
11872
+ // </div>
11873
+ // ))}
11874
+ // </div>
11875
+ // </PageContent>
11876
+ // )
11877
+ // if (walletConfig && walletConfig.recoveryMethod === RecoveryMethod.AUTOMATIC) {
11878
+ // return <AutomaticRecovery />
11879
+ // }
11880
+ // if (needsRecovery) {
11881
+ // return <Recover />
11882
+ // } else {
11883
+ // return (
11884
+ // <PageContent>
11885
+ // <Loader reason="Setting up signer" />
11886
+ // </PageContent>
11887
+ // )
11888
+ // }
11540
11889
  };
11541
11890
 
11542
11891
  const SocialProviders = () => {
@@ -11608,7 +11957,7 @@ const ConnectModal = ({ mode = 'auto', theme = 'auto', customTheme = customTheme
11608
11957
  connect: jsx(ConnectUsing, {}),
11609
11958
  profile: jsx(Profile, {}),
11610
11959
  switchNetworks: jsx(SwitchNetworks, {}),
11611
- recover: jsx(CreateEmbeddedSigner, {}),
11960
+ recover: jsx(RecoverPage, {}),
11612
11961
  };
11613
11962
  function hide() {
11614
11963
  context.setOpen(false);
@@ -11705,8 +12054,9 @@ const OpenfortProvider = ({ children, uiConfig, onConnect, onDisconnect, debugMo
11705
12054
  }
11706
12055
  const chains = useChains();
11707
12056
  const injectedConnector = useConnector('injected');
12057
+ const allowAutomaticRecovery = !!((walletConfig === null || walletConfig === void 0 ? void 0 : walletConfig.createEncryptedSessionEndpoint) || (walletConfig === null || walletConfig === void 0 ? void 0 : walletConfig.getEncryptionSession));
11708
12058
  // Default config options
11709
- const defaultOptions = {
12059
+ const defaultUIOptions = {
11710
12060
  theme: 'auto',
11711
12061
  mode: 'auto',
11712
12062
  language: 'en-US',
@@ -11729,20 +12079,33 @@ const OpenfortProvider = ({ children, uiConfig, onConnect, onDisconnect, debugMo
11729
12079
  ethereumOnboardingUrl: undefined,
11730
12080
  walletOnboardingUrl: undefined,
11731
12081
  disableSiweRedirect: false,
11732
- // Openfort options
11733
- authProviders: [],
11734
- };
11735
- const opts = Object.assign({}, defaultOptions, uiConfig);
11736
- if (!opts.authProviders || opts.authProviders.length === 0) {
11737
- opts.authProviders = [
12082
+ walletRecovery: {
12083
+ allowedMethods: [
12084
+ RecoveryMethod.PASSWORD,
12085
+ ...(allowAutomaticRecovery ? [RecoveryMethod.AUTOMATIC] : [])
12086
+ ],
12087
+ defaultMethod: allowAutomaticRecovery ? RecoveryMethod.AUTOMATIC : RecoveryMethod.PASSWORD,
12088
+ },
12089
+ authProviders: [
11738
12090
  AuthProvider.GUEST,
11739
12091
  AuthProvider.EMAIL,
11740
12092
  AuthProvider.WALLET,
11741
- ];
12093
+ ],
12094
+ };
12095
+ const safeUiConfig = Object.assign({}, defaultUIOptions, uiConfig);
12096
+ if (!safeUiConfig.walletRecovery.allowedMethods) {
12097
+ safeUiConfig.walletRecovery.allowedMethods = defaultUIOptions.walletRecovery.allowedMethods;
12098
+ }
12099
+ if (!safeUiConfig.walletRecovery.defaultMethod) {
12100
+ safeUiConfig.walletRecovery.defaultMethod = defaultUIOptions.walletRecovery.defaultMethod;
12101
+ }
12102
+ if (safeUiConfig.walletRecovery.allowedMethods.includes(RecoveryMethod.AUTOMATIC) && !allowAutomaticRecovery) {
12103
+ safeUiConfig.walletRecovery.allowedMethods = safeUiConfig.walletRecovery.allowedMethods.filter(m => m !== RecoveryMethod.AUTOMATIC);
12104
+ console.warn("Automatic recovery method was removed from allowedMethods because no recovery options are configured in the walletConfig. Please provide either createEncryptedSessionEndpoint or getEncryptionSession to enable automatic recovery.");
11742
12105
  }
11743
12106
  if (typeof window !== 'undefined') {
11744
12107
  // Buffer Polyfill, needed for bundlers that don't provide Node polyfills (e.g CRA, Vite, etc.)
11745
- if (opts.bufferPolyfill)
12108
+ if (safeUiConfig.bufferPolyfill)
11746
12109
  window.Buffer = (_b = window.Buffer) !== null && _b !== void 0 ? _b : Buffer;
11747
12110
  // Some bundlers may need `global` and `process.env` polyfills as well
11748
12111
  // Not implemented here to avoid unexpected behaviors, but leaving example here for future reference
@@ -11751,8 +12114,8 @@ const OpenfortProvider = ({ children, uiConfig, onConnect, onDisconnect, debugMo
11751
12114
  * window.process = window.process ?? { env: {} };
11752
12115
  */
11753
12116
  }
11754
- const [ckTheme, setTheme] = useState((_d = (_c = uiConfig === null || uiConfig === void 0 ? void 0 : uiConfig.theme) !== null && _c !== void 0 ? _c : defaultOptions.theme) !== null && _d !== void 0 ? _d : "auto");
11755
- const [ckMode, setMode] = useState((_f = (_e = uiConfig === null || uiConfig === void 0 ? void 0 : uiConfig.mode) !== null && _e !== void 0 ? _e : defaultOptions.mode) !== null && _f !== void 0 ? _f : 'auto');
12117
+ const [ckTheme, setTheme] = useState((_d = (_c = uiConfig === null || uiConfig === void 0 ? void 0 : uiConfig.theme) !== null && _c !== void 0 ? _c : defaultUIOptions.theme) !== null && _d !== void 0 ? _d : "auto");
12118
+ const [ckMode, setMode] = useState((_f = (_e = uiConfig === null || uiConfig === void 0 ? void 0 : uiConfig.mode) !== null && _e !== void 0 ? _e : defaultUIOptions.mode) !== null && _f !== void 0 ? _f : 'auto');
11756
12119
  const [ckCustomTheme, setCustomTheme] = useState((_g = uiConfig === null || uiConfig === void 0 ? void 0 : uiConfig.customTheme) !== null && _g !== void 0 ? _g : {});
11757
12120
  const [ckLang, setLang] = useState('en-US');
11758
12121
  const [open, setOpen] = useState(false);
@@ -11763,17 +12126,17 @@ const OpenfortProvider = ({ children, uiConfig, onConnect, onDisconnect, debugMo
11763
12126
  const [errorMessage, setErrorMessage] = useState('');
11764
12127
  const [resize, onResize] = useState(0);
11765
12128
  // Include Google Font that is needed for a themes
11766
- if (opts.embedGoogleFonts)
12129
+ if (safeUiConfig.embedGoogleFonts)
11767
12130
  useThemeFont(ckTheme);
11768
12131
  // Other Configuration
11769
12132
  useEffect(() => { var _a; return setTheme((_a = uiConfig === null || uiConfig === void 0 ? void 0 : uiConfig.theme) !== null && _a !== void 0 ? _a : 'auto'); }, [uiConfig === null || uiConfig === void 0 ? void 0 : uiConfig.theme]);
11770
- useEffect(() => setLang(opts.language || 'en-US'), [opts.language]);
12133
+ useEffect(() => setLang(safeUiConfig.language || 'en-US'), [safeUiConfig.language]);
11771
12134
  useEffect(() => setErrorMessage(null), [route, open]);
11772
12135
  // Check if chain is supported, elsewise redirect to switches page
11773
12136
  const { chain, isConnected } = useAccount();
11774
12137
  const isChainSupported = useChainIsSupported(chain === null || chain === void 0 ? void 0 : chain.id);
11775
12138
  useEffect(() => {
11776
- if (isConnected && opts.enforceSupportedChains && !isChainSupported) {
12139
+ if (isConnected && safeUiConfig.enforceSupportedChains && !isChainSupported) {
11777
12140
  setOpen(true);
11778
12141
  setRoute(routes.SWITCHNETWORKS);
11779
12142
  }
@@ -11804,7 +12167,7 @@ const OpenfortProvider = ({ children, uiConfig, onConnect, onDisconnect, debugMo
11804
12167
  onConnect,
11805
12168
  onDisconnect,
11806
12169
  // Other configuration
11807
- uiConfig: opts,
12170
+ uiConfig: safeUiConfig,
11808
12171
  errorMessage,
11809
12172
  debugMode,
11810
12173
  log,
@@ -11826,7 +12189,6 @@ const OpenfortProvider = ({ children, uiConfig, onConnect, onDisconnect, debugMo
11826
12189
  publishableKey,
11827
12190
  }, shieldConfiguration: walletConfig ? {
11828
12191
  shieldPublishableKey: walletConfig.shieldPublishableKey,
11829
- shieldEncryptionKey: walletConfig.recoveryMethod === RecoveryMethod.PASSWORD ? walletConfig.shieldEncryptionKey : undefined,
11830
12192
  debug: debugMode,
11831
12193
  } : undefined, overrides: overrides, thirdPartyAuth: thirdPartyAuth, debugMode: debugMode, onConnect: onConnect, onDisconnect: onDisconnect, children: [children, jsx(ConnectModal, { lang: ckLang, theme: ckTheme, mode: (_h = uiConfig === null || uiConfig === void 0 ? void 0 : uiConfig.mode) !== null && _h !== void 0 ? _h : ckMode, customTheme: ckCustomTheme })] }) }) }));
11832
12194
  };
@@ -12248,7 +12610,7 @@ const ConnectedLabel = ({ separator }) => {
12248
12610
  if (!user)
12249
12611
  return "Loading user...";
12250
12612
  if (!address)
12251
- return truncateUserId(user.id, separator);
12613
+ return "Not connected";
12252
12614
  return "Loading...";
12253
12615
  };
12254
12616
  function OpenfortButtonInner({ label, showAvatar, separator, }) {
@@ -12369,21 +12731,16 @@ const mapStatus = (status) => {
12369
12731
  };
12370
12732
 
12371
12733
  function useSignOut(hookOptions = {}) {
12372
- const { client, updateUser, user } = useOpenfortCore();
12734
+ const { logout } = useOpenfortCore();
12373
12735
  const [status, setStatus] = useState({
12374
12736
  status: "idle",
12375
12737
  });
12376
- const { disconnect } = useDisconnect();
12377
- const queryClient = useQueryClient();
12378
12738
  const signOut = useCallback(async (options = {}) => {
12379
12739
  setStatus({
12380
12740
  status: 'loading',
12381
12741
  });
12382
12742
  try {
12383
- await client.auth.logout();
12384
- queryClient.resetQueries({ queryKey: ['openfortEmbeddedWalletList'] });
12385
- disconnect();
12386
- updateUser();
12743
+ logout();
12387
12744
  setStatus({
12388
12745
  status: 'success',
12389
12746
  });
@@ -12405,7 +12762,7 @@ function useSignOut(hookOptions = {}) {
12405
12762
  error,
12406
12763
  });
12407
12764
  }
12408
- }, [client, user, disconnect, updateUser, setStatus, hookOptions]);
12765
+ }, [logout, setStatus, hookOptions]);
12409
12766
  return {
12410
12767
  ...mapStatus(status),
12411
12768
  signOut,
@@ -12413,22 +12770,43 @@ function useSignOut(hookOptions = {}) {
12413
12770
  }
12414
12771
 
12415
12772
  // this hook is used to create a wallet after the user has authenticated
12416
- const useCreateWalletPostAuth = () => {
12417
- const { setActiveWallet } = useWallets();
12773
+ const useConnectToWalletPostAuth = () => {
12774
+ const { createWallet, setActiveWallet } = useWallets();
12418
12775
  const { walletConfig } = useOpenfort();
12419
12776
  const { signOut } = useSignOut();
12777
+ const queryClient = useQueryClient();
12420
12778
  const tryUseWallet = useCallback(async ({ logoutOnError: signOutOnError = true, automaticRecovery = true }) => {
12421
- if (!walletConfig || walletConfig.recoveryMethod !== RecoveryMethod.AUTOMATIC || !automaticRecovery) {
12779
+ console.log("tryUseWallet", { walletConfig, automaticRecovery });
12780
+ if ((!(walletConfig === null || walletConfig === void 0 ? void 0 : walletConfig.createEncryptedSessionEndpoint) && !(walletConfig === null || walletConfig === void 0 ? void 0 : walletConfig.getEncryptionSession)) || !automaticRecovery) {
12781
+ // If there is no encryption session, we cannot create a wallet
12422
12782
  return {};
12423
12783
  }
12424
- const wallet = await setActiveWallet({
12425
- connector: embeddedWalletId,
12426
- });
12427
- if (wallet.error && signOutOnError) {
12428
- // If there was an error and we should log out, we can call the logout function
12429
- await signOut();
12784
+ const wallets = await queryClient.ensureQueryData({ queryKey: ['openfortEmbeddedWalletList'] });
12785
+ console.log("WALLETS", wallets);
12786
+ let wallet;
12787
+ if (wallets.length === 0) {
12788
+ const createWalletResult = await createWallet();
12789
+ if (createWalletResult.error && signOutOnError) {
12790
+ console.error("Error creating wallet:", createWalletResult.error);
12791
+ // If there was an error and we should log out, we can call the logout function
12792
+ await signOut();
12793
+ return {};
12794
+ }
12795
+ wallet = createWalletResult.wallet;
12430
12796
  }
12431
- return wallet;
12797
+ // Has a wallet with automatic recovery
12798
+ if (wallets.some(w => w.recoveryMethod === RecoveryMethod.AUTOMATIC)) {
12799
+ const setWalletResult = await setActiveWallet({
12800
+ connector: embeddedWalletId,
12801
+ });
12802
+ if (!setWalletResult.wallet || (setWalletResult.error && signOutOnError)) {
12803
+ console.error("Error recovering wallet:", setWalletResult.error);
12804
+ // If there was an error and we should log out, we can call the logout function
12805
+ await signOut();
12806
+ }
12807
+ wallet = setWalletResult.wallet;
12808
+ }
12809
+ return { wallet };
12432
12810
  }, [walletConfig, setActiveWallet, signOut]);
12433
12811
  return {
12434
12812
  tryUseWallet,
@@ -12448,7 +12826,7 @@ const useEmailAuth = (hookOptions = {}) => {
12448
12826
  });
12449
12827
  setRequiresEmailVerification(false);
12450
12828
  }, []);
12451
- const { tryUseWallet } = useCreateWalletPostAuth();
12829
+ const { tryUseWallet } = useConnectToWalletPostAuth();
12452
12830
  const signInEmail = useCallback(async (options) => {
12453
12831
  var _a;
12454
12832
  try {
@@ -12769,7 +13147,7 @@ const useOAuth = (hookOptions = {}) => {
12769
13147
  const [status, setStatus] = useState({
12770
13148
  status: "idle",
12771
13149
  });
12772
- const { tryUseWallet } = useCreateWalletPostAuth();
13150
+ const { tryUseWallet } = useConnectToWalletPostAuth();
12773
13151
  const storeCredentials = useCallback(async ({ player, accessToken, refreshToken, ...options }) => {
12774
13152
  setStatus({
12775
13153
  status: 'loading',
@@ -13017,7 +13395,7 @@ const useGuestAuth = (hookOptions = {}) => {
13017
13395
  const [status, setStatus] = useState({
13018
13396
  status: "idle",
13019
13397
  });
13020
- const { tryUseWallet } = useCreateWalletPostAuth();
13398
+ const { tryUseWallet } = useConnectToWalletPostAuth();
13021
13399
  const signUpGuest = useCallback(async (options = {}) => {
13022
13400
  try {
13023
13401
  setStatus({