@forge-connect/react 1.0.13 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/provider.tsx
2
- import { useState as useState16, useCallback as useCallback9, useEffect as useEffect12, useRef as useRef9, useMemo as useMemo3 } from "react";
2
+ import { useState as useState17, useCallback as useCallback9, useEffect as useEffect13, useRef as useRef9, useMemo as useMemo3 } from "react";
3
3
 
4
4
  // src/context.ts
5
5
  import { createContext } from "react";
@@ -454,7 +454,7 @@ function getRefreshDelay(token) {
454
454
  }
455
455
 
456
456
  // src/components/login-modal.tsx
457
- import { useState as useState6 } from "react";
457
+ import { useState as useState7 } from "react";
458
458
 
459
459
  // src/hooks/use-forge-connect.ts
460
460
  import { useContext } from "react";
@@ -843,7 +843,7 @@ function EmailOtpForm() {
843
843
  }
844
844
 
845
845
  // src/components/tabs/wallet-connect.tsx
846
- import { useState as useState3, useMemo, useRef as useRef4, useCallback } from "react";
846
+ import { useState as useState4, useMemo, useEffect as useEffect4, useRef as useRef4, useCallback } from "react";
847
847
 
848
848
  // src/components/svg-icon.tsx
849
849
  import { useRef as useRef3, useEffect as useEffect2 } from "react";
@@ -923,6 +923,65 @@ function OAuthButton({ provider }) {
923
923
  );
924
924
  }
925
925
 
926
+ // src/hooks/use-standard-wallets.ts
927
+ import { useEffect as useEffect3, useState as useState3 } from "react";
928
+ function useStandardWallets() {
929
+ const [wallets, setWallets] = useState3([]);
930
+ useEffect3(() => {
931
+ if (typeof window === "undefined") return;
932
+ let unsubRegister;
933
+ let unsubUnregister;
934
+ let cancelled = false;
935
+ (async () => {
936
+ try {
937
+ const { getWallets } = await import("@wallet-standard/app");
938
+ if (cancelled) return;
939
+ const registry = getWallets();
940
+ const update = () => {
941
+ const raw = registry.get();
942
+ const seen = /* @__PURE__ */ new Set();
943
+ const list = [];
944
+ for (const w of raw) {
945
+ if (seen.has(w.name)) continue;
946
+ seen.add(w.name);
947
+ list.push(w);
948
+ }
949
+ console.log("[ForgeConnect/MWA] useStandardWallets ->", list.map((w) => w.name), `(raw: ${raw.length})`);
950
+ setWallets(list);
951
+ };
952
+ update();
953
+ unsubRegister = registry.on("register", update);
954
+ unsubUnregister = registry.on("unregister", update);
955
+ } catch {
956
+ }
957
+ })();
958
+ return () => {
959
+ cancelled = true;
960
+ unsubRegister?.();
961
+ unsubUnregister?.();
962
+ };
963
+ }, []);
964
+ return wallets;
965
+ }
966
+
967
+ // src/lib/standard-wallet.ts
968
+ async function connectAndPrepareStandardWallet(wallet) {
969
+ const connectFeature = wallet.features["standard:connect"];
970
+ const signMessageFeature = wallet.features["solana:signMessage"];
971
+ if (!connectFeature) throw new Error(`${wallet.name} does not support standard:connect`);
972
+ if (!signMessageFeature) throw new Error(`${wallet.name} does not support solana:signMessage`);
973
+ const { accounts } = await connectFeature.connect();
974
+ const account = accounts[0];
975
+ if (!account) throw new Error(`${wallet.name} did not return any accounts`);
976
+ const signMessage = async (msg) => {
977
+ const results = await signMessageFeature.signMessage({ account, message: msg });
978
+ const first = results[0];
979
+ if (!first) throw new Error("Wallet did not return a signature");
980
+ return first.signature;
981
+ };
982
+ return { address: account.address, signMessage };
983
+ }
984
+
926
985
  // src/components/tabs/wallet-connect.tsx
927
986
  import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
928
987
  function MatricaWalletEntry() {
@@ -987,12 +1046,26 @@ function WalletConnectForm() {
987
1046
  ] });
988
1047
  }
