@forge-connect/react 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/provider.tsx
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/provider.tsx
2
2
  var _react = require('react');
3
3
 
4
4
  // src/context.ts
@@ -402,33 +402,13 @@ function createApiClient(apiUrl) {
402
402
  }
403
403
 
404
404
  // src/utils.ts
405
- var TOKEN_KEY = "fc_access_token";
406
- function getStoredToken() {
407
- try {
408
- return localStorage.getItem(TOKEN_KEY);
409
- } catch (e4) {
410
- return null;
411
- }
412
- }
413
- function setStoredToken(token) {
414
- try {
415
- localStorage.setItem(TOKEN_KEY, token);
416
- } catch (e5) {
417
- }
418
- }
419
- function removeStoredToken() {
420
- try {
421
- localStorage.removeItem(TOKEN_KEY);
422
- } catch (e6) {
423
- }
424
- }
425
405
  function decodeJWT(token) {
426
406
  try {
427
407
  const parts = token.split(".");
428
408
  if (parts.length !== 3) return null;
429
409
  const payload = JSON.parse(atob(parts[1].replace(/-/g, "+").replace(/_/g, "/")));
430
410
  return payload;
431
- } catch (e7) {
411
+ } catch (e4) {
432
412
  return null;
433
413
  }
434
414
  }
@@ -1253,7 +1233,7 @@ async function startAuthentication(options) {
1253
1233
  }
1254
1234
 
1255
1235
  // src/runtime-imports.ts
1256
- var importSolanaWeb3 = () => new Function('return import("@solana/web3.js")')();
1236
+ var importSolanaWeb3 = () => Promise.resolve().then(() => _interopRequireWildcard(require("@solana/web3.js")));
1257
1237
 
1258
1238
  // src/components/tabs/wallet-connect.tsx
1259
1239
 
@@ -1759,7 +1739,7 @@ function SvgIcon({ svg, className }) {
1759
1739
  });
1760
1740
  ref.current.textContent = "";
1761
1741
  ref.current.appendChild(svgEl);
1762
- } catch (e8) {
1742
+ } catch (e5) {
1763
1743
  ref.current.textContent = "";
1764
1744
  }
1765
1745
  }, [svg]);
@@ -2164,19 +2144,33 @@ function useWallets() {
2164
2144
  [api, getAccessToken, fetchWallets]
2165
2145
  );
