@abstraxn/signer-react 3.1.3 → 3.1.4

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,16 +5,20 @@ 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
- ## [3.1.3] - 2026-03-31
8
+ ## [3.1.4] - 2026-04-06
9
9
 
10
10
  ### Changed
11
11
 
12
- - **Embedded-only wagmi context** – When `externalWallets.enabled` is `false`, the provider still mounts `QueryClientProvider` and `WagmiProvider` using a **connector-free** wagmi config (`createWagmiConfig(..., embedOnly: true)`), so hooks like `useConfig`, `useAccount`, and unified chain switching keep working for email/social embedded flows without registering injected/MetaMask/WalletConnect connectors. If React Query is missing, the error message now describes wagmi hook requirements instead of blaming disabled external wallets.
13
- - **`createWagmiConfig` embed mode** – New optional `embedOnly` flag builds a minimal wagmi `Config` (empty `connectors`, shared HTTP transports and storage) for embedded-only usage; chain list must still be non-empty.
12
+ - **Passkey completion via login code (`@abstraxn/signer-core`)** – Passkey signup and login now expect a `loginCode` (and optional `mfaRequired`) from the backend, then exchange it through `POST /auth/exchange` before tokens and user state are finalized. Passkey responses no longer persist access/refresh tokens directly from those calls.
13
+ - **Auth route prefixes** – OTP init/verify and passkey signup/login client paths use `/auth/otp/...` and `/auth/passkey/...` instead of `/login/otp/...` and `/login/passkey/...`.
14
+ - **Passkey login stamp** – The WebAuthn/Turnkey stamp is serialized and sent as a JSON string in the passkey login request, matching the updated API contract.
15
+ - **Passkey signup payload** – `targetPublicKey` is optional when a device public key is not available; session completion merges profile fields from the passkey API response where the JWT omits them (e.g. `isPolicy`, `publicKey`, `authProvider`).
16
+ - **MFA after passkey** – `AbstraxnWallet.loginWithPasskey` / `signupWithPasskey` and the React provider defer `connect()` when MFA is still required; `AuthManager` tracks `pendingSessionAuthMethod: 'passkey'` so post-MFA session setup uses the correct path.
14
17
 
15
- ### Fixed
18
+ ### Added
16
19
 
17
- - **`useExternalWalletInfo().switchChain`** – Returns the unified `switchChain` implementation (embedded + external) instead of only the external-wallet switcher, so chain changes behave consistently when external wallets are off.
20
+ - **`PasskeyFlowResult` and onboarding hooks** – `onPasskeySignup` / `onPasskeyLogin` may return `{ mfaRequired: true }`; `onPasskeyPendingMfa` lets UIs jump to the MFA step (`OnboardingUIReact`, `OnboardingUIWeb`, and `useAuthMethods`). `PasskeyFlowResult` is re-exported from `@abstraxn/signer-core`.
21
+ - **Server logout on full disconnect** – When the Abstraxn session disconnect runs, the SDK best-effort calls `POST /auth/logout` with the current access token (external-wallet-only disconnect continues to skip this).
18
22
 
19
23
  ## [3.1.2] - 2026-03-27
20
24
 
@@ -168,67 +168,38 @@ export function AbstraxnProvider({ config, children }) {
168
168
  externalSsr,
169
169
  config.wagmiConfig,
170
170
  ]);
171
- // Connector-free wagmi config so `useConfig` / `useAccount` / etc. never throw when
172
- // `externalWallets.enabled` is false (embedded email/social only). React Query is required
173
- // for WagmiProvider the same as for the full external-wallet tree.
174
- const { embedWagmiConfig, embedConfigError } = useMemo(() => {
175
- if (externalWalletsEnabled) {
176
- return { embedWagmiConfig: null, embedConfigError: null };
177
- }
178
- try {
179
- const cfg = createWagmiConfig(wagmiChains, undefined, undefined, wagmiThemeRef.current, externalSsr, true);
180
- return { embedWagmiConfig: cfg, embedConfigError: null };
181
- }
182
- catch (error) {
183
- console.error("Failed to create embed-only wagmi config:", error);
184
- return {
185
- embedWagmiConfig: null,
186
- embedConfigError: error instanceof Error
187
- ? error
188
- : new Error("Failed to create embed-only wagmi config"),
189
- };
190
- }
191
- }, [externalWalletsEnabled, chainsKey, externalSsr]);
192
- // Embedded-only mode: still mount WagmiProvider (no connectors) when React Query is available.
193
- if (!externalWalletsEnabled) {
171
+ // If external wallets are enabled, wrap with QueryClientProvider and WagmiProvider
172
+ if (externalWalletsEnabled) {
173
+ // Check if React Query is available BEFORE doing anything else
174
+ // This prevents errors from happening in the first place
194
175
  const queryCheck = canUseReactQuery();
195
176
  if (!queryCheck.canUse) {
196
- console.error("❌ Wagmi hooks require @tanstack/react-query. Install it or wrap your app with QueryClientProvider.\n" +
177
+ console.error("❌ External wallets are disabled because React Query is not available.\n" +
197
178
  `Reason: ${queryCheck.reason || "Unknown"}\n` +
198
- "Rendering without WagmiProvider; calls to useConfig may throw.");
179
+ "Please install @tanstack/react-query@^5.90.16 and ensure there is only one React instance.\n" +
180
+ "Falling back to Abstraxn wallet only.");
199
181
  return (_jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }));
200
182
  }
