@abstraxn/signer-react 2.2.2 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/src/components/AbstraxnProvider/AbstraxnProviderInner.js +31 -88
  3. package/dist/src/components/AbstraxnProvider/AbstraxnProviderInner.js.map +1 -1
  4. package/dist/src/components/AbstraxnProvider/useWalletInitialization.js +6 -3
  5. package/dist/src/components/AbstraxnProvider/useWalletInitialization.js.map +1 -1
  6. package/dist/src/components/AbstraxnProvider/utils.js +1 -12
  7. package/dist/src/components/AbstraxnProvider/utils.js.map +1 -1
  8. package/dist/src/components/OnboardingUI/OnboardingUIReact.js +4 -27
  9. package/dist/src/components/OnboardingUI/OnboardingUIReact.js.map +1 -1
  10. package/dist/src/components/OnboardingUI/OnboardingUIWeb.js +3 -26
  11. package/dist/src/components/OnboardingUI/OnboardingUIWeb.js.map +1 -1
  12. package/dist/src/components/OnboardingUI/hooks/useAuthMethods.js +6 -3
  13. package/dist/src/components/OnboardingUI/hooks/useAuthMethods.js.map +1 -1
  14. package/dist/src/components/OnboardingUI/hooks/useOnboarding.js +2 -2
  15. package/dist/src/components/OnboardingUI/hooks/useOnboarding.js.map +1 -1
  16. package/dist/src/components/WalletModal/components/ManageWalletModal.js +94 -118
  17. package/dist/src/components/WalletModal/components/ManageWalletModal.js.map +1 -1
  18. package/dist/src/hooks.d.ts +52 -1
  19. package/dist/src/hooks.js +200 -0
  20. package/dist/src/hooks.js.map +1 -1
  21. package/dist/src/index.d.ts +1 -1
  22. package/dist/src/index.js +1 -1
  23. package/dist/src/index.js.map +1 -1
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.2.3] - 2026-03-24
9
+
10
+ ### Changed
11
+
12
+ - **API key in header** - Changed API key handling to send the API key in request headers.
13
+ - **Social login API flow** - Changed social login flow to call API directly instead of redirecting.
14
+
15
+ ### Added
16
+
17
+ - **MFA hooks (enable/disable)** – Added `useEnableMfa` and `useDisableMfa` as state-machine hooks for MFA setup and disable flows with cleaner, minimal APIs.
18
+
19
+ ### Fixed
20
+
21
+ - **MFA enable endpoint payload** – Removed transaction API/sign-payload dependency from MFA enable flow so `mfa/enable` is called directly without transaction payload requirements.
22
+
23
+ ### Other changes
24
+
25
+ - **Cookie-based refresh flow** - Updated session refresh handling to call `/auth/refresh` without a refresh token body and rely on backend HttpOnly cookie rotation, while keeping access token updates in SDK state.
26
+ - **OAuth callback query handling** - Updated callback/onboarding URL parsing to consume `success`, `loginCode`, `loginCodeExpiresIn`, optional `mfaRequired`, and `error`.
27
+
8
28
  ## [2.2.2] - 2026-03-20
9
29
 
10
30
  ### Fixed
@@ -649,7 +649,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
649
649
  // Clear OAuth callback params from URL so app shows connected state without refresh
650
650
  if (typeof window !== "undefined") {
651
651
  const url = new URL(window.location.href);
652
- const keys = ["success", "mfaRequired", "user", "accessToken", "refreshToken", "turnkeyPublicKey", "error", "provider", "authProvider"];
652
+ const keys = ["success", "mfaRequired", "loginCode", "loginCodeExpiresIn", "turnkeyPublicKey", "error", "provider", "authProvider"];
653
653
  keys.forEach((k) => url.searchParams.delete(k));
654
654
  window.history.replaceState({}, document.title, url.pathname + url.search);
655
655
  }
@@ -683,7 +683,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
683
683
  url.searchParams.delete("state");
684
684
  url.searchParams.delete("error");
685
685
  url.searchParams.delete("success");
686
- url.searchParams.delete("accessToken");
686
+ url.searchParams.delete("loginCode");
687
687
  url.searchParams.delete("provider");
688
688
  url.searchParams.delete("authProvider");
689
689
  window.history.replaceState({}, document.title, url.toString());
@@ -712,7 +712,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
712
712
  url.searchParams.delete("state");
713
713
  url.searchParams.delete("error");
714
714
  url.searchParams.delete("success");
715
- url.searchParams.delete("accessToken");
715
+ url.searchParams.delete("loginCode");
716
716
  url.searchParams.delete("provider");
717
717
  url.searchParams.delete("authProvider");
718
718
  window.history.replaceState({}, document.title, url.toString());
@@ -741,7 +741,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
741
741
  url.searchParams.delete("state");
742
742
  url.searchParams.delete("error");
