@abstraxn/signer-react 2.1.1 → 2.1.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,12 @@ 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.1.3] - 2026-03-06
9
+
10
+ ### Fixed
11
+
12
+ - **Turnkey code 16 (session expired)** – When the backend returns a 401 with Turnkey error code 16 (PUBLIC_KEY_NOT_FOUND, e.g. stamping key not found in organization), the SDK now treats it as session expired instead of surfacing a long `NetworkError` message. The user is logged out, the context error is set to "Session expired", and callers receive a simple "Session expired" error. Detection uses Turnkey’s `code === 16` in the error payload (from the API response or from the parsed message). Applied in `@abstraxn/signer-core` (all authenticated API catch blocks) and in the React provider for `signTransactionViaAPI`, `signSolanaTransactionViaAPI`, `signTypedTxViaAPI`, and `signAndSendTransaction`.
13
+
8
14
  ## [2.1.1] - 2026-03-05
9
15
  ## [2.1.0] - 2026-03-05
10
16
 
@@ -1582,6 +1582,28 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1582
1582
  }, 200);
1583
1583
  }
1584
1584
  }, [isExternalWalletConnected, externalWalletsEnabled, wagmiDisconnect, wagmiAccount?.connector]);
1585
+ // Detect Turnkey code 16 (PUBLIC_KEY_NOT_FOUND) / session expired (backend returns 401 with code 16)
1586
+ // Handles both AuthenticationError('Session expired') and NetworkError wrapping the Turnkey payload
1587
+ const isSessionExpiredError = (err) => {
1588
+ if (err instanceof AuthenticationError && err.message === "Session expired")
1589
+ return true;
1590
+ if (err instanceof Error && typeof err.message === "string") {
1591
+ try {
1592
+ // Message may be "Network error: Turnkey API error: 401 - {\"code\":16, ...}" or raw JSON
1593
+ const inner = err.message.match(/\{[\s\S]*\}/)?.[0];
1594
+ const parsed = inner ? JSON.parse(inner) : null;
1595
+ return parsed != null && parsed.code === 16;
1596
+ }
1597
+ catch {
1598
+ return false;
1599
+ }
1600
+ }
1601
+ return false;
1602
+ };
1603
+ const handleSessionExpired = useCallback(async () => {
1604
+ setError(new Error("Session expired"));
1605
+ await disconnect();
1606
+ }, [disconnect]);
1585
1607
  // Hide onboarding UI
1586
1608
  const hideOnboarding = useCallback(() => {
1587
1609
  setError(null); // Clear any previous errors
@@ -1848,6 +1870,10 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1848
1870
  return await walletRef.current.signTransactionViaAPI(unsignedTransaction, fromAddress);
1849
1871
  }
1850
1872
  catch (err) {
1873
+ if (isSessionExpiredError(err)) {
1874
+ await handleSessionExpired();
1875
+ throw new Error("Session expired");
1876
+ }
1851
1877
  const error = err instanceof Error ? err : new Error("Failed to sign transaction");
1852
1878
  setError(error);
1853
1879
  throw error;
@@ -1855,7 +1881,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1855
1881
  finally {
1856
1882
  setLoading(false);
1857
1883
  }
1858
- }, []);
1884
+ }, [handleSessionExpired]);
1859
1885
  // Sign Solana transaction via API (returns signed transaction)
1860
1886
  const signSolanaTransactionViaAPI = useCallback(async (unsignedTransaction, fromAddress) => {
1861
1887
  if (!walletRef.current)
@@ -1870,6 +1896,10 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1870
1896
  return await walletAny.signSolanaTransactionViaAPI(unsignedTransaction, fromAddress);
1871
1897
  }
1872
1898
  catch (err) {
1899
+ if (isSessionExpiredError(err)) {
1900
+ await handleSessionExpired();
1901
+ throw new Error("Session expired");
1902
+ }
1873
1903
  const error = err instanceof Error ? err : new Error("Failed to sign Solana transaction");
1874
1904
  setError(error);
1875
1905
  throw error;
@@ -1877,7 +1907,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1877
1907
  finally {
1878
1908
  setLoading(false);
1879
1909
  }
1880
- }, []);
1910
+ }, [handleSessionExpired]);
1881
1911
  // Sign typed data / raw payload via API (same flow as signTransactionViaAPI, payload: from, unsignedTransaction, encoding, hashFunction)
1882
1912
  const signTypedTxViaAPI = useCallback(async (fromAddress, unsignedTransaction, encoding, hashFunction) => {
1883
1913
  if (!walletRef.current)
@@ -1888,6 +1918,10 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1888
1918
  return await walletRef.current.signTypedTxViaAPI(fromAddress, unsignedTransaction, encoding, hashFunction);
1889
1919
  }
1890
1920
  catch (err) {
1921
+ if (isSessionExpiredError(err)) {
1922
+ await handleSessionExpired();
1923
+ throw new Error("Session expired");
1924
+ }
1891
1925
  const error = err instanceof Error ? err : new Error("Failed to sign typed payload");
1892
1926
  setError(error);
1893
1927
  throw error;
@@ -1895,7 +1929,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1895
1929
  finally {
1896
1930
  setLoading(false);
1897
1931
  }
1898
- }, []);
1932
+ }, [handleSessionExpired]);
1899
1933
  // Sign and send transaction using backend API
1900
1934
  const signAndSendTransaction = useCallback(async (unsignedTransaction, fromAddress, rpcUrl) => {
1901
1935
  if (!walletRef.current)
@@ -1906,6 +1940,10 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1906
1940
  return await walletRef.current.signAndSendTransaction(unsignedTransaction, fromAddress, rpcUrl);
1907
1941
  }
1908
1942
  catch (err) {
1943
+ if (isSessionExpiredError(err)) {
1944
+ await handleSessionExpired();
1945
+ throw new Error("Session expired");
1946
+ }
1909
1947
  const error = err instanceof Error
1910
1948
  ? err
1911
1949
  : new Error("Failed to sign and send transaction");
@@ -1915,7 +1953,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1915
1953
  finally {
1916
1954
  setLoading(false);
1917
1955
  }
1918
- }, []);
1956
+ }, [handleSessionExpired]);
1919
1957
  // Login with email OTP (initiate OTP)
1920
1958
  const loginWithOTP = useCallback(async (email) => {
1921
1959
  if (!walletRef.current)