Guides
Lifecycle callbacks
onConnect, onConnectError, onDisconnect, onHydrated, onSlowConnect, onStorageError.
WalletManagerConfig exposes lifecycle callbacks. They exist so you wire
observability and side effects in one place instead of wrapping every
connect call.
import type { WalletManagerConfig } from "@usebutr/core";
import { autoDiscovery } from "@usebutr/wallets";
const config: WalletManagerConfig = {
onConnect: (wallet, { reconnected }) => {
track(reconnected ? "wallet_restored" : "wallet_connected", { id: wallet.connector.id });
},
onConnectError: (error, connectorId) => reportToSentry(error, { connectorId, kind: error.kind }),
onDisconnect: (wallet, { byUser }) => {
track("wallet_disconnected", { byUser, id: wallet.connector.id });
},
onHydrated: (outcome) => track("hydrated", outcome),
onSlowConnect: (connectorId) => showHint(`${connectorId} is taking a while…`),
onStorageError: (error) => reportToSentry(error),
slowConnectThresholdMs: 8000,
sources: [autoDiscovery()],
};| Callback | Signature | Fires when |
|---|---|---|
onConnect | (wallet: ConnectedWallet, context: { reconnected: boolean }) => void | a wallet goes live: a user connect, or a silent restore |
onConnectError | (error: ConnectionError, connectorId: string) => void | a connect attempt fails |
onDisconnect | (wallet: ConnectedWallet, context: { byUser: boolean }) => void | a live wallet leaves the pool |
onHydrated | (outcome: HydrationOutcome) => void | once, after the start-up restore pass |
onSlowConnect | (connectorId: string) => void | a connect passes slowConnectThresholdMs without settling |
onStorageError | (error: Error) => void | loading or saving persisted state fails |
The manager reads the config once, when it is created, so define it at module scope. A callback that closes over component state sees only the values from that first render.
Notes
onConnectfires forconnect()withreconnected: false, and for every silent restore withreconnected: true, including a wallet restored late because its adapter announced after the start-up pass. It is the one place to observe every wallet going live.onConnectErrorreceives the normalisedConnectionError, so you branch onerror.kind. It fires for every failed attempt, whichever component started it.onDisconnecthasbyUser: truefordisconnect(id)anddisconnectAll(), which fires it once per live wallet.byUser: falsemeans the wallet ended the session itself (locked, extension removed, relay session expired); that entry stays persisted and is retried on the next load. Run sign-out logic, such as clearing auth tokens, after callingdisconnectAll().onHydratedis the only place to learn which stored wallets came back, which are still waiting for their adapter, and which failed; see hydration. Without it, failed restores are logged withconsole.warn.onSlowConnectfires at most once per attempt, and only if the connect hasn't resolved or rejected by the threshold (default5000ms). Useful for a "still trying, check your wallet" hint or a slow-path metric. It is a hint, not a timeout: the attempt itself fails withTimeoutafter 90 seconds.onStorageErroris the only signal for otherwise-silent persistence failures. With no callback the manager logs them withconsole.warn. See persistence.
A callback that throws is caught and logged; it never breaks the manager.
Source: packages/core/src/types/manager.ts (WalletManagerConfig),
packages/core/src/store/wallet-manager.ts.