201
- if (embedConfigError || !embedWagmiConfig) {
202
- if (embedConfigError) {
203
- console.error("Failed to create embed-only wagmi config:", embedConfigError);
204
- }
183
+ if (configError) {
184
+ console.error("Failed to create wagmi config:", configError);
185
+ // Fallback to provider without wagmi if config creation fails
205
186
  return (_jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }));
206
187
  }
188
+ if (!wagmiConfig) {
189
+ // Show loading state while config is being created
190
+ // Don't render AbstraxnProviderInner until wagmiConfig is ready
191
+ return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx("div", { style: { display: "none" }, children: "Loading wallet connectors..." }) }));
192
+ }
193
+ // ✅ For SSR mode, wait for hydration before rendering WagmiProvider
194
+ // This ensures injected wallets (Phantom, etc.) are detected properly
207
195
  if (externalSsr && !isHydrated) {
208
- return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx("div", { style: { display: "none" }, children: "Hydrating..." }) }));
196
+ return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx("div", { style: { display: "none" }, children: "Hydrating wallet connectors..." }) }));
209
197
  }
210
- return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx(WagmiProvider, { config: embedWagmiConfig, children: _jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }) }) }));
211
- }
212
- // External wallets enabled: full connectors + Solana adapter tree
213
- // Check if React Query is available BEFORE doing anything else
214
- const queryCheck = canUseReactQuery();
215
- if (!queryCheck.canUse) {
216
- console.error("❌ External wallets are disabled because React Query is not available.\n" +
217
- `Reason: ${queryCheck.reason || "Unknown"}\n` +
218
- "Please install @tanstack/react-query@^5.90.16 and ensure there is only one React instance.\n" +
219
- "Falling back to Abstraxn wallet only.");
220
- return (_jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }));
221
- }
222
- if (configError) {
223
- console.error("Failed to create wagmi config:", configError);
224
- return (_jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }));
225
- }
226
- if (!wagmiConfig) {
227
- return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx("div", { style: { display: "none" }, children: "Loading wallet connectors..." }) }));
228
- }
229
- if (externalSsr && !isHydrated) {
230
- return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx("div", { style: { display: "none" }, children: "Hydrating wallet connectors..." }) }));
198
+ // Do NOT pass key to WagmiProvider. Remounting loses connection state and causes
199
+ // "Connector not connected" in Next.js (e.g. when config loads after hydration).
200
+ return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx(ConnectionProvider, { endpoint: config.chains?.solanaEndpoint || "https://api.mainnet-beta.solana.com", children: _jsx(WalletProvider, { wallets: solanaWallets, autoConnect: true, children: _jsx(WagmiProvider, { config: wagmiConfig, initialState: config.initialState, children: _jsx(AbstraxnProviderWithWagmi, { config: config, children: children }) }) }) }) }));
231
201
  }
232
- return (_jsx(QueryClientWrapper, { queryClient: queryClient, children: _jsx(ConnectionProvider, { endpoint: config.chains?.solanaEndpoint || "https://api.mainnet-beta.solana.com", children: _jsx(WalletProvider, { wallets: solanaWallets, autoConnect: true, children: _jsx(WagmiProvider, { config: wagmiConfig, initialState: config.initialState, children: _jsx(AbstraxnProviderWithWagmi, { config: config, children: children }) }) }) }) }));
202
+ // If external wallets are disabled, use the provider without wagmi
203
+ return (_jsx(AbstraxnProviderWithoutWagmi, { config: config, children: children }));
233
204
  }
234
205
  //# sourceMappingURL=AbstraxnProvider.js.map
@@ -766,10 +766,13 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
766
766
  }
767
767
  const authManager = walletInstance.getAuthManager();
768
768
  const user = await authManager.loginWithPasskey();
769
- // Set user immediately so onLoginSuccess can access it
770
769
  setUser(user);
771
- // Connect wallet after successful authentication
770
+ const lastAuthState = authManager.getLastAuthState();
771
+ if (lastAuthState?.mfaRequired === true) {
772
+ return { mfaRequired: true };
773
+ }
772
774
  await walletInstance.connect();
775
+ return undefined;
773
776
  },
774
777
  onPasskeySignup: async () => {
775
778
  if (!walletInstance)
@@ -784,11 +787,13 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
784
787
  }
