@abstraxn/signer-react 1.0.15 → 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/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
+ ## [1.0.16] - 2026-02-23
9
+
10
+ ### Fixed
11
+
12
+ - **External wallet disconnect from extension** – When the user disconnects from an external wallet (e.g. MetaMask) via the extension ("Disconnect this site"), the app now updates `isConnected` to false immediately without requiring a page refresh. Previously the sync effect returned early when the user had explicitly connected, so state was never reset until refresh. The fix: (1) allow the sync effect to run the existing reset when wagmi reports disconnected; (2) use wagmi’s `useConnectionEffect(onDisconnect)` to clear external wallet state as soon as wagmi reports disconnect; (3) subscribe to the connector provider’s `accountsChanged` and `disconnect` events so state clears even if wagmi is slow or stale.
13
+
8
14
  ## [1.0.15] - 2026-02-20
9
15
 
10
16
  ### Added
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * AbstraxnProviderInner - Core provider logic
4
4
  * This component contains all the wallet state management and operations
@@ -6,15 +6,22 @@ import { jsx as _jsx } from "react/jsx-runtime";
6
6
  import { useEffect, useState, useRef, useCallback, useMemo, } from "react";
7
7
  import { AbstraxnWallet, AuthenticationError, } from "@abstraxn/signer-core";
8
8
  import { OnboardingUIWeb } from "../OnboardingUI";
9
+ import { useConnectionEffect, } from "wagmi";
9
10
  import { parseEther, createPublicClient, http } from "viem";
10
11
  import { ExternalWalletButtons } from "../../ExternalWalletButtons";
11
12
  import { EVM_CHAINS, SOLANA_CHAINS, getChainById, toCoreChain, } from "../../chains";
12
13
  import { AbstraxnContext } from "./context";
14
+ /** Syncs wagmi disconnect to external wallet state; only rendered when wagmi is available (under WagmiProvider). */
15
+ function WagmiConnectionEffectSync({ onDisconnect, }) {
16
+ useConnectionEffect({ onDisconnect });
17
+ return null;
18
+ }
13
19
  export function AbstraxnProviderInner({ config, children, base, wagmi, }) {
14
20
  const { isInitialized, setIsInitialized, isConnected, setIsConnected, address, setAddress, user, setUser, whoami, setWhoami, chainId, setChainId, error, setError, loading, setLoading, resending, setResending, walletBalance, setWalletBalance, onboardingRef, otpIdRef, walletRef, googleCallbackHandledRef, twitterCallbackHandledRef, discordCallbackHandledRef, } = base;
15
21
  const externalWalletsEnabled = config.externalWallets?.enabled ?? false;
16
22
  // Keep a ref to avoid re-creating callbacks when toggling config (prevents flicker)
17
23
  const externalWalletsEnabledRef = useRef(externalWalletsEnabled);
24
+ const isExternalWalletConnectedRef = useRef(false);
18
25
  useEffect(() => {
19
26
  externalWalletsEnabledRef.current = externalWalletsEnabled;
20
27
  }, [externalWalletsEnabled]);
@@ -37,6 +44,9 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, }) {
37
44
  const [emailForOtp, setEmailForOtpState] = useState("");
38
45
  const explicitConnectionRef = useRef(false);
39
46
  const autoDisconnectHandledRef = useRef(false);
47
+ useEffect(() => {
48
+ isExternalWalletConnectedRef.current = isExternalWalletConnected;
49
+ }, [isExternalWalletConnected]);
40
50
  // Track when we last connected to prevent premature reset
41
51
  const lastConnectionTimeRef = useRef(0);
42
52
  // Refs to track previous values and prevent unnecessary updates
@@ -1984,12 +1994,6 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, }) {
1984
1994
  isUpdatingRef.current = false;
1985
1995
  return;
1986
1996
  }
1987
- // If we're not connected but explicitConnectionRef is true, it means we're trying to reconnect
1988
- // Don't reset state in this case - wait for the connection to complete
1989
- if (!wagmiAccount.isConnected && explicitConnectionRef.current) {
1990
- // Connection is in progress, don't interfere
1991
- return;
1992
- }
1993
1997
  }
1994
1998
  // Check if external wallet is connected
1995
1999
  if (wagmiAccount.isConnected && wagmiAccount.address) {
@@ -2483,6 +2487,95 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, }) {
2483
2487
  setLoading(false);
2484
2488
  }
2485
2489
  }, [externalWalletsEnabled, wagmiDisconnect, wagmiAccount?.connector]);