743
743
  url.searchParams.delete("success");
744
- url.searchParams.delete("accessToken");
744
+ url.searchParams.delete("loginCode");
745
745
  url.searchParams.delete("provider");
746
746
  url.searchParams.delete("authProvider");
747
747
  window.history.replaceState({}, document.title, url.toString());
@@ -887,25 +887,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
887
887
  const hasAuthParams = (params) => params.get("success") === "true" ||
888
888
  params.get("error") ||
889
889
  params.get("code") ||
890
- params.get("accessToken");
891
- const getAuthProviderFromToken = (token) => {
892
- try {
893
- const base64Url = token.split(".")[1];
894
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
895
- const jsonPayload = decodeURIComponent(window
896
- .atob(base64)
897
- .split("")
898
- .map(function (c) {
899
- return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
900
- })
901
- .join(""));
902
- const payload = JSON.parse(jsonPayload);
903
- return (payload.authProvider || payload.provider || "").toLowerCase();
904
- }
905
- catch (e) {
906
- return null;
907
- }
908
- };
890
+ params.get("loginCode");
909
891
  const matchesProvider = (provider, params) => {
910
892
  const providerParam = (params.get("provider") ||
911
893
  params.get("authProvider") ||
@@ -917,17 +899,6 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
917
899
  }
918
900
  return providerParam === provider;
919
901
  }
920
- // Check accessToken for provider
921
- const accessToken = params.get("accessToken");
922
- if (accessToken) {
923
- const tokenProvider = getAuthProviderFromToken(accessToken);
924
- if (tokenProvider) {
925
- if (provider === "twitter") {
926
- return tokenProvider === "twitter" || tokenProvider === "x";
927
- }
928
- return tokenProvider === provider;
929
- }
930
- }
931
902
  if (provider === "twitter") {
932
903
  return path.includes("/twitter") || path.includes("/x");
933
904
  }
@@ -1821,6 +1792,21 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1821
1792
  setError(new Error("Session expired"));
1822
1793
  await disconnect();
1823
1794
  }, [disconnect]);
1795
+ const withSessionGuard = useCallback(async (action, fallbackMessage = "Operation failed") => {
1796
+ try {
1797
+ return await action();
1798
+ }
1799
+ catch (err) {
1800
+ const alreadyConnected = Boolean(walletRef.current?.isConnected || isConnected);
1801
+ if (alreadyConnected && isSessionExpiredError(err)) {
1802
+ await handleSessionExpired();
1803
+ throw new Error("Session expired");
1804
+ }
1805
+ const error = err instanceof Error ? err : new Error(fallbackMessage);
1806
+ setError(error);
1807
+ throw error;
1808
+ }
1809
+ }, [handleSessionExpired, isConnected]);
1824
1810
  // Hide onboarding UI
1825
1811
  const hideOnboarding = useCallback(() => {
1826
1812
  setError(null); // Clear any previous errors
@@ -2084,21 +2070,12 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
2084
2070
  setLoading(true);
2085
2071
  setError(null);
2086
2072
  try {
2087
- return await walletRef.current.signTransactionViaAPI(unsignedTransaction, fromAddress);
2088
- }
2089
- catch (err) {
2090
- if (isSessionExpiredError(err)) {
2091
- await handleSessionExpired();
2092
- throw new Error("Session expired");
2093
- }
2094
- const error = err instanceof Error ? err : new Error("Failed to sign transaction");
2095
- setError(error);
2096
- throw error;
2073
+ return await withSessionGuard(() => walletRef.current.signTransactionViaAPI(unsignedTransaction, fromAddress), "Failed to sign transaction");
2097
2074
  }
2098
2075
  finally {
2099
2076
  setLoading(false);
2100
2077
  }
2101
- }, [handleSessionExpired]);
2078
+ }, [withSessionGuard]);
2102
2079
  // Sign Solana transaction via API (returns signed transaction)
2103
2080
  const signSolanaTransactionViaAPI = useCallback(async (unsignedTransaction, fromAddress) => {
2104
2081
  if (!walletRef.current)
@@ -2110,21 +2087,12 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
2110
2087
  if (typeof walletAny.signSolanaTransactionViaAPI !== "function") {
2111
2088
  throw new Error("Solana transaction signing is not supported by this wallet");
2112
2089
  }
2113
- return await walletAny.signSolanaTransactionViaAPI(unsignedTransaction, fromAddress);
2114
- }
2115
- catch (err) {
2116
- if (isSessionExpiredError(err)) {
2117
- await handleSessionExpired();
2118
- throw new Error("Session expired");
2119
- }
2120
- const error = err instanceof Error ? err : new Error("Failed to sign Solana transaction");
2121
- setError(error);
2122
- throw error;
2090
+ return await withSessionGuard(() => walletAny.signSolanaTransactionViaAPI(unsignedTransaction, fromAddress), "Failed to sign Solana transaction");
2123
2091
  }
2124
2092
  finally {
2125
2093
  setLoading(false);
2126
2094
  }
2127
- }, [handleSessionExpired]);
2095
+ }, [withSessionGuard]);
2128
2096
  // Sign typed data / raw payload via API (same flow as signTransactionViaAPI, payload: from, unsignedTransaction, encoding, hashFunction)