785
788
  const authManager = walletInstance.getAuthManager();
786
789
  const user = await authManager.signupWithPasskey();
787
- // Clear any previous errors on successful verification
788
- // setError(null);
789
790
  setUser(user);
790
- // Connect wallet after successful authentication
791
+ const lastAuthState = authManager.getLastAuthState();
792
+ if (lastAuthState?.mfaRequired === true) {
793
+ return { mfaRequired: true };
794
+ }
791
795
  await walletInstance.connect();
796
+ return undefined;
792
797
  },
793
798
  onLoginSuccess: async (_data) => {
794
799
  // Clear any previous errors on successful login
@@ -1605,7 +1610,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
1605
1610
  setLoading(false);
1606
1611
  }
1607
1612
  }, [showOnboarding]);
1608
- // Disconnect wallet
1613
+ // Full disconnect: when Abstraxn is connected, `wallet.disconnect()` runs and signer-core notifies POST /auth/logout; external-wallet-only flows use `disconnectExternalWallet` instead (no core disconnect).
1609
1614
  const disconnect = useCallback(async () => {
1610
1615
  setLoading(true);
1611
1616
  setDisconnecting(true);
@@ -2972,7 +2977,7 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, solana, }
2972
2977
  wagmiDisconnect,
2973
2978
  wagmiAccount?.isConnected,
2974
2979
  ]);