2490
+ // When wagmi reports disconnect (e.g. user disconnected in extension), clear external wallet state immediately
2491
+ const handleWagmiDisconnect = useCallback(() => {
2492
+ if (!externalWalletsEnabledRef.current)
2493
+ return;
2494
+ setIsExternalWalletConnected(false);
2495
+ setExternalWalletAddress(null);
2496
+ setExternalWalletChainId(null);
2497
+ setConnectionType(null);
2498
+ try {
2499
+ localStorage.removeItem("abstraxn_connection_type");
2500
+ }
2501
+ catch (e) {
2502
+ // Ignore
2503
+ }
2504
+ explicitConnectionRef.current = false;
2505
+ lastConnectionTimeRef.current = 0;
2506
+ lastAddressRef.current = null;
2507
+ lastChainIdRef.current = null;
2508
+ if (!walletRef.current?.isConnected) {
2509
+ setIsConnected(false);
2510
+ setAddress(null);
2511
+ setChainId(null);
2512
+ }
2513
+ }, [
2514
+ setIsExternalWalletConnected,
2515
+ setExternalWalletAddress,
2516
+ setExternalWalletChainId,
2517
+ setConnectionType,
2518
+ setIsConnected,
2519
+ setAddress,
2520
+ setChainId,
2521
+ ]);
2522
+ // When user disconnects in the extension, provider may emit before wagmi updates; listen so we clear state even if wagmi is stale
2523
+ const providerListenerCleanupRef = useRef(null);
2524
+ useEffect(() => {
2525
+ if (!externalWalletsEnabled ||
2526
+ !isExternalWalletConnected ||
2527
+ !wagmiAccount?.connector) {
2528
+ return;
2529
+ }
2530
+ const connector = wagmiAccount.connector;
2531
+ let mounted = true;
2532
+ const setup = async () => {
2533
+ try {
2534
+ const getProvider = connector.getProvider ?? connector.getEthereumProvider;
2535
+ if (typeof getProvider !== "function")
2536
+ return;
2537
+ const p = await getProvider();
2538
+ if (!mounted || !p)
2539
+ return;
2540
+ const onDisconnectFromProvider = () => {
2541
+ if (!isExternalWalletConnectedRef.current)
2542
+ return;
2543
+ handleWagmiDisconnect();
2544
+ };
2545
+ const onAccountsChanged = (accounts) => {
2546
+ const list = Array.isArray(accounts) ? accounts : [];
2547
+ if (list.length === 0)
2548
+ onDisconnectFromProvider();
2549
+ };
2550
+ p.on?.("accountsChanged", onAccountsChanged);
2551
+ p.on?.("disconnect", onDisconnectFromProvider);
2552
+ return () => {
2553
+ p.removeListener?.("accountsChanged", onAccountsChanged);
2554
+ p.removeListener?.("disconnect", onDisconnectFromProvider);
2555
+ };
2556
+ }
2557
+ catch {
2558
+ // Connector may not support getProvider (e.g. some injected)
2559
+ return undefined;
2560
+ }
2561
+ };
2562
+ setup().then((cleanup) => {
2563
+ if (mounted)
2564
+ providerListenerCleanupRef.current = cleanup ?? null;
2565
+ });
2566
+ return () => {
2567
+ mounted = false;
2568
+ const cleanup = providerListenerCleanupRef.current;
2569
+ providerListenerCleanupRef.current = null;
2570
+ if (typeof cleanup === "function")
2571
+ cleanup();
2572
+ };
2573
+ }, [
2574
+ externalWalletsEnabled,
2575
+ isExternalWalletConnected,
2576
+ wagmiAccount?.connector,
2577
+ handleWagmiDisconnect,
2578
+ ]);
2486
2579
  // Helper function to get network name from chain ID
2487
2580
  const getNetworkName = useCallback((chainId) => {
2488
2581
  const chainNames = {
@@ -3351,6 +3444,6 @@ export function AbstraxnProviderInner({ config, children, base, wagmi, }) {
3351
3444
  console.warn("Failed to update ExternalWalletButtons:", error);
3352
3445
  }
3353
3446
  }, [value, externalWalletsEnabled]);
3354
- return (_jsx(AbstraxnContext.Provider, { value: value, children: children }));
3447
+ return (_jsxs(AbstraxnContext.Provider, { value: value, children: [wagmi ? (_jsx(WagmiConnectionEffectSync, { onDisconnect: handleWagmiDisconnect })) : null, children] }));
3355
3448
  }
3356
3449
  //# sourceMappingURL=AbstraxnProviderInner.js.map