989
1048
  function MobileWalletFlow() {
990
- const { setModalStep, config } = useForgeConnect();
1049
+ const { setModalStep, config, loginWithWallet } = useForgeConnect();
1050
+ const standardWallets = useStandardWallets();
1051
+ const [loading, setLoading] = useState4(false);
1052
+ const [error, setError] = useState4("");
991
1053
  const methods = resolveLoginMethods(config);
992
1054
  const showBack = methods.length > 1;
993
1055
  const walletConfig = config.walletConfig;
994
1056
  const preferred = walletConfig?.preferredWallets ?? [];
995
1057
  const onlyPreferred = walletConfig?.onlyPreferred ?? false;
1058
+ const handleStandardConnect = async (w) => {
1059
+ setError("");
1060
+ setLoading(true);
1061
+ try {
1062
+ const { address, signMessage } = await connectAndPrepareStandardWallet(w);
1063
+ await loginWithWallet(address, signMessage, "solana");
1064
+ } catch (err) {
1065
+ setError(err instanceof Error ? err.message : `Could not connect ${w.name}.`);
1066
+ setLoading(false);
1067
+ }
1068
+ };
996
1069
  const walletsToShow = useMemo(() => {
997
1070
  if (preferred.length > 0) {
998
1071
  const prefList = preferred.map((name) => MOBILE_WALLETS.find((mw) => mw.name === name)).filter(Boolean);
@@ -1009,8 +1082,42 @@ function MobileWalletFlow() {
1009
1082
  };
1010
1083
  const showMatrica = methods.includes("matrica");
1011
1084
  return /* @__PURE__ */ jsxs5("div", { className: "fc-tab", children: [
1012
- /* @__PURE__ */ jsxs5("div", { className: "fc-wallet-list", children: [
1085
+ loading && /* @__PURE__ */ jsxs5("div", { style: { textAlign: "center", padding: "24px 0" }, children: [
1086
+ /* @__PURE__ */ jsx6("p", { className: "fc-tab-title", children: "Connecting..." }),
1087
+ /* @__PURE__ */ jsx6("p", { className: "fc-text", children: "Approve in your wallet, then sign the verification request." }),
1088
+ error && /* @__PURE__ */ jsxs5(Fragment, { children: [
1089
+ /* @__PURE__ */ jsx6("p", { className: "fc-error", children: error }),
1090
+ /* @__PURE__ */ jsx6(
1091
+ "button",
1092
+ {
1093
+ type: "button",
1094
+ className: "fc-btn fc-btn-secondary",
1095
+ onClick: () => {
1096
+ setLoading(false);
1097
+ setError("");
1098
+ },
1099
+ style: { marginTop: 8 },
1100
+ children: "Try again"
1101
+ }
1102
+ )
1103
+ ] })
1104
+ ] }),
1105
+ !loading && /* @__PURE__ */ jsxs5("div", { className: "fc-wallet-list", children: [
1013
1106
  showMatrica && /* @__PURE__ */ jsx6(MatricaWalletEntry, {}),
1107
+ standardWallets.map((w) => /* @__PURE__ */ jsxs5(
1108
+ "button",
1109
+ {
1110
+ type: "button",
1111
+ className: "fc-btn fc-btn-wallet",
1112
+ onClick: () => handleStandardConnect(w),
1113
+ children: [
1114
+ /* @__PURE__ */ jsx6("span", { style: { position: "relative", display: "inline-flex" }, children: /* @__PURE__ */ jsx6("img", { src: w.icon, alt: "", className: "fc-wallet-icon" }) }),
1115
+ /* @__PURE__ */ jsx6("span", { className: "fc-wallet-name", children: w.name }),
1116
+ /* @__PURE__ */ jsx6("span", { className: "fc-badge-preferred", children: "Detected" })
1117
+ ]
1118
+ },
1119
+ `std:${w.name}`
1120
+ )),
1014
1121
  walletsToShow.map((mw) => /* @__PURE__ */ jsxs5(
1015
1122
  "button",
1016
1123
  {
@@ -1033,13 +1140,17 @@ function MobileWalletFlow() {
1033
1140
  function WalletAdapterFlow() {
1034
1141
  const { walletAdapter, loginWithWallet, setModalStep, config } = useForgeConnect();
1035
1142
  const wallet = walletAdapter;
1143
+ const standardWallets = useStandardWallets();
1036
1144
  const walletConfig = config.walletConfig;
1037
1145
  const methods = resolveLoginMethods(config);
1038
1146
  const showBack = methods.length > 1;
1039
- const [error, setError] = useState3("");
1040
- const [loading, setLoading] = useState3(false);
1041
- const [showOther, setShowOther] = useState3(false);
1042
- const [coldWallet, setColdWallet] = useState3(false);
1147
+ const [error, setError] = useState4("");
1148
+ const [loading, setLoading] = useState4(false);
1149
+ const [showOther, setShowOther] = useState4(false);
1150
+ useEffect4(() => {
1151
+ if (isMobile()) setShowOther(true);
1152
+ }, []);
1153
+ const [coldWallet, setColdWallet] = useState4(false);
1043
1154
  const mobile = useMemo(() => isMobile(), []);
1044
1155
  const coldWalletRef = useRef4(coldWallet);
1045
1156
  coldWalletRef.current = coldWallet;
@@ -1098,21 +1209,42 @@ function WalletAdapterFlow() {
1098
1209
  const preferredSet = new Set(preferred);
1099
1210
  const connectedWalletName = wallet.publicKey ? wallet.wallets.find((w) => w.adapter.connected)?.adapter.name ?? null : null;
1100
1211
  const { preferredWallets, otherWallets } = useMemo(() => {
1101
- const all = wallet.wallets;
1212
+ const seenNames = /* @__PURE__ */ new Set();
1213
+ const all = wallet.wallets.filter((w) => {
1214
+ if (seenNames.has(w.adapter.name)) return false;
1215
+ seenNames.add(w.adapter.name);
1216
+ return true;
1217
+ });
1102
1218
  const prefList = preferred.map((name) => all.find((w) => w.adapter.name === name)).filter(Boolean);
1103
1219
  if (onlyPreferred && preferred.length > 0) {
1104
1220
  return { preferredWallets: prefList, otherWallets: [] };
1105
1221
  }
1106
1222
  const others = all.filter(
1107
- (w) => !preferredSet.has(w.adapter.name) && w.readyState === "Installed"
1223
+ (w) => !preferredSet.has(w.adapter.name) && (w.readyState === "Installed" || mobile && w.readyState === "Loadable")
1108
1224
  );
1109
1225
  return { preferredWallets: prefList, otherWallets: others };
1110
- }, [wallet.wallets, walletConfig]);
1226
+ }, [wallet.wallets, walletConfig, mobile]);
1111
1227
  const mobileExtraWallets = useMemo(() => {
1112
1228
  if (!mobile) return [];
1113
1229
  const adapterNames = new Set(wallet.wallets.map((w) => w.adapter.name));
1114
- return MOBILE_WALLETS.filter((mw) => !adapterNames.has(mw.name));
1115
- }, [mobile, wallet.wallets]);
1230
+ const stdNames = new Set(standardWallets.map((w) => w.name));
1231
+ return MOBILE_WALLETS.filter((mw) => !adapterNames.has(mw.name) && !stdNames.has(mw.name));
1232
+ }, [mobile, wallet.wallets, standardWallets]);
1233
+ const standardExtras = useMemo(() => {
1234
+ const adapterNames = new Set(wallet.wallets.map((w) => w.adapter.name));
1235
+ return standardWallets.filter((w) => !adapterNames.has(w.name));
1236
+ }, [wallet.wallets, standardWallets]);
1237
+ const handleStandardConnect = async (w) => {
1238
+ setError("");
1239
+ setLoading(true);
1240
+ try {
1241
+ const { address, signMessage } = await connectAndPrepareStandardWallet(w);
1242
+ await loginWithWallet(address, signMessage, "solana");
1243
+ } catch (err) {
1244
+ setError(err instanceof Error ? err.message : `Could not connect ${w.name}.`);
1245
+ setLoading(false);
1246
+ }
1247
+ };
1116
1248
  return /* @__PURE__ */ jsxs5("div", { className: "fc-tab", children: [
1117
1249
  loading ? /* @__PURE__ */ jsxs5("div", { style: { textAlign: "center", padding: "24px 0" }, children: [
1118
1250
  /* @__PURE__ */ jsx6("p", { className: "fc-tab-title", children: "Connecting..." }),
@@ -1155,6 +1287,20 @@ function WalletAdapterFlow() {
1155
1287
  w.adapter.name
1156
1288
  );
1157
1289
  }),
1290
+ standardExtras.map((w) => /* @__PURE__ */ jsxs5(
1291
+ "button",
1292
+ {
1293
+ type: "button",
1294
+ className: "fc-btn fc-btn-wallet",
1295
+ onClick: () => handleStandardConnect(w),
1296
+ children: [
1297
+ /* @__PURE__ */ jsx6("span", { style: { position: "relative", display: "inline-flex" }, children: /* @__PURE__ */ jsx6("img", { src: w.icon, alt: "", className: "fc-wallet-icon" }) }),
1298
+ /* @__PURE__ */ jsx6("span", { className: "fc-wallet-name", children: w.name }),
1299
+ /* @__PURE__ */ jsx6("span", { className: "fc-badge-preferred", children: "Detected" })
1300
+ ]
1301
+ },
1302
+ `std:${w.name}`
1303
+ )),
1158
1304
  mobileExtraWallets.map((mw) => /* @__PURE__ */ jsxs5(
1159
1305
  "button",
1160
1306
  {
@@ -1203,7 +1349,7 @@ function WalletAdapterFlow() {
1203
1349
  );
1204
1350
  })
1205
1351
  ] }),
1206
- preferredWallets.length === 0 && otherWallets.length === 0 && mobileExtraWallets.length === 0 && /* @__PURE__ */ jsx6("p", { className: "fc-text", children: "No wallet found. Please install a Solana wallet (like Phantom) to continue." }),
1352
+ preferredWallets.length === 0 && otherWallets.length === 0 && mobileExtraWallets.length === 0 && standardExtras.length === 0 && /* @__PURE__ */ jsx6("p", { className: "fc-text", children: "No wallet found. Please install a Solana wallet (like Phantom) to continue." }),
1207
1353
  /* @__PURE__ */ jsxs5("label", { className: "fc-cold-wallet-toggle", children: [
1208
1354
  /* @__PURE__ */ jsx6(
1209
1355
  "input",
@@ -1226,16 +1372,16 @@ function WalletAdapterFlow() {
1226
1372
  }
1227
1373
 
1228
1374
  // src/components/tabs/forgot-password.tsx
1229
- import { useState as useState4 } from "react";
1375
+ import { useState as useState5 } from "react";
1230
1376
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1231
1377
  function ForgotPasswordForm() {
1232
1378
  const { forgotPassword, resetPassword, setModalStep } = useForgeConnect();
1233
- const [step, setStep] = useState4("email");
1234
- const [email, setEmail] = useState4("");
1235
- const [token, setToken] = useState4("");
1236
- const [password, setPassword] = useState4("");
1237
- const [error, setError] = useState4("");
1238
- const [loading, setLoading] = useState4(false);
1379
+ const [step, setStep] = useState5("email");
1380
+ const [email, setEmail] = useState5("");
1381
+ const [token, setToken] = useState5("");
1382
+ const [password, setPassword] = useState5("");
1383
+ const [error, setError] = useState5("");
1384
+ const [loading, setLoading] = useState5(false);
1239
1385
  const handleSendCode = async (e) => {
1240
1386
  e.preventDefault();
1241
1387
  setError("");
@@ -1342,17 +1488,17 @@ function ForgotPasswordForm() {
1342
1488
  }
1343
1489
 
1344
1490
  // src/components/tabs/verify-2fa.tsx
1345
- import { useState as useState5, useRef as useRef5, useEffect as useEffect4, useCallback as useCallback2 } from "react";
1491
+ import { useState as useState6, useRef as useRef5, useEffect as useEffect5, useCallback as useCallback2 } from "react";
1346
1492
  import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1347
1493
  function Verify2FAForm() {
1348
1494
  const { verify2FA, verifyRecoveryCode, setModalStep } = useForgeConnect();
1349
- const [code, setCode] = useState5("");
1350
- const [loading, setLoading] = useState5(false);
1351
- const [error, setError] = useState5("");
1352
- const [useRecovery, setUseRecovery] = useState5(false);
1495
+ const [code, setCode] = useState6("");
1496
+ const [loading, setLoading] = useState6(false);
1497
+ const [error, setError] = useState6("");
1498
+ const [useRecovery, setUseRecovery] = useState6(false);
1353
1499
  const inputRef = useRef5(null);
1354
1500
  const submittingRef = useRef5(false);
1355
- useEffect4(() => {
1501
+ useEffect5(() => {
1356
1502
  inputRef.current?.focus();
1357
1503
  }, [useRecovery]);
1358
1504
  const submitCode = useCallback2(async (codeValue, isRecovery) => {
@@ -1510,8 +1656,8 @@ var LoadingSpinner = () => /* @__PURE__ */ jsx9("div", { className: "fc-method-i
1510
1656
  function MethodSelect() {
1511
1657
  const { setModalStep, loginWithPasskey, config } = useForgeConnect();
1512
1658
  const methods = resolveLoginMethods(config);
1513
- const [passkeyLoading, setPasskeyLoading] = useState6(false);
1514
- const [passkeyError, setPasskeyError] = useState6("");
1659
+ const [passkeyLoading, setPasskeyLoading] = useState7(false);
1660
+ const [passkeyError, setPasskeyError] = useState7("");
1515
1661
  const handlePasskey = async () => {
1516
1662
  setPasskeyLoading(true);
1517
1663
  setPasskeyError("");
@@ -1630,8 +1776,8 @@ var MigrationIcons = {
1630
1776
  };
1631
1777
  function MatricaMigrationView() {
1632
1778
  const { matricaMigration, resolveMatricaMigration } = useForgeConnect();
1633
- const [loading, setLoading] = useState6(null);
1634
- const [error, setError] = useState6("");
1779
+ const [loading, setLoading] = useState7(null);
1780
+ const [error, setError] = useState7("");
1635
1781
  if (!matricaMigration) return null;
1636
1782
  const { conflicts } = matricaMigration;
1637
1783
  const total = conflicts.wallets.length + conflicts.socials.length + (conflicts.email ? 1 : 0);
@@ -1711,14 +1857,14 @@ function SuccessView() {
1711
1857
  }
1712
1858
 
1713
1859
  // src/components/account-modal.tsx
1714
- import { useState as useState14, useEffect as useEffect10, useRef as useRef7, useCallback as useCallback7 } from "react";
1860
+ import { useState as useState15, useEffect as useEffect11, useRef as useRef7, useCallback as useCallback7 } from "react";
1715
1861
 
1716
1862
  // src/hooks/use-user.ts
1717
- import { useState as useState7, useCallback as useCallback3, useEffect as useEffect5, useRef as useRef6 } from "react";
1863
+ import { useState as useState8, useCallback as useCallback3, useEffect as useEffect6, useRef as useRef6 } from "react";
1718
1864
  function useUser() {
1719
1865
  const { auth, api, config, getAccessToken } = useForgeConnect();
1720
- const [authMethods, setAuthMethods] = useState7(null);
1721
- const [loading, setLoading] = useState7(false);
1866
+ const [authMethods, setAuthMethods] = useState8(null);
1867
+ const [loading, setLoading] = useState8(false);
1722
1868
  const pendingRefreshRef = useRef6(false);
1723
1869
  const updateProfile = useCallback3(
1724
1870
  async (data) => {
@@ -1791,7 +1937,7 @@ function useUser() {
1791
1937
  },
1792
1938
  [api, config.apiUrl, getAccessToken]
1793
1939
  );
1794
- useEffect5(() => {
1940
+ useEffect6(() => {
1795
1941
  const handleMessage = (event) => {
1796
1942
  if (event.origin !== window.location.origin) return;
1797
1943
  if (event.data?.type === "fc_oauth_link_success" && pendingRefreshRef.current) {
@@ -1818,7 +1964,7 @@ function useUser() {
1818
1964
  }
1819
1965
 
1820
1966
  // src/hooks/use-wallets.ts
1821
- import { useState as useState8, useCallback as useCallback4 } from "react";
1967
+ import { useState as useState9, useCallback as useCallback4 } from "react";
1822
1968
 
1823
1969
  // src/lib/utils.ts
1824
1970
  var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
@@ -1862,8 +2008,8 @@ function timeAgo(dateStr) {
1862
2008
  // src/hooks/use-wallets.ts
1863
2009
  function useWallets() {
1864
2010
  const { api, getAccessToken } = useForgeConnect();
1865
- const [wallets, setWallets] = useState8(null);
1866
- const [loading, setLoading] = useState8(false);
2011
+ const [wallets, setWallets] = useState9(null);
2012
+ const [loading, setLoading] = useState9(false);
1867
2013
  const fetchWallets = useCallback4(async () => {
1868
2014
  const token = getAccessToken();
1869
2015
  if (!token) throw new Error("Please sign in to continue.");
@@ -1927,11 +2073,11 @@ function useWallets() {
1927
2073
  }
1928
2074
 
1929
2075
  // src/hooks/use-sessions.ts
1930
- import { useState as useState9, useCallback as useCallback5 } from "react";
2076
+ import { useState as useState10, useCallback as useCallback5 } from "react";
1931
2077
  function useSessions() {
1932
2078
  const { api, getAccessToken } = useForgeConnect();
1933
- const [sessions, setSessions] = useState9(null);
1934
- const [loading, setLoading] = useState9(false);
2079
+ const [sessions, setSessions] = useState10(null);
2080
+ const [loading, setLoading] = useState10(false);
1935
2081
  const fetchSessions = useCallback5(async () => {
1936
2082
  const token = getAccessToken();
1937
2083
  if (!token) throw new Error("Please sign in to continue.");
@@ -1962,19 +2108,19 @@ function useSessions() {
1962
2108
  }
1963
2109
 
1964
2110
  // src/components/two-factor-modal.tsx
1965
- import { useState as useState10, useEffect as useEffect6 } from "react";
2111
+ import { useState as useState11, useEffect as useEffect7 } from "react";
1966
2112
  import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1967
2113
  function TwoFactorModal({ isOpen, onClose, initialEnabled, onStatusChange }) {
1968
2114
  const { api, getAccessToken, config } = useForgeConnect();
1969
2115
  const theme = config.appearance?.theme ?? "light";
1970
- const [step, setStep] = useState10(initialEnabled ? "manage" : "setup");
1971
- const [setupData, setSetupData] = useState10(null);
1972
- const [code, setCode] = useState10("");
1973
- const [loading, setLoading] = useState10(false);
1974
- const [msg, setMsg] = useState10(null);
1975
- const [showSecret, setShowSecret] = useState10(false);
1976
- const [recoveryCodes, setRecoveryCodes] = useState10([]);
1977
- useEffect6(() => {
2116
+ const [step, setStep] = useState11(initialEnabled ? "manage" : "setup");
2117
+ const [setupData, setSetupData] = useState11(null);
2118
+ const [code, setCode] = useState11("");
2119
+ const [loading, setLoading] = useState11(false);
2120
+ const [msg, setMsg] = useState11(null);
2121
+ const [showSecret, setShowSecret] = useState11(false);
2122
+ const [recoveryCodes, setRecoveryCodes] = useState11([]);
2123
+ useEffect7(() => {
1978
2124
  if (isOpen) {
1979
2125
  setStep(initialEnabled ? "manage" : "setup");
1980
2126
  setSetupData(null);
@@ -2238,7 +2384,7 @@ function TwoFactorModal({ isOpen, onClose, initialEnabled, onStatusChange }) {
2238
2384
  }
2239
2385
 
2240
2386
  // src/components/passkeys-modal.tsx
2241
- import { useState as useState11, useEffect as useEffect7, useCallback as useCallback6 } from "react";
2387
+ import { useState as useState12, useEffect as useEffect8, useCallback as useCallback6 } from "react";
2242
2388
 
2243
2389
  // ../../node_modules/.pnpm/@simplewebauthn+browser@13.2.2/node_modules/@simplewebauthn/browser/esm/helpers/bufferToBase64URLString.js
2244
2390
  function bufferToBase64URLString(buffer) {
@@ -2664,10 +2810,10 @@ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2664
2810
  function PasskeysModal({ isOpen, onClose, onCountChange }) {
2665
2811
  const { api, getAccessToken, config } = useForgeConnect();
2666
2812
  const theme = config.appearance?.theme ?? "light";
2667
- const [passkeys, setPasskeys] = useState11([]);
2668
- const [loading, setLoading] = useState11(false);
2669
- const [addLoading, setAddLoading] = useState11(false);
2670
- const [msg, setMsg] = useState11("");
2813
+ const [passkeys, setPasskeys] = useState12([]);
2814
+ const [loading, setLoading] = useState12(false);
2815
+ const [addLoading, setAddLoading] = useState12(false);
2816
+ const [msg, setMsg] = useState12("");
2671
2817
  const fetchPasskeys = useCallback6(async () => {
2672
2818
  const token = getAccessToken();
2673
2819
  if (!token) return;
@@ -2681,7 +2827,7 @@ function PasskeysModal({ isOpen, onClose, onCountChange }) {
2681
2827
  setLoading(false);
2682
2828
  }
2683
2829
  }, [api, getAccessToken, onCountChange]);
2684
- useEffect7(() => {
2830
+ useEffect8(() => {
2685
2831
  if (isOpen) {
2686
2832
  setMsg("");
2687
2833
  fetchPasskeys();
@@ -2768,7 +2914,7 @@ function PasskeysModal({ isOpen, onClose, onCountChange }) {
2768
2914
  }
2769
2915
 
2770
2916
  // src/components/password-modal.tsx
2771
- import { useState as useState12, useEffect as useEffect8 } from "react";
2917
+ import { useState as useState13, useEffect as useEffect9 } from "react";
2772
2918
 
2773
2919
  // src/components/error-view.tsx
2774
2920
  import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
@@ -2798,12 +2944,12 @@ import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-r
2798
2944
  function PasswordModal({ isOpen, onClose, hasPassword }) {
2799
2945
  const { api, getAccessToken, config } = useForgeConnect();
2800
2946
  const theme = config.appearance?.theme ?? "light";
2801
- const [step, setStep] = useState12("form");
2802
- const [currentPassword, setCurrentPassword] = useState12("");
2803
- const [newPassword, setNewPassword] = useState12("");
2804
- const [loading, setLoading] = useState12(false);
2805
- const [error, setError] = useState12("");
2806
- useEffect8(() => {
2947
+ const [step, setStep] = useState13("form");
2948
+ const [currentPassword, setCurrentPassword] = useState13("");
2949
+ const [newPassword, setNewPassword] = useState13("");
2950
+ const [loading, setLoading] = useState13(false);
2951
+ const [error, setError] = useState13("");
2952
+ useEffect9(() => {
2807
2953
  if (isOpen) {
2808
2954
  setStep("form");
2809
2955
  setCurrentPassword("");
@@ -2899,16 +3045,16 @@ function PasswordModal({ isOpen, onClose, hasPassword }) {
2899
3045
  }
2900
3046
 
2901
3047
  // src/components/delete-account-modal.tsx
2902
- import { useState as useState13, useEffect as useEffect9 } from "react";
3048
+ import { useState as useState14, useEffect as useEffect10 } from "react";
2903
3049
  import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
2904
3050
  function DeleteAccountModal({ isOpen, onClose, onDeleted }) {
2905
3051
  const { api, getAccessToken, config, logout } = useForgeConnect();
2906
3052
  const theme = config.appearance?.theme ?? "light";
2907
- const [step, setStep] = useState13("confirm");
2908
- const [code, setCode] = useState13("");
2909
- const [loading, setLoading] = useState13(false);
2910
- const [error, setError] = useState13("");
2911
- useEffect9(() => {
3053
+ const [step, setStep] = useState14("confirm");
3054
+ const [code, setCode] = useState14("");
3055
+ const [loading, setLoading] = useState14(false);
3056
+ const [error, setError] = useState14("");
3057
+ useEffect10(() => {
2912
3058
  if (isOpen) {
2913
3059
  setStep("confirm");
2914
3060
  setCode("");
@@ -3080,10 +3226,10 @@ var TABS = [
3080
3226
  function AccountModal() {
3081
3227
  const { accountModal, closeAccountModal, openLinkModal, linkModal, config, logout } = useForgeConnect();
3082
3228
  const { user } = useUser();
3083
- const [activeTab, setActiveTab] = useState14("profile");
3084
- const [refreshKey, setRefreshKey] = useState14(0);
3229
+ const [activeTab, setActiveTab] = useState15("profile");
3230
+ const [refreshKey, setRefreshKey] = useState15(0);
3085
3231
  const prevLinkOpen = useRef7(false);
3086
- useEffect10(() => {
3232
+ useEffect11(() => {
3087
3233
  if (prevLinkOpen.current && !linkModal.isOpen) {
3088
3234
  setRefreshKey((k) => k + 1);
3089
3235
  }
@@ -3141,11 +3287,11 @@ function AccountModal() {
3141
3287
  }
3142
3288
  function ProfileTab() {
3143
3289
  const { user, updateProfile } = useUser();
3144
- const [displayName, setDisplayName] = useState14(user?.displayName ?? "");
3145
- const [avatarUrl, setAvatarUrl] = useState14(user?.avatarUrl ?? "");
3146
- const [loading, setLoading] = useState14(false);
3147
- const [msg, setMsg] = useState14(null);
3148
- useEffect10(() => {
3290
+ const [displayName, setDisplayName] = useState15(user?.displayName ?? "");
3291
+ const [avatarUrl, setAvatarUrl] = useState15(user?.avatarUrl ?? "");
3292
+ const [loading, setLoading] = useState15(false);
3293
+ const [msg, setMsg] = useState15(null);
3294
+ useEffect11(() => {
3149
3295
  setDisplayName(user?.displayName ?? "");
3150
3296
  setAvatarUrl(user?.avatarUrl ?? "");
3151
3297
  }, [user]);
@@ -3195,8 +3341,8 @@ function ProfileTab() {
3195
3341
  }
3196
3342
  function LoginsTab({ onLink, refreshKey }) {
3197
3343
  const { authMethods, loading, fetchAuthMethods, unlinkAuthMethod } = useUser();
3198
- const [msg, setMsg] = useState14("");
3199
- useEffect10(() => {
3344
+ const [msg, setMsg] = useState15("");
3345
+ useEffect11(() => {
3200
3346
  fetchAuthMethods().catch(() => {
3201
3347
  });
3202
3348
  }, [fetchAuthMethods, refreshKey]);
@@ -3233,8 +3379,8 @@ function LoginsTab({ onLink, refreshKey }) {
3233
3379
  }
3234
3380
  function WalletsTab({ onLink, refreshKey }) {
3235
3381
  const { wallets, loading, fetchWallets, updateWallet } = useWallets();
3236
- const [msg, setMsg] = useState14("");
3237
- useEffect10(() => {
3382
+ const [msg, setMsg] = useState15("");
3383
+ useEffect11(() => {
3238
3384
  fetchWallets().catch(() => {
3239
3385
  });
3240
3386
  }, [fetchWallets, refreshKey]);
@@ -3269,13 +3415,13 @@ function SecurityTab() {
3269
3415
  const { sessions, loading, fetchSessions, revokeSession } = useSessions();
3270
3416
  const { logoutAll, logout, closeAccountModal, api, getAccessToken } = useForgeConnect();
3271
3417
  const { user, authMethods: userAuthMethods, fetchAuthMethods } = useUser();
3272
- const [msg, setMsg] = useState14("");
3273
- const [totpEnabled, setTotpEnabled] = useState14(null);
3274
- const [passkeyCount, setPasskeyCount] = useState14(0);
3275
- const [show2FAModal, setShow2FAModal] = useState14(false);
3276
- const [showPasskeyModal, setShowPasskeyModal] = useState14(false);
3277
- const [showPasswordModal, setShowPasswordModal] = useState14(false);
3278
- const [showDeleteModal, setShowDeleteModal] = useState14(false);
3418
+ const [msg, setMsg] = useState15("");
3419
+ const [totpEnabled, setTotpEnabled] = useState15(null);
3420
+ const [passkeyCount, setPasskeyCount] = useState15(0);
3421
+ const [show2FAModal, setShow2FAModal] = useState15(false);
3422
+ const [showPasskeyModal, setShowPasskeyModal] = useState15(false);
3423
+ const [showPasswordModal, setShowPasswordModal] = useState15(false);
3424
+ const [showDeleteModal, setShowDeleteModal] = useState15(false);
3279
3425
  const refreshStatus = useCallback7(() => {
3280
3426
  const token = getAccessToken();
3281
3427
  if (!token) return;
@@ -3288,7 +3434,7 @@ function SecurityTab() {
3288
3434
  api.getPasskeys(token).then((list) => setPasskeyCount(list.length)).catch(() => {
3289
3435
  });
3290
3436
  }, [api, getAccessToken]);
3291
- useEffect10(() => {
3437
+ useEffect11(() => {
3292
3438
  fetchSessions().catch(() => {
3293
3439
  });
3294
3440
  fetchAuthMethods().catch(() => {
@@ -3441,21 +3587,21 @@ function SecurityTab() {
3441
3587
  }
3442
3588
 
3443
3589
  // src/components/link-auth-modal.tsx
3444
- import { useState as useState15, useEffect as useEffect11, useMemo as useMemo2, useRef as useRef8, useCallback as useCallback8 } from "react";
3590
+ import { useState as useState16, useEffect as useEffect12, useMemo as useMemo2, useRef as useRef8, useCallback as useCallback8 } from "react";
3445
3591
  import { Fragment as Fragment6, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
3446
3592
  function LinkAuthModal() {
3447
3593
  const { linkModal, closeLinkModal, config } = useForgeConnect();
3448
3594
  const { linkOAuth, authMethods } = useUser();
3449
3595
  const mode = linkModal.mode ?? "auth";
3450
- const [step, setStep] = useState15("method-select");
3451
- const [fatalError, setFatalError] = useState15("");
3452
- useEffect11(() => {
3596
+ const [step, setStep] = useState16("method-select");
3597
+ const [fatalError, setFatalError] = useState16("");
3598
+ useEffect12(() => {
3453
3599
  if (linkModal.isOpen) {
3454
3600
  setStep(mode === "wallet" ? "wallet" : "method-select");
3455
3601
  setFatalError("");
3456
3602
  }
3457
3603
  }, [linkModal.isOpen, mode]);
3458
- useEffect11(() => {
3604
+ useEffect12(() => {
3459
3605
  if (!linkModal.isOpen) return;
3460
3606
  const handleMessage = (event) => {
3461
3607
  if (event.origin !== window.location.origin) return;
@@ -3606,10 +3752,10 @@ function AuthMethodSelectStep({
3606
3752
  }
3607
3753
  function EmailLinkStep({ onBack, onSuccess, onFatalError }) {
3608
3754
  const { linkAuthMethod } = useUser();
3609
- const [email, setEmail] = useState15("");
3610
- const [password, setPassword] = useState15("");
3611
- const [loading, setLoading] = useState15(false);
3612
- const [error, setError] = useState15("");
3755
+ const [email, setEmail] = useState16("");
3756
+ const [password, setPassword] = useState16("");
3757
+ const [loading, setLoading] = useState16(false);
3758
+ const [error, setError] = useState16("");
3613
3759
  const handleSubmit = async (e) => {
3614
3760
  e.preventDefault();
3615
3761
  setLoading(true);
@@ -3641,11 +3787,11 @@ function EmailLinkStep({ onBack, onSuccess, onFatalError }) {
3641
3787
  }
3642
3788
  function OtpLinkStep({ onBack, onSuccess, onFatalError }) {
3643
3789
  const { linkOtpSend, linkOtpVerify } = useUser();
3644
- const [email, setEmail] = useState15("");
3645
- const [code, setCode] = useState15("");
3646
- const [codeSent, setCodeSent] = useState15(false);
3647
- const [loading, setLoading] = useState15(false);
3648
- const [error, setError] = useState15("");
3790
+ const [email, setEmail] = useState16("");
3791
+ const [code, setCode] = useState16("");
3792
+ const [codeSent, setCodeSent] = useState16(false);
3793
+ const [loading, setLoading] = useState16(false);
3794
+ const [error, setError] = useState16("");
3649
3795
  const handleSendCode = async (e) => {
3650
3796
  e.preventDefault();
3651
3797
  setLoading(true);
@@ -3722,10 +3868,10 @@ function OtpLinkStep({ onBack, onSuccess, onFatalError }) {
3722
3868
  function WalletLinkStep({ onBack, onSuccess, onFatalError }) {
3723
3869
  const { walletAdapter, config } = useForgeConnect();
3724
3870
  const { linkWallet } = useWallets();
3725
- const [loading, setLoading] = useState15(false);
3726
- const [error, setError] = useState15("");
3727
- const [showOther, setShowOther] = useState15(false);
3728
- const [coldWallet, setColdWallet] = useState15(false);
3871
+ const [loading, setLoading] = useState16(false);
3872
+ const [error, setError] = useState16("");
3873
+ const [showOther, setShowOther] = useState16(false);
3874
+ const [coldWallet, setColdWallet] = useState16(false);
3729
3875
  const mobile = useMemo2(() => isMobile(), []);
3730
3876
  const walletConfig = config.walletConfig;
3731
3877
  const preferred = walletConfig?.preferredWallets ?? [];
@@ -3916,23 +4062,72 @@ function SuccessView2() {
3916
4062
  ] });
3917
4063
  }
3918
4064
 
4065
+ // src/register-mwa.ts
4066
+ var registered = false;
4067
+ async function registerMwaIfAvailable(config, opts) {
4068
+ if (typeof window === "undefined") return;
4069
+ if (registered) return;
4070
+ if (opts?.enabled === false) return;
4071
+ let mod;
4072
+ try {
4073
+ mod = await import("@solana-mobile/wallet-standard-mobile");
4074
+ } catch (err) {
4075
+ console.warn("[ForgeConnect/MWA] dynamic import failed", err);
4076
+ return;
4077
+ }
4078
+ const {
4079
+ registerMwa,
4080
+ createDefaultAuthorizationCache,
4081
+ createDefaultChainSelector,
4082
+ createDefaultWalletNotFoundHandler
4083
+ } = mod;
4084
+ const origin = window.location.origin;
4085
+ const identity = opts?.appIdentity ?? {};
4086
+ const appName = identity.name ?? config.appearance?.title ?? (typeof document !== "undefined" ? document.title : "") ?? "App";
4087
+ registered = true;
4088
+ try {
4089
+ registerMwa({
4090
+ appIdentity: {
4091
+ name: appName,
4092
+ uri: identity.uri ?? origin,
4093
+ icon: identity.icon
4094
+ },
4095
+ authorizationCache: createDefaultAuthorizationCache(),
4096
+ chains: opts?.chains ?? ["solana:mainnet"],
4097
+ chainSelector: createDefaultChainSelector(),
4098
+ onWalletNotFound: createDefaultWalletNotFoundHandler()
4099
+ });
4100
+ console.log("[ForgeConnect/MWA] registered. appIdentity:", { name: appName, uri: identity.uri ?? origin });
4101
+ try {
4102
+ const { getWallets } = await import("@wallet-standard/app");
4103
+ const list = getWallets().get();
4104
+ console.log("[ForgeConnect/MWA] standard wallets after register:", list.map((w) => w.name));
4105
+ } catch (e) {
4106
+ console.warn("[ForgeConnect/MWA] could not enumerate standard wallets", e);
4107
+ }
4108
+ } catch (err) {
4109
+ registered = false;
4110
+ console.warn("[ForgeConnect/MWA] registerMwa threw:", err);
4111
+ }
4112
+ }
4113
+
3919
4114
  // src/provider.tsx
3920
4115
  import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
3921
4116
  var oauthExchangeCache = /* @__PURE__ */ new Map();
3922
4117
  function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapter }) {
3923
- const [auth, setAuth] = useState16({
4118
+ const [auth, setAuth] = useState17({
3924
4119
  status: "loading",
3925
4120
  user: null,
3926
4121
  accessToken: null
3927
4122
  });
3928
- const [modal, setModal] = useState16({
4123
+ const [modal, setModal] = useState17({
3929
4124
  isOpen: false,
3930
4125
  step: "method-select"
3931
4126
  });
3932
- const [accountModal, setAccountModal] = useState16({ isOpen: false });
3933
- const [linkModal, setLinkModal] = useState16({ isOpen: false });
3934
- const [challengeToken, setChallengeToken] = useState16(null);
3935
- const [matricaMigration, setMatricaMigration] = useState16(null);
4127
+ const [accountModal, setAccountModal] = useState17({ isOpen: false });
4128
+ const [linkModal, setLinkModal] = useState17({ isOpen: false });
4129
+ const [challengeToken, setChallengeToken] = useState17(null);
4130
+ const [matricaMigration, setMatricaMigration] = useState17(null);
3936
4131
  const apiRef = useRef9(createApiClient(config.apiUrl));
3937
4132
  const refreshTimerRef = useRef9(null);
3938
4133
  const api = apiRef.current;
@@ -3950,7 +4145,7 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
3950
4145
  }
3951
4146
  }, delay);
3952
4147
  }, [api]);
3953
- useEffect12(() => {
4148
+ useEffect13(() => {
3954
4149
  const init = async () => {
3955
4150
  try {
3956
4151
  const { accessToken } = await api.refresh();
@@ -3966,7 +4161,7 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
3966
4161
  if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
3967
4162
  };
3968
4163
  }, [api, scheduleRefresh]);
3969
- useEffect12(() => {
4164
+ useEffect13(() => {
3970
4165
  if (window.location.pathname === "/fc-oauth-callback") {
3971
4166
  const params = new URLSearchParams(window.location.search);
3972
4167
  if (params.get("fc_link_success") && window.opener) {
@@ -4094,7 +4289,12 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
4094
4289
  window.removeEventListener("storage", handleStorage);
4095
4290
  };
4096
4291
  }, [api, config.apiUrl, scheduleRefresh, onLogin]);
4097
- useEffect12(() => {
4292
+ useEffect13(() => {
4293
+ const methods = resolveLoginMethods(config);
4294
+ if (!methods.includes("wallet")) return;
4295
+ void registerMwaIfAvailable(config, config.mwa);
4296
+ }, [config]);
4297
+ useEffect13(() => {
4098
4298
  if (config.loginMethods && config.loginMethods.length > 0) {
4099
4299
  const hasLegacy = config.oauthProviders || config.walletLogin !== void 0 || config.passwordlessLogin !== void 0;
4100
4300
  if (hasLegacy) {
@@ -4433,13 +4633,13 @@ function AccountButton({ className, loginLabel, compact }) {
4433
4633
  }
4434
4634
 
4435
4635
  // src/hooks/use-admin.ts
4436
- import { useState as useState17, useCallback as useCallback10 } from "react";
4636
+ import { useState as useState18, useCallback as useCallback10 } from "react";
4437
4637
  function useAdmin() {
4438
4638
  const { api, getAccessToken } = useForgeConnect();
4439
- const [users, setUsers] = useState17(null);
4440
- const [selectedUser, setSelectedUser] = useState17(null);
4441
- const [userSessions, setUserSessions] = useState17(null);
4442
- const [loading, setLoading] = useState17(false);
4639
+ const [users, setUsers] = useState18(null);
4640
+ const [selectedUser, setSelectedUser] = useState18(null);
4641
+ const [userSessions, setUserSessions] = useState18(null);
4642
+ const [loading, setLoading] = useState18(false);
4443
4643
  const listUsers = useCallback10(
4444
4644
  async (params) => {
4445
4645
  const token = getAccessToken();
@@ -4519,16 +4719,16 @@ function useAdmin() {
4519
4719
  }
4520
4720
 
4521
4721
  // src/hooks/use-roles.ts
4522
- import { useState as useState18, useCallback as useCallback11 } from "react";
4722
+ import { useState as useState19, useCallback as useCallback11 } from "react";
4523
4723
  function useRoles() {
4524
4724
  const { api, getAccessToken } = useForgeConnect();
4525
- const [roles, setRoles] = useState18(null);
4526
- const [selectedRole, setSelectedRole] = useState18(null);
4527
- const [userRoleAssignments, setUserRoleAssignments] = useState18(null);
4528
- const [roleUsers, setRoleUsers] = useState18(null);
4529
- const [permissionDomains, setPermissionDomains] = useState18(null);
4530
- const [myPermissions, setMyPermissions] = useState18([]);
4531
- const [loading, setLoading] = useState18(false);
4725
+ const [roles, setRoles] = useState19(null);
4726
+ const [selectedRole, setSelectedRole] = useState19(null);
4727
+ const [userRoleAssignments, setUserRoleAssignments] = useState19(null);
4728
+ const [roleUsers, setRoleUsers] = useState19(null);
4729
+ const [permissionDomains, setPermissionDomains] = useState19(null);
4730
+ const [myPermissions, setMyPermissions] = useState19([]);
4731
+ const [loading, setLoading] = useState19(false);
4532
4732
  const listRoles = useCallback11(
4533
4733
  async (tenantId) => {
4534
4734
  const token = getAccessToken();
@@ -4717,6 +4917,7 @@ export {
4717
4917
  hasAnyPermission,
4718
4918
  hasPermission,
4719
4919
  isOAuthMethod,
4920
+ registerMwaIfAvailable,
4720
4921
  resolveLoginMethods,
4721
4922
  useAdmin,
4722
4923
  useForgeConnect,