2975
- // Disconnect external wallet
2980
+ // External wallet only — does not call AbstraxnWallet.disconnect (no server /auth/logout).
2976
2981
  const disconnectExternalWallet = useCallback(async () => {
2977
2982
  if (!externalWalletsEnabled || !wagmiDisconnect) {
2978
2983
  return;
@@ -351,10 +351,13 @@ export function useWalletInitialization({ config, walletRef, onboardingRef, otpI
351
351
  }
352
352
  const authManager = walletInstance.getAuthManager();
353
353
  const user = await authManager.loginWithPasskey();
354
- // Set user immediately so onLoginSuccess can access it
355
354
  setUser(user);
356
- // Connect wallet after successful authentication
355
+ const lastAuthState = authManager.getLastAuthState();
356
+ if (lastAuthState?.mfaRequired === true) {
357
+ return { mfaRequired: true };
358
+ }
357
359
  await walletInstance.connect();
360
+ return undefined;
358
361
  },
359
362
  onPasskeySignup: async () => {
360
363
  if (!walletInstance)
@@ -369,11 +372,13 @@ export function useWalletInitialization({ config, walletRef, onboardingRef, otpI
369
372
  }
370
373
  const authManager = walletInstance.getAuthManager();
371
374
  const user = await authManager.signupWithPasskey();
372
- // Clear any previous errors on successful verification
373
- // setError(null);
374
375
  setUser(user);
375
- // Connect wallet after successful authentication
376
+ const lastAuthState = authManager.getLastAuthState();
377
+ if (lastAuthState?.mfaRequired === true) {
378
+ return { mfaRequired: true };
379
+ }
376
380
  await walletInstance.connect();
381
+ return undefined;
377
382
  },
378
383
  onLoginSuccess: async (_data) => {
379
384
  // Clear any previous errors on successful login
@@ -27,7 +27,10 @@ export const OnboardingUIReact = ({ config = {}, modal = false, onClose, externa
27
27
  const authMethods = config.authMethods || ["otp", "google"];
28
28
  const showModalCloseButton = config.showCloseButton === true;
29
29
  const onboarding = useOnboarding(config);
30
- const authMethodsHook = useAuthMethods(config);
30
+ const authMethodsHook = useAuthMethods({
31
+ ...config,
32
+ onPasskeyPendingMfa: config.onPasskeyPendingMfa ?? (() => onboarding.setStep("mfa")),
33
+ });
31
34
  const { user, isConnected, whoami, loading: providerLoading, error: providerError, emailForOtp, } = useAbstraxnWallet();
32
35
  const [showExternalWallets, setShowExternalWallets] = useState(false);
33
36
  const [oauthLoading, setOauthLoading] = useState(false);
@@ -4286,8 +4286,11 @@ export class OnboardingUIWeb {
4286
4286
  this.setLoading(true, "passkey");
4287
4287
  this.hidePasskeyError();
4288
4288
  if (this.config.onPasskeyLogin) {
4289
- await this.config.onPasskeyLogin();
4290
- // Call onLoginSuccess to close modal and update state
4289
+ const result = await this.config.onPasskeyLogin();
4290
+ if (result && typeof result === "object" && result.mfaRequired === true) {
4291
+ this.showMfaVerificationScreenForOAuth();
4292
+ return;
4293
+ }
4291
4294
  if (this.config.onLoginSuccess) {
4292
4295
  this.config.onLoginSuccess({ user: null });
4293
4296
  }
@@ -4318,8 +4321,11 @@ export class OnboardingUIWeb {
4318
4321
  this.setLoading(true, "passkey");
4319
4322
  this.hidePasskeyError();
4320
4323
  if (this.config.onPasskeySignup) {
4321
- await this.config.onPasskeySignup();
4322
- // Call onLoginSuccess to close modal and update state
4324
+ const result = await this.config.onPasskeySignup();
4325
+ if (result && typeof result === "object" && result.mfaRequired === true) {
4326
+ this.showMfaVerificationScreenForOAuth();
4327
+ return;
4328
+ }
4323
4329
  if (this.config.onLoginSuccess) {
4324
4330
  this.config.onLoginSuccess({ user: null });
4325
4331
  }
@@ -192,6 +192,11 @@ export const useAuthMethods = (config) => {
192
192
  else {
193
193
  await wallet.loginWithPasskey();
194
194
  }
195
+ const mfaPending = wallet.getAuthManager().getLastAuthState()?.mfaRequired === true;
196
+ if (mfaPending) {
197
+ config?.onPasskeyPendingMfa?.();
198
+ return;
199
+ }
195
200
  config?.onLoginSuccess?.({});
196
201
  }
197
202
  catch (err) {
@@ -225,6 +230,11 @@ export const useAuthMethods = (config) => {
225
230
  else {
226
231
  await wallet.signupWithPasskey();
227
232
  }
233
+ const mfaPending = wallet.getAuthManager().getLastAuthState()?.mfaRequired === true;
234
+ if (mfaPending) {
235
+ config?.onPasskeyPendingMfa?.();
236
+ return;
237
+ }
228
238
  config?.onLoginSuccess?.({});
229
239
  }
230
240
  catch (err) {
@@ -322,6 +322,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
322
322
  withdrawalsRoot?: `0x${string}` | undefined;
323
323
  transactions: includeTransactions extends true ? ({
324
324
  type: "legacy";
325
+ value: bigint;
325
326
  yParity?: undefined | undefined;
326
327
  from: Address;
327
328
  gas: bigint;
@@ -333,7 +334,6 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
333
334
  to: Address | null;
334
335
  typeHex: import("viem").Hex | null;
335
336
  v: bigint;
336
- value: bigint;
337
337
  accessList?: undefined | undefined;
338
338
  authorizationList?: undefined | undefined;
339
339
  blobVersionedHashes?: undefined | undefined;
@@ -347,6 +347,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
347
347
  transactionIndex: (blockTag extends "pending" ? true : false) extends infer T_2 ? T_2 extends (blockTag extends "pending" ? true : false) ? T_2 extends true ? null : number : never : never;
348
348
  } | {
349
349
  type: "eip2930";
350
+ value: bigint;
350
351
  yParity: number;
351
352
  from: Address;
352
353
  gas: bigint;
@@ -358,7 +359,6 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
358
359
  to: Address | null;
359
360
  typeHex: import("viem").Hex | null;
360
361
  v: bigint;
361
- value: bigint;
362
362
  accessList: import("viem").AccessList;
363
363
  authorizationList?: undefined | undefined;
364
364
  blobVersionedHashes?: undefined | undefined;
@@ -372,6 +372,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
372
372
  transactionIndex: (blockTag extends "pending" ? true : false) extends infer T_5 ? T_5 extends (blockTag extends "pending" ? true : false) ? T_5 extends true ? null : number : never : never;
373
373
  } | {
374
374
  type: "eip1559";
375
+ value: bigint;
375
376
  yParity: number;
376
377
  from: Address;
377
378
  gas: bigint;
@@ -383,7 +384,6 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
383
384
  to: Address | null;
384
385
  typeHex: import("viem").Hex | null;
385
386
  v: bigint;
386
- value: bigint;
387
387
  accessList: import("viem").AccessList;
388
388
  authorizationList?: undefined | undefined;
389
389
  blobVersionedHashes?: undefined | undefined;
@@ -397,6 +397,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
397
397
  transactionIndex: (blockTag extends "pending" ? true : false) extends infer T_8 ? T_8 extends (blockTag extends "pending" ? true : false) ? T_8 extends true ? null : number : never : never;
398
398
  } | {
399
399
  type: "eip4844";
400
+ value: bigint;
400
401
  yParity: number;
401
402
  from: Address;
402
403
  gas: bigint;
@@ -408,7 +409,6 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
408
409
  to: Address | null;
409
410
  typeHex: import("viem").Hex | null;
410
411
  v: bigint;
411
- value: bigint;
412
412
  accessList: import("viem").AccessList;
413
413
  authorizationList?: undefined | undefined;
414
414
  blobVersionedHashes: readonly import("viem").Hex[];
@@ -422,6 +422,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
422
422
  transactionIndex: (blockTag extends "pending" ? true : false) extends infer T_11 ? T_11 extends (blockTag extends "pending" ? true : false) ? T_11 extends true ? null : number : never : never;
423
423
  } | {
424
424
  type: "eip7702";
425
+ value: bigint;
425
426
  yParity: number;
426
427
  from: Address;
427
428
  gas: bigint;
@@ -433,7 +434,6 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
433
434
  to: Address | null;
434
435
  typeHex: import("viem").Hex | null;
435
436
  v: bigint;
436
- value: bigint;
437
437
  accessList: import("viem").AccessList;
438
438
  authorizationList: import("viem").SignedAuthorizationList;
439
439
  blobVersionedHashes?: undefined | undefined;
@@ -473,6 +473,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
473
473
  getStorageAt: (args: import("viem").GetStorageAtParameters) => Promise<import("viem").GetStorageAtReturnType>;
474
474
  getTransaction: <blockTag extends import("viem").BlockTag = "latest">(args: import("viem").GetTransactionParameters<blockTag>) => Promise<{
475
475
  type: "legacy";
476
+ value: bigint;
476
477
  yParity?: undefined | undefined;
477
478
  from: Address;
478
479
  gas: bigint;
@@ -484,7 +485,6 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
484
485
  to: Address | null;
485
486
  typeHex: import("viem").Hex | null;
486
487
  v: bigint;
487
- value: bigint;
488
488
  accessList?: undefined | undefined;
489
489
  authorizationList?: undefined | undefined;
490
490
  blobVersionedHashes?: undefined | undefined;
@@ -498,6 +498,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
498
498
  transactionIndex: (blockTag extends "pending" ? true : false) extends infer T_2 ? T_2 extends (blockTag extends "pending" ? true : false) ? T_2 extends true ? null : number : never : never;
499
499
  } | {
500
500
  type: "eip2930";
501
+ value: bigint;
501
502
  yParity: number;
502
503
  from: Address;
503
504
  gas: bigint;
@@ -509,7 +510,6 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
509
510
  to: Address | null;
510
511
  typeHex: import("viem").Hex | null;
511
512
  v: bigint;
512
- value: bigint;
513
513
  accessList: import("viem").AccessList;
514
514
  authorizationList?: undefined | undefined;
515
515
  blobVersionedHashes?: undefined | undefined;
@@ -523,6 +523,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
523
523
  transactionIndex: (blockTag extends "pending" ? true : false) extends infer T_5 ? T_5 extends (blockTag extends "pending" ? true : false) ? T_5 extends true ? null : number : never : never;
524
524
  } | {
525
525
  type: "eip1559";
526
+ value: bigint;
526
527
  yParity: number;
527
528
  from: Address;
528
529
  gas: bigint;
@@ -534,7 +535,6 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
534
535
  to: Address | null;
535
536
  typeHex: import("viem").Hex | null;
536
537
  v: bigint;
537
- value: bigint;
538
538
  accessList: import("viem").AccessList;
539
539
  authorizationList?: undefined | undefined;
540
540
  blobVersionedHashes?: undefined | undefined;
@@ -548,6 +548,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
548
548
  transactionIndex: (blockTag extends "pending" ? true : false) extends infer T_8 ? T_8 extends (blockTag extends "pending" ? true : false) ? T_8 extends true ? null : number : never : never;
549
549
  } | {
550
550
  type: "eip4844";
551
+ value: bigint;
551
552
  yParity: number;
552
553
  from: Address;
553
554
  gas: bigint;
@@ -559,7 +560,6 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
559
560
  to: Address | null;
560
561
  typeHex: import("viem").Hex | null;
561
562
  v: bigint;
562
- value: bigint;
563
563
  accessList: import("viem").AccessList;
564
564
  authorizationList?: undefined | undefined;
565
565
  blobVersionedHashes: readonly import("viem").Hex[];
@@ -573,6 +573,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
573
573
  transactionIndex: (blockTag extends "pending" ? true : false) extends infer T_11 ? T_11 extends (blockTag extends "pending" ? true : false) ? T_11 extends true ? null : number : never : never;
574
574
  } | {
575
575
  type: "eip7702";
576
+ value: bigint;
576
577
  yParity: number;
577
578
  from: Address;
578
579
  gas: bigint;
@@ -584,7 +585,6 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
584
585
  to: Address | null;
585
586
  typeHex: import("viem").Hex | null;
586
587
  v: bigint;
587
- value: bigint;
588
588
  accessList: import("viem").AccessList;
589
589
  authorizationList: import("viem").SignedAuthorizationList;
590
590
  blobVersionedHashes?: undefined | undefined;
@@ -3888,7 +3888,7 @@ export declare function usePublicClient(chain: Chain, rpcUrl: string): {
3888
3888
  transport?: undefined;
3889
3889
  type?: undefined;
3890
3890
  uid?: undefined;
3891
- } & import("viem").ExactPartial<Pick<import("viem").PublicActions<import("viem").Transport, Chain | undefined, undefined>, "prepareTransactionRequest" | "call" | "createContractEventFilter" | "createEventFilter" | "estimateContractGas" | "estimateGas" | "getBlock" | "getBlockNumber" | "getChainId" | "getContractEvents" | "getEnsText" | "getFilterChanges" | "getGasPrice" | "getLogs" | "getTransaction" | "getTransactionCount" | "getTransactionReceipt" | "readContract" | "sendRawTransaction" | "simulateContract" | "uninstallFilter" | "watchBlockNumber" | "watchContractEvent"> & Pick<import("viem").WalletActions<Chain | undefined, undefined>, "sendTransaction" | "writeContract">>>(fn: (client: import("viem").Client<import("viem").Transport, Chain | undefined, undefined, import("viem").PublicRpcSchema, import("viem").PublicActions<import("viem").Transport, Chain | undefined>>) => client) => import("viem").Client<import("viem").Transport, Chain | undefined, undefined, import("viem").PublicRpcSchema, { [K in keyof client]: client[K]; } & import("viem").PublicActions<import("viem").Transport, Chain | undefined>>;
3891
+ } & import("viem").ExactPartial<Pick<import("viem").PublicActions<import("viem").Transport, Chain | undefined, undefined>, "call" | "createContractEventFilter" | "createEventFilter" | "estimateContractGas" | "estimateGas" | "getBlock" | "getBlockNumber" | "getChainId" | "getContractEvents" | "getEnsText" | "getFilterChanges" | "getGasPrice" | "getLogs" | "getTransaction" | "getTransactionCount" | "getTransactionReceipt" | "prepareTransactionRequest" | "readContract" | "sendRawTransaction" | "simulateContract" | "uninstallFilter" | "watchBlockNumber" | "watchContractEvent"> & Pick<import("viem").WalletActions<Chain | undefined, undefined>, "sendTransaction" | "writeContract">>>(fn: (client: import("viem").Client<import("viem").Transport, Chain | undefined, undefined, import("viem").PublicRpcSchema, import("viem").PublicActions<import("viem").Transport, Chain | undefined>>) => client) => import("viem").Client<import("viem").Transport, Chain | undefined, undefined, import("viem").PublicRpcSchema, { [K in keyof client]: client[K]; } & import("viem").PublicActions<import("viem").Transport, Chain | undefined>>;
3892
3892
  };
3893
3893
  };
3894
3894
  /**
@@ -8350,7 +8350,7 @@ export declare function useWalletClient(chain: any, rpcUrl?: string): {
8350
8350
  transport?: undefined;
8351
8351
  type?: undefined;
8352
8352
  uid?: undefined;
8353
- } & import("viem").ExactPartial<Pick<import("viem").PublicActions<import("viem").Transport, Chain | undefined, import("viem").Account | undefined>, "prepareTransactionRequest" | "call" | "createContractEventFilter" | "createEventFilter" | "estimateContractGas" | "estimateGas" | "getBlock" | "getBlockNumber" | "getChainId" | "getContractEvents" | "getEnsText" | "getFilterChanges" | "getGasPrice" | "getLogs" | "getTransaction" | "getTransactionCount" | "getTransactionReceipt" | "readContract" | "sendRawTransaction" | "simulateContract" | "uninstallFilter" | "watchBlockNumber" | "watchContractEvent"> & Pick<import("viem").WalletActions<Chain | undefined, import("viem").Account | undefined>, "sendTransaction" | "writeContract">>>(fn: (client: import("viem").Client<import("viem").Transport, Chain | undefined, import("viem").Account | undefined, import("viem").WalletRpcSchema, import("viem").WalletActions<Chain | undefined, import("viem").Account | undefined>>) => client) => import("viem").Client<import("viem").Transport, Chain | undefined, import("viem").Account | undefined, import("viem").WalletRpcSchema, { [K in keyof client]: client[K]; } & import("viem").WalletActions<Chain | undefined, import("viem").Account | undefined>>;
8353
+ } & import("viem").ExactPartial<Pick<import("viem").PublicActions<import("viem").Transport, Chain | undefined, import("viem").Account | undefined>, "call" | "createContractEventFilter" | "createEventFilter" | "estimateContractGas" | "estimateGas" | "getBlock" | "getBlockNumber" | "getChainId" | "getContractEvents" | "getEnsText" | "getFilterChanges" | "getGasPrice" | "getLogs" | "getTransaction" | "getTransactionCount" | "getTransactionReceipt" | "prepareTransactionRequest" | "readContract" | "sendRawTransaction" | "simulateContract" | "uninstallFilter" | "watchBlockNumber" | "watchContractEvent"> & Pick<import("viem").WalletActions<Chain | undefined, import("viem").Account | undefined>, "sendTransaction" | "writeContract">>>(fn: (client: import("viem").Client<import("viem").Transport, Chain | undefined, import("viem").Account | undefined, import("viem").WalletRpcSchema, import("viem").WalletActions<Chain | undefined, import("viem").Account | undefined>>) => client) => import("viem").Client<import("viem").Transport, Chain | undefined, import("viem").Account | undefined, import("viem").WalletRpcSchema, { [K in keyof client]: client[K]; } & import("viem").WalletActions<Chain | undefined, import("viem").Account | undefined>>;
8354
8354
  };
8355
8355
  };
8356
8356
  /**
@@ -13289,7 +13289,7 @@ export declare function useExternalWalletClient(): {
13289
13289
  transport?: undefined;
13290
13290
  type?: undefined;
13291
13291
  uid?: undefined;
13292
- } & import("viem").ExactPartial<Pick<import("viem").PublicActions<import("wagmi").Transport<string, Record<string, any>, import("viem").EIP1193RequestFn>, Chain, import("viem").Account>, "prepareTransactionRequest" | "call" | "createContractEventFilter" | "createEventFilter" | "estimateContractGas" | "estimateGas" | "getBlock" | "getBlockNumber" | "getChainId" | "getContractEvents" | "getEnsText" | "getFilterChanges" | "getGasPrice" | "getLogs" | "getTransaction" | "getTransactionCount" | "getTransactionReceipt" | "readContract" | "sendRawTransaction" | "simulateContract" | "uninstallFilter" | "watchBlockNumber" | "watchContractEvent"> & Pick<import("viem").WalletActions<Chain, import("viem").Account>, "sendTransaction" | "writeContract">>>(fn: (client: import("viem").Client<import("wagmi").Transport<string, Record<string, any>, import("viem").EIP1193RequestFn>, Chain, import("viem").Account, import("viem").WalletRpcSchema, import("viem").WalletActions<Chain, import("viem").Account>>) => client) => import("viem").Client<import("wagmi").Transport<string, Record<string, any>, import("viem").EIP1193RequestFn>, Chain, import("viem").Account, import("viem").WalletRpcSchema, { [K in keyof client]: client[K]; } & import("viem").WalletActions<Chain, import("viem").Account>>;
13292
+ } & import("viem").ExactPartial<Pick<import("viem").PublicActions<import("wagmi").Transport<string, Record<string, any>, import("viem").EIP1193RequestFn>, Chain, import("viem").Account>, "call" | "createContractEventFilter" | "createEventFilter" | "estimateContractGas" | "estimateGas" | "getBlock" | "getBlockNumber" | "getChainId" | "getContractEvents" | "getEnsText" | "getFilterChanges" | "getGasPrice" | "getLogs" | "getTransaction" | "getTransactionCount" | "getTransactionReceipt" | "prepareTransactionRequest" | "readContract" | "sendRawTransaction" | "simulateContract" | "uninstallFilter" | "watchBlockNumber" | "watchContractEvent"> & Pick<import("viem").WalletActions<Chain, import("viem").Account>, "sendTransaction" | "writeContract">>>(fn: (client: import("viem").Client<import("wagmi").Transport<string, Record<string, any>, import("viem").EIP1193RequestFn>, Chain, import("viem").Account, import("viem").WalletRpcSchema, import("viem").WalletActions<Chain, import("viem").Account>>) => client) => import("viem").Client<import("wagmi").Transport<string, Record<string, any>, import("viem").EIP1193RequestFn>, Chain, import("viem").Account, import("viem").WalletRpcSchema, { [K in keyof client]: client[K]; } & import("viem").WalletActions<Chain, import("viem").Account>>;
13293
13293
  } | null;
13294
13294
  isConnected: boolean;
13295
13295
  isPending: boolean;
package/dist/src/hooks.js CHANGED
@@ -504,7 +504,7 @@ export function useExternalWalletChain() {
504
504
  * ```
505
505
  */
506
506
  export function useExternalWalletInfo() {
507
- const { externalWalletChainId, externalWalletNetwork, isExternalWalletConnected, externalWalletAddress, externalWalletBalance, } = useExternalWallet();
507
+ const { externalWalletChainId, externalWalletNetwork, switchExternalWalletChain, isExternalWalletConnected, externalWalletAddress, externalWalletBalance, } = useExternalWallet();
508
508
  const { sendTransaction, signMessage, signTransaction, switchChain, } = useAbstraxnWallet();
509
509
  const [formattedBalance, setFormattedBalance] = useState('0');
510
510
  useEffect(() => {
@@ -571,8 +571,8 @@ export function useExternalWalletInfo() {
571
571
  // Balance information
572
572
  balance: externalWalletBalance, // BigInt in wei
573
573
  formattedBalance, // String formatted as ETH (e.g., "0.123456")
574
- // Unified chain switch (embedded + external); not only switchExternalWalletChain.
575
- switchChain,
574
+ // Chain switching
575
+ switchChain: switchExternalWalletChain,
576
576
  // Connection status
577
577
  isConnected: isExternalWalletConnected,
578
578
  address: externalWalletAddress,
@@ -9,13 +9,7 @@ import { type Chain as CoreChain } from "@abstraxn/signer-core";
9
9
  * Note: Uses 'injected' connector which automatically detects MetaMask and other wallets
10
10
  * without requiring @metamask/sdk
11
11
  */
12
- export declare function createWagmiConfig(chains?: CoreChain[] | Chain[], walletConnectProjectId?: string, enabledConnectors?: ("injected" | "metaMask" | "walletConnect")[], theme?: "light" | "dark", ssr?: boolean,
13
- /**
14
- * When true, builds a wagmi config with **no** wallet connectors. Used when
15
- * `externalWallets.enabled` is false so hooks like `useConfig` / `useAccount`
16
- * still work for embedded flows without exposing MetaMask / WalletConnect.
17
- */
18
- embedOnly?: boolean): Config;
12
+ export declare function createWagmiConfig(chains?: CoreChain[] | Chain[], walletConnectProjectId?: string, enabledConnectors?: ("injected" | "metaMask" | "walletConnect")[], theme?: "light" | "dark", ssr?: boolean): Config;
19
13
  /**
20
14
  * External wallet connector types
21
15
  */
@@ -35,13 +35,7 @@ function convertToViemChain(chain) {
35
35
  * Note: Uses 'injected' connector which automatically detects MetaMask and other wallets
36
36
  * without requiring @metamask/sdk
37
37
  */
38
- export function createWagmiConfig(chains, walletConnectProjectId, enabledConnectors, theme, ssr,
39
- /**
40
- * When true, builds a wagmi config with **no** wallet connectors. Used when
41
- * `externalWallets.enabled` is false so hooks like `useConfig` / `useAccount`
42
- * still work for embedded flows without exposing MetaMask / WalletConnect.
43
- */
44
- embedOnly) {
38
+ export function createWagmiConfig(chains, walletConnectProjectId, enabledConnectors, theme, ssr) {
45
39
  // Normalize chains to ensure they are all valid viem Chain objects
46
40
  // This handles mixed arrays of viem Chains and CoreChains (e.g. custom chains)
47
41
  const viemChains = chains && chains.length > 0
@@ -54,28 +48,6 @@ embedOnly) {
54
48
  return convertToViemChain(chain);
55
49
  })
56
50
  : SUPPORTED_CHAINS.map(convertToViemChain);
57
- // Ensure we have at least one chain (shared by embed + full config)
58
- if (viemChains.length === 0) {
59
- throw new Error("At least one chain is required");
60
- }
61
- const transports = viemChains.reduce((acc, chain) => {
62
- acc[chain.id] = http();
63
- return acc;
64
- }, {});
65
- const storage = ssr
66
- ? createStorage({ storage: cookieStorage })
67
- : typeof window !== "undefined"
68
- ? createStorage({ storage: window.localStorage })
69
- : undefined;
70
- if (embedOnly) {
71
- return createConfig({
72
- chains: viemChains,
73
- connectors: [],
74
- transports,
75
- storage,
76
- ssr: !!ssr,
77
- });
78
- }
79
51
  const connectors = [];
80
52
  // Add connectors based on enabled list
81
53
  // Note: 'injected' connector will automatically detect MetaMask and other injected wallets
@@ -123,11 +95,23 @@ embedOnly) {
123
95
  }));
124
96
  }
125
97
  }
98
+ // Ensure we have at least one chain
99
+ if (viemChains.length === 0) {
100
+ throw new Error("At least one chain is required");
101
+ }
126
102
  return createConfig({
127
103
  chains: viemChains,
128
104
  connectors,
129
- transports,
130
- storage,
105
+ transports: viemChains.reduce((acc, chain) => {
106
+ acc[chain.id] = http();
107
+ return acc;
108
+ }, {}),
109
+ // Configure storage based on SSR setting
110
+ storage: ssr
111
+ ? createStorage({ storage: cookieStorage })
112
+ : typeof window !== "undefined"
113
+ ? createStorage({ storage: window.localStorage })
114
+ : undefined,
131
115
  ssr: !!ssr,
132
116
  });
133
117
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abstraxn/signer-react",
3
- "version": "3.1.3",
3
+ "version": "3.1.4",
4
4
  "description": "React SDK for Abstraxn Wallet - React components, hooks, and providers for seamless Web3 wallet integration",
5
5
  "main": "./dist/src/index.js",
6
6
  "module": "./dist/src/index.js",
@@ -40,7 +40,7 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@abstraxn/signer-core": "^2.1.1",
43
+ "@abstraxn/signer-core": "2.1.2",
44
44
  "@solana/wallet-adapter-base": "^0.9.27",
45
45
  "@solana/wallet-adapter-react": "^0.15.39",
46
46
  "@solana/wallet-adapter-react-ui": "^0.9.39",