2166
2146
  const linkWallet = _react.useCallback.call(void 0,
2167
- async (walletAddress, signMessage, chain = "solana") => {
2147
+ async (walletAddress, signMessage, chain = "solana", signTransaction) => {
2168
2148
  const token = getAccessToken();
2169
2149
  if (!token) throw new Error("Please sign in to continue.");
2170
- const { challengeId, message: challengeMessage } = await api.walletChallenge(walletAddress, chain);
2171
- const encoded = new TextEncoder().encode(challengeMessage);
2172
- const signatureBytes = await signMessage(encoded);
2173
- const signature = chain === "solana" ? uint8ArrayToBase58(signatureBytes) : Array.from(signatureBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
2174
- await api.linkAuthMethod(token, {
2175
- provider: `${chain}_wallet`,
2176
- challengeId,
2177
- signature,
2178
- walletAddress
2179
- });
2150
+ if (signMessage) {
2151
+ const { challengeId, message: challengeMessage } = await api.walletChallenge(walletAddress, chain);
2152
+ const encoded = new TextEncoder().encode(challengeMessage);
2153
+ const signatureBytes = await signMessage(encoded);
2154
+ const signature = chain === "solana" ? uint8ArrayToBase58(signatureBytes) : Array.from(signatureBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
2155
+ await api.linkAuthMethod(token, {
2156
+ provider: `${chain}_wallet`,
2157
+ challengeId,
2158
+ signature,
2159
+ walletAddress
2160
+ });
2161
+ } else {
2162
+ if (!signTransaction) {
2163
+ throw new Error("Wallet does not support message signing or transaction signing.");
2164
+ }
2165
+ const { challengeId, transaction: txBase64 } = await api.walletChallengeTx(walletAddress, chain);
2166
+ const signedTxBase64 = await signTransaction(txBase64);
2167
+ await api.linkAuthMethod(token, {
2168
+ provider: `${chain}_wallet_tx`,
2169
+ challengeId,
2170
+ signedTransaction: signedTxBase64,
2171
+ walletAddress
2172
+ });
2173
+ }
2180
2174
  await fetchWallets();
2181
2175
  },
2182
2176
  [api, getAccessToken, fetchWallets]
@@ -2519,7 +2513,7 @@ function PasskeysModal({ isOpen, onClose, onCountChange }) {
2519
2513
  const list = await api.getPasskeys(token);
2520
2514
  setPasskeys(list);
2521
2515
  onCountChange(list.length);
2522
- } catch (e9) {
2516
+ } catch (e6) {
2523
2517
  } finally {
2524
2518
  setLoading(false);
2525
2519
  }
@@ -3568,10 +3562,23 @@ function WalletLinkStep({ onBack, onSuccess, onFatalError }) {
3568
3562
  const [loading, setLoading] = _react.useState.call(void 0, false);
3569
3563
  const [error, setError] = _react.useState.call(void 0, "");
3570
3564
  const [showOther, setShowOther] = _react.useState.call(void 0, false);
3565
+ const [coldWallet, setColdWallet] = _react.useState.call(void 0, false);
3571
3566
  const mobile = _react.useMemo.call(void 0, () => isMobile(), []);
3572
3567
  const walletConfig = config.walletConfig;
3573
3568
  const preferred = _nullishCoalesce(_optionalChain([walletConfig, 'optionalAccess', _111 => _111.preferredWallets]), () => ( []));
3574
3569
  const onlyPreferred = _nullishCoalesce(_optionalChain([walletConfig, 'optionalAccess', _112 => _112.onlyPreferred]), () => ( false));
3570
+ const coldWalletRef = _react.useRef.call(void 0, coldWallet);
3571
+ coldWalletRef.current = coldWallet;
3572
+ const buildSignTxFnForAdapter = _react.useCallback.call(void 0, (adapter) => {
3573
+ if (!adapter.signTransaction) return void 0;
3574
+ return async (txBase64) => {
3575
+ const { Transaction } = await importSolanaWeb3();
3576
+ const bytes = Uint8Array.from(atob(txBase64), (c) => c.charCodeAt(0));
3577
+ const tx = Transaction.from(bytes);
3578
+ const signedTx = await adapter.signTransaction(tx);
3579
+ return btoa(String.fromCharCode(...new Uint8Array(signedTx.serialize())));
3580
+ };
3581
+ }, []);
3575
3582
  const handleConnect = async (w) => {
3576
3583
  if (w.readyState !== "Installed") {
3577
3584
  if (mobile) {
@@ -3591,9 +3598,14 @@ function WalletLinkStep({ onBack, onSuccess, onFatalError }) {
3591
3598
  if (!w.adapter.connected) await w.adapter.connect();
3592
3599
  const pk = w.adapter.publicKey;
3593
3600
  if (!pk) throw new Error("Wallet did not provide a public key.");
3601
+ const useCold = coldWalletRef.current;
3594
3602
  const adapterSignMessage = w.adapter.signMessage ? (msg) => w.adapter.signMessage(msg) : void 0;
3595
- if (!adapterSignMessage) throw new Error("This wallet does not support message signing.");
3596
- await linkWallet(pk.toBase58(), adapterSignMessage, "solana");
3603
+ await linkWallet(
3604
+ pk.toBase58(),
3605
+ useCold ? void 0 : adapterSignMessage,
3606
+ "solana",
3607
+ useCold ? buildSignTxFnForAdapter(w.adapter) : void 0
3608
+ );
3597
3609
  onSuccess();
3598
3610
  } catch (err) {
3599
3611
  onFatalError(err instanceof Error ? err.message : "Could not link this wallet. Please try again.");
@@ -3650,7 +3662,7 @@ function WalletLinkStep({ onBack, onSuccess, onFatalError }) {
3650
3662
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "fc-tab", children: [
3651
3663
  loading ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { style: { textAlign: "center", padding: "24px 0" }, children: [
3652
3664
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-tab-title", children: "Connecting..." }),
3653
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "Approve the connection, then sign the verification request in your wallet" }),
3665
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: coldWallet ? "Confirm the transaction on your device" : "Approve the connection, then sign the verification request in your wallet" }),
3654
3666
  error && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
3655
3667
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error }),
3656
3668
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -3708,6 +3720,21 @@ function WalletLinkStep({ onBack, onSuccess, onFatalError }) {
3708
3720
  ] }, w.adapter.name))
3709
3721
  ] }),
3710
3722
  preferredWallets.length === 0 && otherWallets.length === 0 && mobileExtraWallets.length === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-text", children: "No wallet found. Please install a Solana wallet (like Phantom) to continue." }),
3723
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "fc-cold-wallet-toggle", children: [
3724
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3725
+ "input",
3726
+ {
3727
+ type: "checkbox",
3728
+ checked: coldWallet,
3729
+ onChange: (e) => setColdWallet(e.target.checked)
3730
+ }
3731
+ ),
3732
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "fc-toggle-track" }),
3733
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "fc-cold-wallet-label", children: [
3734
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Hardware wallet" }),
3735
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Ledger, Trezor, Keystone..." })
3736
+ ] })
3737
+ ] }),
3711
3738
  error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "fc-error", children: error })
3712
3739
  ] }),
3713
3740
  !loading && onBack && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "fc-switch", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", className: "fc-link", onClick: onBack, children: "Back" }) })