2129
2097
  const signTypedTxViaAPI = useCallback(async (fromAddress, unsignedTransaction, encoding, hashFunction) => {
2130
2098
  if (!walletRef.current)
@@ -2132,21 +2100,12 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
2132
2100
  setLoading(true);
2133
2101
  setError(null);
2134
2102
  try {
2135
- return await walletRef.current.signTypedTxViaAPI(fromAddress, unsignedTransaction, encoding, hashFunction);
2136
- }
2137
- catch (err) {
2138
- if (isSessionExpiredError(err)) {
2139
- await handleSessionExpired();
2140
- throw new Error("Session expired");
2141
- }
2142
- const error = err instanceof Error ? err : new Error("Failed to sign typed payload");
2143
- setError(error);
2144
- throw error;
2103
+ return await withSessionGuard(() => walletRef.current.signTypedTxViaAPI(fromAddress, unsignedTransaction, encoding, hashFunction), "Failed to sign typed payload");
2145
2104
  }
2146
2105
  finally {
2147
2106
  setLoading(false);
2148
2107
  }
2149
- }, [handleSessionExpired]);
2108
+ }, [withSessionGuard]);
2150
2109
  // Sign and send transaction using backend API
2151
2110
  const signAndSendTransaction = useCallback(async (unsignedTransaction, fromAddress, rpcUrl) => {
2152
2111
  if (!walletRef.current)
@@ -2154,23 +2113,12 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
2154
2113
  setLoading(true);
2155
2114
  setError(null);
2156
2115
  try {
2157
- return await walletRef.current.signAndSendTransaction(unsignedTransaction, fromAddress, rpcUrl);
2158
- }
2159
- catch (err) {
2160
- if (isSessionExpiredError(err)) {
2161
- await handleSessionExpired();
2162
- throw new Error("Session expired");
2163
- }
2164
- const error = err instanceof Error
2165
- ? err
2166
- : new Error("Failed to sign and send transaction");
2167
- setError(error);
2168
- throw error;
2116
+ return await withSessionGuard(() => walletRef.current.signAndSendTransaction(unsignedTransaction, fromAddress, rpcUrl), "Failed to sign and send transaction");
2169
2117
  }
2170
2118
  finally {
2171
2119
  setLoading(false);
2172
2120
  }
2173
- }, [handleSessionExpired]);
2121
+ }, [withSessionGuard]);
2174
2122
  // Login with email OTP (initiate OTP)
2175
2123
  const loginWithOTP = useCallback(async (email) => {
2176
2124
  if (!walletRef.current)
@@ -2328,7 +2276,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
2328
2276
  setLoading(true);
2329
2277
  setError(null);
2330
2278
  try {
2331
- const whoamiInfo = await walletRef.current.refreshWhoami();
2279
+ const whoamiInfo = await withSessionGuard(() => walletRef.current.refreshWhoami(), "Failed to refresh whoami");
2332
2280
  if (whoamiInfo) {
2333
2281
  setWhoami(whoamiInfo);
2334
2282
  // Update address if available in whoami response
@@ -2338,15 +2286,10 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
2338
2286
  }
2339
2287
  return whoamiInfo;
2340
2288
  }
2341
- catch (err) {
2342
- const error = err instanceof Error ? err : new Error("Failed to refresh whoami");
2343
- setError(error);
2344
- throw error;
2345
- }
2346
2289
  finally {
2347
2290
  setLoading(false);
2348
2291
  }
2349
- }, [isExternalWalletConnected]);
2292
+ }, [isExternalWalletConnected, withSessionGuard]);
2350
2293
  const getSupportedAuthMethods = useCallback(async () => {
2351
2294
  if (!walletRef.current?.isConnected) {
2352
2295
  throw new Error("Wallet not connected");
@@ -3489,7 +3432,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
3489
3432
  // Clear OAuth callback params from URL so app shows connected state without refresh
3490
3433
  if (typeof window !== "undefined") {
3491
3434
  const url = new URL(window.location.href);
3492
- const keys = ["success", "mfaRequired", "user", "accessToken", "refreshToken", "turnkeyPublicKey", "error", "provider", "authProvider"];
3435
+ const keys = ["success", "mfaRequired", "loginCode", "loginCodeExpiresIn", "turnkeyPublicKey", "error", "provider", "authProvider"];
3493
3436
  keys.forEach((k) => url.searchParams.delete(k));
3494
3437
  window.history.replaceState({}, document.title, url.pathname + url.search);
3495
3438
  }