@usebutr/core
v3.0.1
Published
Core types, store, storage, and discovery seam for butr. No React, no protocols.
Maintainers
Readme
@usebutr/core
Core types, store, storage, and discovery seam for butr. No React, no protocols.
Part of butr, a multi-chain wallet discovery and connection-state library. Your application owns the picker UI and chain client.
Install
npm install @usebutr/core zustandThe wallet manager works outside React. Pair it with @usebutr/wallets (or one
platform's discover*Adapters) to find real wallets, or use @usebutr/react
for the provider and hooks.
Usage
import { createWalletManager, fromAdapters } from "@usebutr/core";
import { autoDiscovery } from "@usebutr/wallets";
const manager = createWalletManager({
onConnectError: (error, connectorId) => console.warn(connectorId, error.kind),
sources: [autoDiscovery()],
});
// Creating a manager has no side effects; start() subscribes the sources,
// restores persisted connections once, and bridges wallet events.
const stop = manager.start();
const wallet = await manager.connect("io.metamask");
// A method exists only when it works for this wallet.
if (wallet.connector.signMessage) {
await wallet.connector.signMessage(new TextEncoder().encode("hello"), {
account: wallet.account,
});
}
manager.subscribe((state) => console.log(state.pool.size, state.activeConnectorId));- Sources. A
WalletSourceis(onAdapter) => unsubscribe, so everydiscover*Adaptersexport goes intosourcesas-is.fromAdapters(adapters)wraps an array or a promise of built adapters (WalletConnect, Ledger, hand-rolled ones). The first adapter announced for an id wins. - State.
getState()holds the discoveredadapters, the livepool, theselectionper platform,activeConnectorId,reconnectingIds, and the latest attempt'sconnectionStatus/connectionError. - Actions.
connect,disconnect,disconnectAll,requestAccounts,setAccount,setActive,setSelection,clearConnectionError.connectresolves theConnectedWalletand rejects with aConnectionErrorwhosekindisUserRejected,RequestPending,WalletLocked,ChainMismatch,NotConnected,Timeout,WalletNotFoundorUnknown. - Signers.
connector.getSigner()resolves a taggedWalletSigner; narrow it withswitch (signer.kind). Each transport package registers its kind. - Chains and accounts. Every registry lives here (
EVM_CHAINS,SVM_CHAINS,SUI_CHAINS,BITCOIN_CHAINS,POLKADOT_CHAINS, their*_LIST,CHAINS_BY_PLATFORM). Adapters build chains withresolveChain(id, list)and accounts withbuildAccount(address, chain).
Persistence
Connections persist to localStorage and sessionStorage by default, written
after every change once start-up hydration has read what was there. Swap the
drivers with createWalletStorage({ persistent, session }) (for example
createCookieStorageDriver() so a server can read them), or pass any
WalletPersistence: an object with load() and save(state).
To render connections on the server, read the cookies with
readWalletSnapshot(cookies) and pass the snapshot as
createWalletManager(config, { initialState }). Seeded wallets render at
once and stay in reconnectingIds until their silent reconnect lands.
Documentation
License
MIT, copyright 2026 Pedro Filho.