@@ -3748,42 +3775,22 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
3748
3775
  refreshTimerRef.current = setTimeout(async () => {
3749
3776
  try {
3750
3777
  const { accessToken } = await api.refresh();
3751
- setStoredToken(accessToken);
3752
3778
  setAuth((prev) => ({ ...prev, accessToken }));
3753
3779
  scheduleRefresh(accessToken);
3754
- } catch (e10) {
3755
- removeStoredToken();
3780
+ } catch (e7) {
3756
3781
  setAuth({ status: "unauthenticated", user: null, accessToken: null });
3757
3782
  }
3758
3783
  }, delay);
3759
3784
  }, [api]);
3760
3785
  _react.useEffect.call(void 0, () => {
3761
3786
  const init = async () => {
3762
- const token = getStoredToken();
3763
- if (!token) {
3764
- setAuth({ status: "unauthenticated", user: null, accessToken: null });
3765
- return;
3766
- }
3767
3787
  try {
3768
- const user = await api.getMe(token);
3769
- setAuth({ status: "authenticated", user, accessToken: token });
3770
- scheduleRefresh(token);
3771
- } catch (err) {
3772
- if (err instanceof ForgeConnectApiError && err.status === 401) {
3773
- try {
3774
- const { accessToken } = await api.refresh();
3775
- const user = await api.getMe(accessToken);
3776
- setStoredToken(accessToken);
3777
- setAuth({ status: "authenticated", user, accessToken });
3778
- scheduleRefresh(accessToken);
3779
- } catch (e11) {
3780
- removeStoredToken();
3781
- setAuth({ status: "unauthenticated", user: null, accessToken: null });
3782
- }
3783
- } else {
3784
- removeStoredToken();
3785
- setAuth({ status: "unauthenticated", user: null, accessToken: null });
3786
- }
3788
+ const { accessToken } = await api.refresh();
3789
+ const user = await api.getMe(accessToken);
3790
+ setAuth({ status: "authenticated", user, accessToken });
3791
+ scheduleRefresh(accessToken);
3792
+ } catch (e8) {
3793
+ setAuth({ status: "unauthenticated", user: null, accessToken: null });
3787
3794
  }
3788
3795
  };
3789
3796
  init();
@@ -3826,7 +3833,6 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
3826
3833
  }
3827
3834
  const token = result.accessToken;
3828
3835
  if (!token) return;
3829
- setStoredToken(token);
3830
3836
  setModal({ isOpen: true, step: "success" });
3831
3837
  const user = await api.getMe(token);
3832
3838
  setAuth({ status: "authenticated", user, accessToken: token });
@@ -3835,8 +3841,7 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
3835
3841
  setTimeout(() => {
3836
3842
  setModal({ isOpen: false, step: "method-select" });
3837
3843
  }, 1500);
3838
- } catch (e12) {
3839
- removeStoredToken();
3844
+ } catch (e9) {
3840
3845
  }
3841
3846
  };
3842
3847
  window.addEventListener("message", handleMessage);
@@ -3854,7 +3859,6 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
3854
3859
  }, []);
3855
3860
  const handleAuthSuccess = _react.useCallback.call(void 0,
3856
3861
  async (token) => {
3857
- setStoredToken(token);
3858
3862
  const user = await api.getMe(token);
3859
3863
  setAuth({ status: "authenticated", user, accessToken: token });
3860
3864
  scheduleRefresh(token);
@@ -3957,14 +3961,13 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
3957
3961
  );
3958
3962
  const logout = _react.useCallback.call(void 0, async () => {
3959
3963
  const token = auth.accessToken;
3960
- removeStoredToken();
3961
3964
  if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
3962
3965
  setAuth({ status: "unauthenticated", user: null, accessToken: null });
3963
3966
  _optionalChain([onLogout, 'optionalCall', _119 => _119()]);
3964
3967
  if (token) {
3965
3968
  try {
3966
3969
  await api.logout(token);
3967
- } catch (e13) {
3970
+ } catch (e10) {
3968
3971
  }
3969
3972
  }
3970
3973
  }, [auth.accessToken, api, onLogout]);
@@ -4012,14 +4015,13 @@ function ForgeConnectProvider({ config, children, onLogin, onLogout, walletAdapt
4012
4015
  }, [api, challengeToken, handleAuthSuccess]);
4013
4016
  const logoutAll = _react.useCallback.call(void 0, async () => {
4014
4017
  const token = auth.accessToken;
4015
- removeStoredToken();
4016
4018
  if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
4017
4019
  setAuth({ status: "unauthenticated", user: null, accessToken: null });
4018
4020
  _optionalChain([onLogout, 'optionalCall', _120 => _120()]);
4019
4021
  if (token) {
4020
4022
  try {
4021
4023
  await api.logoutAll(token);
4022
- } catch (e14) {
4024
+ } catch (e11) {
4023
4025
  }
4024
4026
  }
4025
4027
  }, [auth.accessToken, api, onLogout]);