@usebutr/core 2.0.0 → 2.0.1
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 +213 -0
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/dist/index.d.ts +39 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -11
- package/dist/index.js.map +1 -1
- package/package.json +19 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# @usebutr/core
|
|
2
|
+
|
|
3
|
+
## 2.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#179](https://github.com/pedroapfilho/usebutr/pull/179) [`bc5b58c`](https://github.com/pedroapfilho/usebutr/commit/bc5b58cd87601be38dbb77a14e16eaaa36e8f012) Thanks [@pedroapfilho](https://github.com/pedroapfilho)! - Include package READMEs, MIT licenses, and documentation and issue links on npm.
|
|
8
|
+
|
|
9
|
+
## 2.0.0
|
|
10
|
+
|
|
11
|
+
### Major Changes
|
|
12
|
+
|
|
13
|
+
- 9b1caa2: Correctness pass across the storage, hydration and connector layers. Several of
|
|
14
|
+
these change observable behaviour; the ones worth knowing about before upgrading:
|
|
15
|
+
|
|
16
|
+
**Breaking**
|
|
17
|
+
|
|
18
|
+
- `SuiWallet.signTransaction` now returns `{ bytes, signature }` instead of
|
|
19
|
+
`Uint8Array`. Sui's `executeTransactionBlock` needs both, and each connector
|
|
20
|
+
previously returned a different half, so the old value could not be broadcast
|
|
21
|
+
and a consumer could not tell which half they held. SVM and Bitcoin keep their
|
|
22
|
+
single-`Uint8Array` shape.
|
|
23
|
+
- `@usebutr/svm`'s `sendTx` returns the signature base58-encoded, matching the
|
|
24
|
+
WalletConnect namespace, the Ledger app, Solana explorers and
|
|
25
|
+
`getSignatureStatuses`. It previously returned base64.
|
|
26
|
+
- `@usebutr/sui`'s feature input types drop the `string` arm from
|
|
27
|
+
`transaction`; wallets only ever accepted the `toJSON()` form. Strings and BCS
|
|
28
|
+
bytes are now wrapped for you, so `sendTx` accepts strictly more than before.
|
|
29
|
+
|
|
30
|
+
**Behaviour fixes**
|
|
31
|
+
|
|
32
|
+
- `WalletStorage.setPool` and `removePoolEntry` could self-deadlock on a corrupt
|
|
33
|
+
pool payload, leaving `connectWallet` unresolved and every later pool write
|
|
34
|
+
jammed for the page's life. Both are fixed, and `readWalletSnapshot` now shares
|
|
35
|
+
one codec with `WalletStorage` so the server and client decodes cannot drift.
|
|
36
|
+
- A seeded (SSR) entry whose silent reconnect failed used to stay in the pool
|
|
37
|
+
backed by a placeholder connector forever, so `useSigner`/`useBalance`
|
|
38
|
+
reported an error and `useConnectionStatus` reported `"reconnecting"`
|
|
39
|
+
permanently. Those entries are now dropped.
|
|
40
|
+
- `useSigner` and `useBalance` stay `idle` for a wallet that is still
|
|
41
|
+
reconnecting instead of surfacing a placeholder rejection as `status: "error"`.
|
|
42
|
+
- `useConnectionStatus` lets a live `"connecting"`/`"error"` take precedence over
|
|
43
|
+
the derived `"reconnecting"`, so an in-flight attempt and a connection error
|
|
44
|
+
are no longer hidden. New `useIsReconnecting(connectorId?)` answers the
|
|
45
|
+
per-wallet question directly.
|
|
46
|
+
- A background restore no longer writes the connect-attempt status or steals
|
|
47
|
+
`activeConnectorId`, and a superseded `CONNECT_FAILED` no longer overwrites the
|
|
48
|
+
current attempt.
|
|
49
|
+
- An externally-disconnected connector is now torn down, not just dropped from
|
|
50
|
+
the pool, so a cached adapter is not reused while still holding a session.
|
|
51
|
+
- EVM: a malformed provider response is treated as absent rather than `""`, which
|
|
52
|
+
previously produced chain `eip155:0`, zero-length signatures, empty transaction
|
|
53
|
+
hashes and a confident `0 ETH`. `switchChain` gained the same-chain
|
|
54
|
+
short-circuit `sendTxToChain` already had.
|
|
55
|
+
- WalletConnect: accounts carry their own chain instead of all being stamped with
|
|
56
|
+
the active one, so a multi-chain session no longer returns a wrong-chain
|
|
57
|
+
address. One pairing now covers every configured namespace, the pairing URI
|
|
58
|
+
survives a reconnect, and concurrent connects share one pairing.
|
|
59
|
+
- Bitcoin: the sats-connect (Xverse) adapter honours `silent`, so a reload no
|
|
60
|
+
longer triggers an unsolicited approval prompt, and exposes the payment address
|
|
61
|
+
as its single account instead of also presenting the ordinals address as
|
|
62
|
+
spendable.
|
|
63
|
+
- Polkadot: the injected adapter actually delivers events to subscribers,
|
|
64
|
+
`switchChain` notifies like its Wallet Standard sibling, and chain resolution
|
|
65
|
+
prefers the mainnets rather than whatever the wallet listed first.
|
|
66
|
+
- Ledger: the device session is committed atomically, so a locked device no
|
|
67
|
+
longer leaves an open transport that reports itself connected, and concurrent
|
|
68
|
+
connects open one transport.
|
|
69
|
+
- SVM: `sendTxToChain` submits to the chain you asked for instead of the
|
|
70
|
+
adapter's current one, and rejects a chain the wallet does not advertise.
|
|
71
|
+
- `@usebutr/svm`'s `switchChain` capability now counts only `solana:` chains, so
|
|
72
|
+
a multi-namespace wallet no longer advertises a method that always throws.
|
|
73
|
+
|
|
74
|
+
**Testing**
|
|
75
|
+
|
|
76
|
+
- `createFakePersistence` is now the real `WalletStorage` over memory drivers
|
|
77
|
+
rather than a parallel implementation, so it inherits upsert semantics,
|
|
78
|
+
validation and JSON round-tripping. Two divergences are fixed as a result:
|
|
79
|
+
`setPool` upserts rather than replaces, and `clearAll` leaves the
|
|
80
|
+
user-disconnected flag alone.
|
|
81
|
+
- `createFakeConnectedWallet` rejects being given both an `adapter` and explicit
|
|
82
|
+
`addresses`/`accounts`, a combination whose halves could disagree.
|
|
83
|
+
|
|
84
|
+
## 1.1.0
|
|
85
|
+
|
|
86
|
+
### Minor Changes
|
|
87
|
+
|
|
88
|
+
- 8ecaf89: Close five gaps that made multi-chain integration harder than it needed to be.
|
|
89
|
+
|
|
90
|
+
**Group wallets by platform without writing the loop yourself.**
|
|
91
|
+
`groupByPlatform(items, getPlatform)` in `@usebutr/core` buckets any list into
|
|
92
|
+
a `Map<ChainPlatform, T[]>` keyed in `CHAIN_PLATFORMS` order with empty
|
|
93
|
+
platforms omitted, and `@usebutr/react` adds
|
|
94
|
+
`useDiscoveredWalletsByPlatform()` / `useConnectedWalletsByPlatform()` on top.
|
|
95
|
+
A multi-chain wallet announces one adapter per platform, so every app hitting
|
|
96
|
+
more than one chain was writing this bucketing by hand.
|
|
97
|
+
|
|
98
|
+
**`autoDiscovery` takes an allowlist array, and says something when it's empty.**
|
|
99
|
+
`autoDiscovery(["evm", "svm"])` now works alongside the object form and reads
|
|
100
|
+
as the allowlist it is. An options value that enables no platforms logs a
|
|
101
|
+
warning instead of silently discovering nothing: a list built at runtime that
|
|
102
|
+
comes back empty was otherwise indistinguishable from "no wallets installed".
|
|
103
|
+
The bare `autoDiscovery()` everything-path is unchanged and stays silent.
|
|
104
|
+
|
|
105
|
+
**`createFakeConnectedWallet` in `@usebutr/testing`.** Builds the
|
|
106
|
+
`{ account, accounts, connector }` pool entry that UI tests actually render,
|
|
107
|
+
with accounts constructed through `buildAccount` so the `<chain>:<address>` id
|
|
108
|
+
format is never restated in a fixture. Defaults to the platform's mainnet chain
|
|
109
|
+
and a deterministic address; pass `adapter` to wrap a connector you already
|
|
110
|
+
built.
|
|
111
|
+
|
|
112
|
+
**The icon sanitization contract is now on the type.** `Connector.icon` is
|
|
113
|
+
already run through `sanitizeIcon` at discovery, so it is a trimmed non-empty
|
|
114
|
+
string or `undefined`, safe to hand to `next/image` with no second call and no
|
|
115
|
+
`icon !== ""` guard. `ConnectorMeta.icon` documents the opposite: it is
|
|
116
|
+
consumer-supplied and not sanitized.
|
|
117
|
+
|
|
118
|
+
**`createSignInFlow` in `@usebutr/core`.** Wraps the nonce, capability gate,
|
|
119
|
+
signature, base64 encoding, and verification handshake that every wallet-auth
|
|
120
|
+
app writes identically. Solana wallets advertising `solana:signIn` take the
|
|
121
|
+
SIWS path automatically. It deliberately does not define a message format: pass
|
|
122
|
+
`buildMessage` to match your backend. Also re-exports the SVM SIWS types
|
|
123
|
+
(`SolanaSignInFeature`, `SolanaSignInInput`, `SolanaSignInOutput`) from
|
|
124
|
+
`@usebutr/svm`, which were defined but not exported.
|
|
125
|
+
|
|
126
|
+
## 1.0.0
|
|
127
|
+
|
|
128
|
+
### Major Changes
|
|
129
|
+
|
|
130
|
+
- f0a5116: **Breaking:** the `platform` field is gone from the `PlatformDiscoverer` type in `@usebutr/core`, and from the `evmDiscoverer`, `svmDiscoverer`, `suiDiscoverer`, `bitcoinDiscoverer` and `polkadotDiscoverer` objects that implement it. Nothing read it: the aggregator keys discoverers by `ChainPlatform` in its own registry, so the field only restated the key.
|
|
131
|
+
|
|
132
|
+
Migration: read the platform from the `KNOWN_DISCOVERERS` key in `@usebutr/wallets` (`Object.entries(KNOWN_DISCOVERERS)`), or from `adapter.chainPlatform` on a discovered adapter. Custom `PlatformDiscoverer` implementations must drop the `platform` property; keeping it is now an excess-property error.
|
|
133
|
+
|
|
134
|
+
- f0a5116: **Breaking:** the deprecated `Wallet` type alias is removed from `@usebutr/core`.
|
|
135
|
+
|
|
136
|
+
Migration: import `WalletBase` instead (`type Wallet = WalletBase` was all the alias ever was), or the per-platform surface you actually mean: `EvmWallet`, `SvmWallet`, `SuiWallet`, `BitcoinWallet`, `PolkadotWallet`.
|
|
137
|
+
|
|
138
|
+
### Minor Changes
|
|
139
|
+
|
|
140
|
+
- 7887cf0: Add `bytesToBase58` and `base58ToBytes` to the shared encoding module, alongside the existing hex and base64 helpers. Base58 was hand-rolled in eight places across the connector packages and the demo apps; a single tested implementation removes the drift surface on Solana addresses and signatures.
|
|
141
|
+
|
|
142
|
+
### Patch Changes
|
|
143
|
+
|
|
144
|
+
- 7887cf0: Split the 497-line `types/wallet.ts` into focused modules (platform, account, capabilities, connector, wallet, manager) behind the same barrel. Pure file motion: every exported name and type is unchanged.
|
|
145
|
+
|
|
146
|
+
## 0.5.0
|
|
147
|
+
|
|
148
|
+
### Minor Changes
|
|
149
|
+
|
|
150
|
+
- 4467a5e: Compare the adapter instance in `walletEqual` instead of `connector.id`, so selectors re-render when hydration swaps a shadow adapter for the live one. Previously an SSR consumer stayed pinned to the placeholder whose methods throw `ShadowConnectorError`.
|
|
151
|
+
|
|
152
|
+
`isShadowAdapter` and `ShadowConnectorError` are now exported from the package root.
|
|
153
|
+
|
|
154
|
+
## 0.4.2
|
|
155
|
+
|
|
156
|
+
### Patch Changes
|
|
157
|
+
|
|
158
|
+
- c1309ee: Validate persisted wallet data and WalletConnect responses with shared Zod schemas.
|
|
159
|
+
|
|
160
|
+
## 0.4.1
|
|
161
|
+
|
|
162
|
+
### Patch Changes
|
|
163
|
+
|
|
164
|
+
- 937dfae: Bump runtime dependency floors (`@wallet-standard/app` 1.1.1, `@ledgerhq/*` latest minors, `@walletconnect/universal-provider` 2.23.10) and modernize public type declarations from method signatures to property function types (oxlint `method-signature-style`). Type-level only — no runtime behavior change.
|
|
165
|
+
|
|
166
|
+
## 0.4.0
|
|
167
|
+
|
|
168
|
+
### Minor Changes
|
|
169
|
+
|
|
170
|
+
- b5322ae: Add shared byte-encoding utilities (`bytesToHex`, `bytesToHexPrefixed`,
|
|
171
|
+
`hexToBytes`, `base64ToBytes`, `bytesToBase64`) and consolidate the per-connector
|
|
172
|
+
copies onto them. Behavior preserved: prefixed (`0x`) and bare hex are distinct
|
|
173
|
+
variants so each chain keeps its existing output.
|
|
174
|
+
|
|
175
|
+
### Patch Changes
|
|
176
|
+
|
|
177
|
+
- d5f32c7: Fix Polkadot wallet connections failing to persist and reconnect on reload.
|
|
178
|
+
The storage validators' chain-platform allowlist was missing `polkadot`, so
|
|
179
|
+
Polkadot pool entries were rejected on write — and because the write rejects
|
|
180
|
+
the whole batch, a co-connected sibling (e.g. Solana) could be dropped too.
|
|
181
|
+
The allowlist is now derived from a single `CHAIN_PLATFORMS` source of truth
|
|
182
|
+
shared with the `ChainPlatform` type, so the runtime checks can't drift from
|
|
183
|
+
the type again.
|
|
184
|
+
- a46eecd: Ship unminified ESM so downstream bundlers (Vite/esbuild dep pre-bundling) process the package correctly; fixes a ReferenceError in consumer dev servers. The consuming app minifies once at its own build.
|
|
185
|
+
|
|
186
|
+
## 0.3.0
|
|
187
|
+
|
|
188
|
+
### Minor Changes
|
|
189
|
+
|
|
190
|
+
- 886ee1d: Add Polkadot/Substrate support. New `@usebutr/polkadot` package discovers wallets via injectedWeb3 (polkadot-js, Talisman, SubWallet, Nova, Enkrypt) with a Wallet Standard `polkadot:*` fallback. `ChainPlatform` widens to include `"polkadot"`; `autoDiscovery({ polkadot: true })` and `CHAINS_BY_PLATFORM` now cover it. Message signing works via the injected `signer.signRaw`; transaction signing is delegated to the consumer through `getSigner()` (e.g. polkadot-api), matching butr's no-RPC posture.
|
|
191
|
+
|
|
192
|
+
## 0.2.2
|
|
193
|
+
|
|
194
|
+
### Patch Changes
|
|
195
|
+
|
|
196
|
+
- db5d7e9: Fix intermittent wallet disconnect on page reload. Two storage-write bugs caused a remembered connection to be erased:
|
|
197
|
+
|
|
198
|
+
- An external `disconnected` event (EIP-1193 emits `accountsChanged: []`) fired on a simple wallet **auto-lock**, not just on permission revocation — and the store persisted the resulting empty pool, wiping the saved connection on every lock. The store now mirrors the disconnect into reducer state (so the UI hides the wallet) but leaves storage untouched; the next hydrate retries and self-heals once the wallet is unlocked. Explicit `disconnectWallet` still evicts via `removePoolEntry`.
|
|
199
|
+
- A transient `eth_accounts: []` during eager restore (a locked wallet) was treated as a permanent failure and the storage entry was deleted. Hydration now preserves storage on a failed restore and reports it as `dropped` for telemetry only, so a reload retries.
|
|
200
|
+
|
|
201
|
+
Additionally, `WalletStorage.setPool` is now **additive** and serialized through an internal mutation queue, so concurrent fire-and-forget writes can't interleave their read-modify-write phases and clobber each other's entries. `connectWallet` / `disconnectWallet` now await their storage writes so callers can trust persistence has landed on the next line.
|
|
202
|
+
|
|
203
|
+
## 0.2.1
|
|
204
|
+
|
|
205
|
+
### Patch Changes
|
|
206
|
+
|
|
207
|
+
- f846e77: Wallet-announced icons are trimmed of surrounding whitespace on ingestion. Some wallets ship data-URI icons with a leading newline, which strict consumers reject — Next.js's `<Image>` throws because `src` must not start with a control character. `@usebutr/core` exports a `sanitizeIcon` helper; the EIP-6963 and Wallet Standard adapters apply it, and an all-whitespace icon now resolves to `undefined` rather than a blank string.
|
|
208
|
+
|
|
209
|
+
## 0.2.0
|
|
210
|
+
|
|
211
|
+
### Minor Changes
|
|
212
|
+
|
|
213
|
+
- b77a477: Persisted pool entries now require the `accounts` field. Entries written by older versions without it are dropped on read with a warning.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pedro Filho
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# @usebutr/core
|
|
2
|
+
|
|
3
|
+
Core types, store, storage, and discovery seam for butr. No React, no protocols.
|
|
4
|
+
|
|
5
|
+
Part of [butr](https://www.usebutr.com), a multi-chain wallet discovery and
|
|
6
|
+
connection-state library. Your application owns the picker UI and chain client.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @usebutr/core zustand
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The store works outside React. Add a discovery source or your own connector factory when wiring real wallets.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { createWalletStore } from "@usebutr/core";
|
|
20
|
+
|
|
21
|
+
export const store = createWalletStore({
|
|
22
|
+
connectors: [],
|
|
23
|
+
createConnector: () => null,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Read state from a non-React host.
|
|
27
|
+
const wallets = store.getState().pool;
|
|
28
|
+
console.log(wallets.size);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Documentation
|
|
32
|
+
|
|
33
|
+
- [Package reference](https://docs.usebutr.com/api/core)
|
|
34
|
+
- [Getting started](https://docs.usebutr.com/getting-started/quickstart)
|
|
35
|
+
- [Examples and source](https://github.com/pedroapfilho/usebutr)
|
|
36
|
+
- [Report an issue](https://github.com/pedroapfilho/usebutr/issues)
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
[MIT](./LICENSE), copyright 2026 Pedro Filho.
|
package/dist/index.d.ts
CHANGED
|
@@ -99,7 +99,13 @@ type ChainsByPlatform = Readonly<Record<ChainPlatform, ReadonlyArray<ChainBase>>
|
|
|
99
99
|
* chain registries out of its bundle. Apps that want all of them import
|
|
100
100
|
* `CHAINS_BY_PLATFORM` from `@usebutr/wallets`.
|
|
101
101
|
*/
|
|
102
|
-
declare const buildChainsByPlatform: (partial: Partial<ChainsByPlatform>) =>
|
|
102
|
+
declare const buildChainsByPlatform: (partial: Partial<ChainsByPlatform>) => {
|
|
103
|
+
bitcoin: readonly ChainBase[];
|
|
104
|
+
evm: readonly ChainBase[];
|
|
105
|
+
polkadot: readonly ChainBase[];
|
|
106
|
+
sui: readonly ChainBase[];
|
|
107
|
+
svm: readonly ChainBase[];
|
|
108
|
+
};
|
|
103
109
|
//#endregion
|
|
104
110
|
//#region src/types/connector.d.ts
|
|
105
111
|
/**
|
|
@@ -188,6 +194,17 @@ type ConnectorMeta = {
|
|
|
188
194
|
};
|
|
189
195
|
//#endregion
|
|
190
196
|
//#region src/types/wallet.d.ts
|
|
197
|
+
type SignInInput = {
|
|
198
|
+
readonly [key: string]: SignInValue;
|
|
199
|
+
};
|
|
200
|
+
type SignInValue = boolean | number | string | null | ReadonlyArray<SignInValue> | SignInInput;
|
|
201
|
+
type TransactionObject = {
|
|
202
|
+
readonly [key: string]: TransactionValue | undefined;
|
|
203
|
+
};
|
|
204
|
+
type TransactionMethod = (...args: ReadonlyArray<never>) => Promise<string>;
|
|
205
|
+
type TransactionValue = bigint | boolean | number | string | null | Uint8Array | ReadonlyArray<TransactionValue> | TransactionObject | TransactionMethod;
|
|
206
|
+
type TransactionInput = TransactionObject | string | Uint8Array;
|
|
207
|
+
type WalletSigner = object;
|
|
191
208
|
/**
|
|
192
209
|
* Methods every connected wallet supports regardless of chain. The
|
|
193
210
|
* per-platform `Wallet` types extend this with their platform-specific
|
|
@@ -201,7 +218,7 @@ type WalletBase = {
|
|
|
201
218
|
/** Returns a chain-specific signer. Consumers cast to the concrete
|
|
202
219
|
* type via the `SignerForPlatform` registry (or directly to the
|
|
203
220
|
* library shape they wrap: `WalletClient` on viem, etc.). */
|
|
204
|
-
getSigner: () => Promise<
|
|
221
|
+
getSigner: () => Promise<WalletSigner>;
|
|
205
222
|
/** Look up the status of a previously-submitted transaction. */
|
|
206
223
|
getTransactionReceipt: (tx: string) => Promise<{
|
|
207
224
|
status: "Success" | "Error" | "Pending";
|
|
@@ -209,12 +226,12 @@ type WalletBase = {
|
|
|
209
226
|
/** `account` routes through a specific exposed address (EVM via
|
|
210
227
|
* `tx.from`, Wallet Standard via the feature's `account` input);
|
|
211
228
|
* omitting it lets the wallet pick. */
|
|
212
|
-
sendTx: (tx:
|
|
229
|
+
sendTx: (tx: TransactionInput, account?: Account) => Promise<string>;
|
|
213
230
|
/** Submit a transaction targeting a specific chain. The optional
|
|
214
231
|
* callback fires after the connector has switched chain (consumers
|
|
215
232
|
* use this to re-enable UI). Pass an `account` to route through a
|
|
216
233
|
* specific exposed address (see `sendTx`). */
|
|
217
|
-
sendTxToChain: (tx:
|
|
234
|
+
sendTxToChain: (tx: TransactionInput, targetChainId: string, account?: Account, cb?: () => void) => Promise<string>;
|
|
218
235
|
/**
|
|
219
236
|
* Verify against `signedMessage`, not the input: Solana Wallet
|
|
220
237
|
* Standard wallets may prefix or re-encode it. `account` signs with a
|
|
@@ -247,7 +264,7 @@ type SvmWallet = WalletBase & {
|
|
|
247
264
|
* consumer can verify server-side. `input` is the SIWS message fields
|
|
248
265
|
* (domain, statement, nonce, …); pass `{}` or omit for wallet
|
|
249
266
|
* defaults. */
|
|
250
|
-
signIn?: (input?:
|
|
267
|
+
signIn?: (input?: SignInInput) => Promise<{
|
|
251
268
|
account: Account;
|
|
252
269
|
signature: Uint8Array;
|
|
253
270
|
signedMessage: Uint8Array;
|
|
@@ -255,7 +272,7 @@ type SvmWallet = WalletBase & {
|
|
|
255
272
|
/** Sign a Solana transaction WITHOUT broadcasting it. butr ships no
|
|
256
273
|
* RPC, so the consumer broadcasts the returned bytes via
|
|
257
274
|
* `@solana/kit` / `@solana/web3.js` / etc. */
|
|
258
|
-
signTransaction?: (tx:
|
|
275
|
+
signTransaction?: (tx: TransactionInput, account?: Account) => Promise<Uint8Array>;
|
|
259
276
|
};
|
|
260
277
|
/**
|
|
261
278
|
* Sui wallet surface. Adds optional `signTransaction` for the
|
|
@@ -267,7 +284,7 @@ type SuiWallet = WalletBase & {
|
|
|
267
284
|
* chain requires: `SuiClient.executeTransactionBlock` needs
|
|
268
285
|
* `{ transactionBlock, signature }`, so a bare `Uint8Array` cannot express
|
|
269
286
|
* the result and a consumer holding one cannot tell which half they have. */
|
|
270
|
-
signTransaction?: (tx:
|
|
287
|
+
signTransaction?: (tx: TransactionInput, account?: Account) => Promise<{
|
|
271
288
|
bytes: Uint8Array;
|
|
272
289
|
signature: Uint8Array;
|
|
273
290
|
}>;
|
|
@@ -278,7 +295,7 @@ type SuiWallet = WalletBase & {
|
|
|
278
295
|
* your own Esplora or Electrum client.
|
|
279
296
|
*/
|
|
280
297
|
type BitcoinWallet = WalletBase & {
|
|
281
|
-
signTransaction?: (tx:
|
|
298
|
+
signTransaction?: (tx: TransactionInput, account?: Account) => Promise<Uint8Array>;
|
|
282
299
|
};
|
|
283
300
|
/**
|
|
284
301
|
* No standalone `signTransaction`: building an extrinsic needs chain
|
|
@@ -358,17 +375,21 @@ type ConnectionError = {
|
|
|
358
375
|
kind: "Timeout";
|
|
359
376
|
message: string;
|
|
360
377
|
} | {
|
|
361
|
-
cause?:
|
|
378
|
+
cause?: ErrorCause;
|
|
362
379
|
kind: "Unknown";
|
|
363
380
|
message: string;
|
|
364
381
|
};
|
|
365
382
|
type ConnectionErrorKind = ConnectionError["kind"];
|
|
383
|
+
type ErrorCause = Error | string;
|
|
384
|
+
type CodedError = Error & {
|
|
385
|
+
code: number | string;
|
|
386
|
+
};
|
|
366
387
|
/**
|
|
367
388
|
* EIP-1193 codes: `4001` rejected, `-32002` pending, `4100`/`4900`/`4901`
|
|
368
389
|
* unauthorized or disconnected. Message-substring matching is the last
|
|
369
390
|
* resort for SDKs that ship no codes at all.
|
|
370
391
|
*/
|
|
371
|
-
declare const mapConnectionError: (raw:
|
|
392
|
+
declare const mapConnectionError: (raw: ErrorCause) => ConnectionError;
|
|
372
393
|
//#endregion
|
|
373
394
|
//#region src/storage/persistence.d.ts
|
|
374
395
|
type MaybePromise<T> = T | Promise<T>;
|
|
@@ -452,7 +473,7 @@ declare const readWalletSnapshot: (source: CookieSource, options?: SnapshotOptio
|
|
|
452
473
|
type HydrationOutcome = {
|
|
453
474
|
dropped: Array<{
|
|
454
475
|
connectorId: string;
|
|
455
|
-
reason:
|
|
476
|
+
reason: ErrorCause;
|
|
456
477
|
}>;
|
|
457
478
|
pendingIds: Array<string>;
|
|
458
479
|
restoredIds: Array<string>;
|
|
@@ -493,7 +514,7 @@ type WalletManagerConfig = {
|
|
|
493
514
|
* cross-tab conflict) never breaks reducer state, it only surfaces
|
|
494
515
|
* here. Defaults to `console.warn`.
|
|
495
516
|
*/
|
|
496
|
-
onStorageError?: (error:
|
|
517
|
+
onStorageError?: (error: ErrorCause, context: string) => void;
|
|
497
518
|
/** Threshold for `onSlowConnect`, in milliseconds. Defaults to 5_000. */
|
|
498
519
|
slowConnectThresholdMs?: number;
|
|
499
520
|
/** Optional custom persistence implementation (e.g., cookie-backed) */
|
|
@@ -557,7 +578,7 @@ type State = {
|
|
|
557
578
|
* on `capabilities.*` (all `false` here) or `reconnectingIds`, before
|
|
558
579
|
* silent reconnect swapped in the live adapter.
|
|
559
580
|
*/
|
|
560
|
-
declare class ShadowConnectorError extends Error {
|
|
581
|
+
declare class ShadowConnectorError extends Error implements CodedError {
|
|
561
582
|
readonly code = "BUTR_RECONNECTING";
|
|
562
583
|
readonly connectorId: string;
|
|
563
584
|
readonly method: string;
|
|
@@ -758,6 +779,9 @@ type SignInFlowOptions = {
|
|
|
758
779
|
/** Hand the signed result to your backend. Throw to fail the flow. */
|
|
759
780
|
verify: (result: SignInResult) => Promise<void>;
|
|
760
781
|
};
|
|
782
|
+
type SignInFlow = {
|
|
783
|
+
signIn: (wallet: ConnectedWallet, account?: Account) => Promise<SignInResult>;
|
|
784
|
+
};
|
|
761
785
|
/** Thrown before any wallet interaction when the wallet can't sign at
|
|
762
786
|
* all. Distinct from a rejection: nothing was asked of the user, so UI
|
|
763
787
|
* should say "this wallet can't sign in" rather than "you declined". */
|
|
@@ -770,9 +794,7 @@ declare class SignInUnsupportedError extends Error {
|
|
|
770
794
|
* `result.signedMessage` holds the wallet-composed statement and
|
|
771
795
|
* `result.message` is absent. `preferSignMessage` opts out.
|
|
772
796
|
*/
|
|
773
|
-
declare const createSignInFlow: (options: SignInFlowOptions) =>
|
|
774
|
-
signIn: (wallet: ConnectedWallet, account?: Account) => Promise<SignInResult>;
|
|
775
|
-
};
|
|
797
|
+
declare const createSignInFlow: (options: SignInFlowOptions) => SignInFlow;
|
|
776
798
|
//#endregion
|
|
777
799
|
//#region src/wallet-equal.d.ts
|
|
778
800
|
/**
|
|
@@ -827,5 +849,5 @@ declare const bytesToBase58: (bytes: Uint8Array) => string;
|
|
|
827
849
|
* rather than silently dropping them. */
|
|
828
850
|
declare const base58ToBytes: (input: string) => Uint8Array;
|
|
829
851
|
//#endregion
|
|
830
|
-
export { type Account, type Balance, type BitcoinAdapter, type BitcoinWallet, type BrowserStorageDrivers, CHAIN_PLATFORMS, type ChainBase, type ChainPlatform, type ChainsByPlatform, type ConnectedWallet, type ConnectionError, type ConnectionErrorKind, type ConnectionStatus, type Connector, type ConnectorEvent, type ConnectorMeta, type CookieDriverOptions, type CookieSource, EMPTY_SNAPSHOT, type EvmAdapter, type EvmWallet, type HydrationOutcome, type InitialCookies, type MaybePromise, type PlatformDiscoverer, type PolkadotAdapter, type PolkadotWallet, ShadowConnectorError, type SignInFlowOptions, type SignInMessageContext, type SignInResult, SignInUnsupportedError, type SignerForPlatform, type SignerOf, type SnapshotOptions, type StorageDriver, type StoredPoolEntry, type StoredPoolRecord, type StoredSelectionRecord, type SuiAdapter, type SuiWallet, type SvmAdapter, type SvmWallet, type WalletAdapter, type WalletAvailability, type WalletBase, type WalletCapabilities, type WalletManagerConfig, type WalletPersistence, type WalletSnapshot, type WalletSource, WalletStorage, type WalletStore, type WalletStoreState, base58ToBytes, base64ToBytes, buildAccount, buildChainsByPlatform, bytesToBase58, bytesToBase64, bytesToHex, bytesToHexPrefixed, createBrowserStorageDriver, createCookieStorageDriver, createMemoryStorageDriver, createSignInFlow, createWalletSource, createWalletStore, groupByPlatform, hexToBytes, isShadowAdapter, logError, logWarn, mapConnectionError, readWalletSnapshot, sanitizeIcon, walletEqual };
|
|
852
|
+
export { type Account, type Balance, type BitcoinAdapter, type BitcoinWallet, type BrowserStorageDrivers, CHAIN_PLATFORMS, type ChainBase, type ChainPlatform, type ChainsByPlatform, type ConnectedWallet, type ConnectionError, type ConnectionErrorKind, type ConnectionStatus, type Connector, type ConnectorEvent, type ConnectorMeta, type CookieDriverOptions, type CookieSource, EMPTY_SNAPSHOT, type EvmAdapter, type EvmWallet, type HydrationOutcome, type InitialCookies, type MaybePromise, type PlatformDiscoverer, type PolkadotAdapter, type PolkadotWallet, ShadowConnectorError, type SignInFlowOptions, type SignInInput, type SignInMessageContext, type SignInResult, SignInUnsupportedError, type SignInValue, type SignerForPlatform, type SignerOf, type SnapshotOptions, type StorageDriver, type StoredPoolEntry, type StoredPoolRecord, type StoredSelectionRecord, type SuiAdapter, type SuiWallet, type SvmAdapter, type SvmWallet, type TransactionInput, type TransactionMethod, type TransactionObject, type TransactionValue, type WalletAdapter, type WalletAvailability, type WalletBase, type WalletCapabilities, type WalletManagerConfig, type WalletPersistence, type WalletSigner, type WalletSnapshot, type WalletSource, WalletStorage, type WalletStore, type WalletStoreState, base58ToBytes, base64ToBytes, buildAccount, buildChainsByPlatform, bytesToBase58, bytesToBase64, bytesToHex, bytesToHexPrefixed, createBrowserStorageDriver, createCookieStorageDriver, createMemoryStorageDriver, createSignInFlow, createWalletSource, createWalletStore, groupByPlatform, hexToBytes, isShadowAdapter, logError, logWarn, mapConnectionError, readWalletSnapshot, sanitizeIcon, walletEqual };
|
|
831
853
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/chain.ts","../src/types/account.ts","../src/types/capabilities.ts","../src/types/platform.ts","../src/types/chains-by-platform.ts","../src/types/connector.ts","../src/types/wallet.ts","../src/types/discoverer.ts","../src/types/errors.ts","../src/storage/persistence.ts","../src/storage/snapshot.ts","../src/types/manager.ts","../src/types/signer.ts","../src/wallet-source.ts","../src/store/reducer.ts","../src/store/shadow-adapter.ts","../src/storage/browser-storage-driver.ts","../src/storage/cookie-storage-driver.ts","../src/storage/wallet-storage.ts","../src/store/wallet-store.ts","../src/group-by-platform.ts","../src/sign-in/sign-in-flow.ts","../src/wallet-equal.ts","../src/logger.ts","../src/sanitize-icon.ts","../src/encoding/bytes.ts"],"mappings":";;;;;KAIK;;EAEH;;EAEA;;EAEA;;EAEA;;;;KCVG;EACH,OAAO;EACP;EACA;;;;;;;cAQI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/chain.ts","../src/types/account.ts","../src/types/capabilities.ts","../src/types/platform.ts","../src/types/chains-by-platform.ts","../src/types/connector.ts","../src/types/wallet.ts","../src/types/discoverer.ts","../src/types/errors.ts","../src/storage/persistence.ts","../src/storage/snapshot.ts","../src/types/manager.ts","../src/types/signer.ts","../src/wallet-source.ts","../src/store/reducer.ts","../src/store/shadow-adapter.ts","../src/storage/browser-storage-driver.ts","../src/storage/cookie-storage-driver.ts","../src/storage/wallet-storage.ts","../src/store/wallet-store.ts","../src/group-by-platform.ts","../src/sign-in/sign-in-flow.ts","../src/wallet-equal.ts","../src/logger.ts","../src/sanitize-icon.ts","../src/encoding/bytes.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,8 @@ const buildChainsByPlatform = (partial) => ({
|
|
|
30
30
|
|
|
31
31
|
//#endregion
|
|
32
32
|
//#region src/types/errors.ts
|
|
33
|
+
const isCodedError = (error) => "code" in error;
|
|
34
|
+
const toErrorCause = (value) => value;
|
|
33
35
|
/**
|
|
34
36
|
* EIP-1193 codes: `4001` rejected, `-32002` pending, `4100`/`4900`/`4901`
|
|
35
37
|
* unauthorized or disconnected. Message-substring matching is the last
|
|
@@ -47,7 +49,7 @@ const mapConnectionError = (raw) => {
|
|
|
47
49
|
kind: "NotConnected",
|
|
48
50
|
message
|
|
49
51
|
};
|
|
50
|
-
const code =
|
|
52
|
+
const code = isCodedError(raw) ? raw.code : void 0;
|
|
51
53
|
if (code === 4001) return {
|
|
52
54
|
kind: "UserRejected",
|
|
53
55
|
message
|
|
@@ -191,7 +193,7 @@ const createShadowAdapter = (entry) => {
|
|
|
191
193
|
};
|
|
192
194
|
default:
|
|
193
195
|
entry.chainPlatform;
|
|
194
|
-
throw new Error(`[butr] unknown chainPlatform: ${entry.chainPlatform}`);
|
|
196
|
+
throw new Error(`[butr] unknown chainPlatform: ${String(entry.chainPlatform)}`);
|
|
195
197
|
}
|
|
196
198
|
};
|
|
197
199
|
/**
|
|
@@ -216,7 +218,7 @@ const logError = (...args) => {
|
|
|
216
218
|
//#region src/storage/browser-storage-driver.ts
|
|
217
219
|
const hasWebStorage = (kind) => {
|
|
218
220
|
try {
|
|
219
|
-
return
|
|
221
|
+
return kind === "localStorage" ? globalThis.localStorage !== void 0 : globalThis.sessionStorage !== void 0;
|
|
220
222
|
} catch {
|
|
221
223
|
return false;
|
|
222
224
|
}
|
|
@@ -329,7 +331,8 @@ const decodePool = (raw, label = "[butr]") => {
|
|
|
329
331
|
if (!parsed.success) return {};
|
|
330
332
|
const result = {};
|
|
331
333
|
for (const [key, entryValue] of Object.entries(parsed.data)) {
|
|
332
|
-
const
|
|
334
|
+
const candidate = storedPoolEntrySchema.safeParse(entryValue);
|
|
335
|
+
const entry = candidate.success ? parseStoredPoolEntry(key, candidate.data) : null;
|
|
333
336
|
if (entry === null) logWarn(`${label} dropping invalid pool entry for ${key}`);
|
|
334
337
|
else result[key] = entry;
|
|
335
338
|
}
|
|
@@ -611,7 +614,7 @@ const restoreOneEntry = async (connectorId, entry, connector) => {
|
|
|
611
614
|
} catch (error) {
|
|
612
615
|
return {
|
|
613
616
|
connectorId,
|
|
614
|
-
error,
|
|
617
|
+
error: toErrorCause(error instanceof Error ? error : String(error)),
|
|
615
618
|
kind: "fail"
|
|
616
619
|
};
|
|
617
620
|
}
|
|
@@ -822,8 +825,8 @@ const reducer = (state, event) => {
|
|
|
822
825
|
if (event.active) nextAccount = event.active;
|
|
823
826
|
else nextAccount = event.accounts.some((a) => a.walletAddress === wallet.account.walletAddress && a.chain.id === wallet.account.chain.id) ? wallet.account : event.accounts[0] ?? wallet.account;
|
|
824
827
|
const sameAccount = nextAccount.walletAddress === wallet.account.walletAddress && nextAccount.chain.id === wallet.account.chain.id;
|
|
825
|
-
const
|
|
826
|
-
if (sameAccount &&
|
|
828
|
+
const hasSameAccounts = event.accounts.length === wallet.accounts.length && event.accounts.every((a, i) => a.walletAddress === wallet.accounts[i]?.walletAddress);
|
|
829
|
+
if (sameAccount && hasSameAccounts) return state;
|
|
827
830
|
const updated = {
|
|
828
831
|
...wallet,
|
|
829
832
|
account: nextAccount,
|
|
@@ -885,7 +888,7 @@ const run = async (fn, onError) => {
|
|
|
885
888
|
try {
|
|
886
889
|
await fn();
|
|
887
890
|
} catch (error) {
|
|
888
|
-
onError(error);
|
|
891
|
+
onError(toErrorCause(error instanceof Error ? error : String(error)));
|
|
889
892
|
}
|
|
890
893
|
};
|
|
891
894
|
|
|
@@ -1021,7 +1024,7 @@ const createWalletStore = (config) => {
|
|
|
1021
1024
|
config.onConnect?.(entry);
|
|
1022
1025
|
onSuccess?.(entry);
|
|
1023
1026
|
} catch (error) {
|
|
1024
|
-
const normalised = mapConnectionError(error);
|
|
1027
|
+
const normalised = mapConnectionError(error instanceof Error ? error : String(error));
|
|
1025
1028
|
dispatch({
|
|
1026
1029
|
connectorId,
|
|
1027
1030
|
error: normalised,
|
|
@@ -1264,10 +1267,12 @@ const createCookieStorageDriver = (options = {}) => {
|
|
|
1264
1267
|
|
|
1265
1268
|
//#endregion
|
|
1266
1269
|
//#region src/storage/snapshot.ts
|
|
1270
|
+
const EMPTY_POOL = Object.freeze({});
|
|
1271
|
+
const EMPTY_SELECTION = Object.freeze({});
|
|
1267
1272
|
const EMPTY_SNAPSHOT = Object.freeze({
|
|
1268
1273
|
activeConnectorId: null,
|
|
1269
|
-
pool:
|
|
1270
|
-
selection:
|
|
1274
|
+
pool: EMPTY_POOL,
|
|
1275
|
+
selection: EMPTY_SELECTION
|
|
1271
1276
|
});
|
|
1272
1277
|
const toCookieMap = (input) => {
|
|
1273
1278
|
if (!(Symbol.iterator in input)) return new Map(Object.entries(input));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["VALID_CHAIN_PLATFORMS","isChainPlatform","toCookieMap"],"sources":["../src/types/account.ts","../src/types/chains-by-platform.ts","../src/types/errors.ts","../src/types/platform.ts","../src/wallet-source.ts","../src/store/shadow-adapter.ts","../src/logger.ts","../src/storage/browser-storage-driver.ts","../src/storage/validation.ts","../src/storage/wallet-storage.ts","../src/store/connector-lifecycle.ts","../src/store/hydration.ts","../src/store/reducer.ts","../src/store/wallet-store-helpers.ts","../src/store/wallet-store.ts","../src/storage/cookie-storage-driver.ts","../src/storage/snapshot.ts","../src/group-by-platform.ts","../src/encoding/bytes.ts","../src/sign-in/sign-in-flow.ts","../src/wallet-equal.ts","../src/sanitize-icon.ts"],"sourcesContent":["import type { ChainBase } from \"./chain\";\n\ntype Account = {\n chain: ChainBase;\n id: string;\n walletAddress: string;\n};\n\n/**\n * The reducer compares accounts by the composite `<chain>:<address>`\n * id, so every adapter must build accounts here or reproduce that\n * format byte for byte.\n */\nconst buildAccount = (address: string, chain: ChainBase): Account => ({\n chain,\n id: `${chain.id}:${address}`,\n walletAddress: address,\n});\n\ntype Balance = {\n /** Token decimals (e.g. 9 for SOL, 18 for ETH) */\n decimals: number;\n /** Human-readable string, trimmed of trailing zeros */\n formatted: string;\n /** Token symbol (e.g. \"SOL\", \"ETH\") */\n symbol: string;\n /** Raw integer amount */\n value: bigint;\n};\n\nexport type { Account, Balance };\nexport { buildAccount };\n","import type { ChainBase } from \"./chain\";\nimport type { ChainPlatform } from \"./platform\";\n\n/**\n * Values come from the per-platform packages (`EVM_CHAINS_LIST`,\n * `SVM_CHAINS_LIST`, …); an empty list opts that platform out of the\n * consumer's chain UI.\n */\ntype ChainsByPlatform = Readonly<Record<ChainPlatform, ReadonlyArray<ChainBase>>>;\n\n/**\n * Naming only the platforms an app targets keeps the other packages'\n * chain registries out of its bundle. Apps that want all of them import\n * `CHAINS_BY_PLATFORM` from `@usebutr/wallets`.\n */\nconst buildChainsByPlatform = (partial: Partial<ChainsByPlatform>): ChainsByPlatform => ({\n bitcoin: partial.bitcoin ?? [],\n evm: partial.evm ?? [],\n polkadot: partial.polkadot ?? [],\n sui: partial.sui ?? [],\n svm: partial.svm ?? [],\n});\n\nexport type { ChainsByPlatform };\nexport { buildChainsByPlatform };\n","/**\n * Wallet SDKs disagree on error shape (EIP-1193 codes, bare strings,\n * bespoke classes), so consumers branch on `kind` rather than regexing\n * messages. `cause` keeps the original value for the `Unknown` case.\n */\ntype ConnectionError =\n | { kind: \"UserRejected\"; message: string }\n | { kind: \"RequestPending\"; message: string }\n | { kind: \"WalletLocked\"; message: string }\n | { actualChain?: string; expectedChain?: string; kind: \"ChainMismatch\"; message: string }\n | { kind: \"NotConnected\"; message: string }\n | { kind: \"Timeout\"; message: string }\n | { cause?: unknown; kind: \"Unknown\"; message: string };\n\ntype ConnectionErrorKind = ConnectionError[\"kind\"];\n\n/**\n * EIP-1193 codes: `4001` rejected, `-32002` pending, `4100`/`4900`/`4901`\n * unauthorized or disconnected. Message-substring matching is the last\n * resort for SDKs that ship no codes at all.\n */\nconst mapConnectionError = (raw: unknown): ConnectionError => {\n if (raw instanceof Error) {\n const message = raw.message;\n const lower = message.toLowerCase();\n\n if (message === \"Connection timeout\") {\n return { kind: \"Timeout\", message };\n }\n if (message === \"Failed to get account\" || lower.includes(\"not connected\")) {\n return { kind: \"NotConnected\", message };\n }\n\n const code = \"code\" in raw ? raw.code : undefined;\n if (code === 4001) {\n return { kind: \"UserRejected\", message };\n }\n if (code === -32_002) {\n return { kind: \"RequestPending\", message };\n }\n if (code === 4100 || code === 4900 || code === 4901) {\n return { kind: \"NotConnected\", message };\n }\n\n if (lower.includes(\"user rejected\") || lower.includes(\"user denied\")) {\n return { kind: \"UserRejected\", message };\n }\n if (lower.includes(\"locked\")) {\n return { kind: \"WalletLocked\", message };\n }\n if (lower.includes(\"chain\") && (lower.includes(\"mismatch\") || lower.includes(\"unsupported\"))) {\n return { kind: \"ChainMismatch\", message };\n }\n\n return { cause: raw, kind: \"Unknown\", message };\n }\n\n if (typeof raw === \"string\") {\n return { kind: \"Unknown\", message: raw };\n }\n\n return { cause: raw, kind: \"Unknown\", message: \"Connection failed\" };\n};\n\nexport type { ConnectionError, ConnectionErrorKind };\nexport { mapConnectionError };\n","/**\n * Single runtime source of truth: `ChainPlatform` and the storage\n * validators' allowlists both derive from it. Omitting a platform here\n * silently stops its connections from persisting.\n */\nconst CHAIN_PLATFORMS = [\"evm\", \"svm\", \"sui\", \"bitcoin\", \"polkadot\"] as const;\n\ntype ChainPlatform = (typeof CHAIN_PLATFORMS)[number];\n\nexport type { ChainPlatform };\nexport { CHAIN_PLATFORMS };\n","import type { WalletAdapter } from \"./types\";\n\n/**\n * The discovery seam: implementable by third parties without depending\n * on `@usebutr/wallets`, which itself just composes the per-platform\n * sources into one.\n */\ntype WalletSource = {\n subscribe: (onAdapter: (adapter: WalletAdapter) => void) => () => void;\n};\n\n/**\n * Takes the exact shape of `discoverEvmAdapters` and friends, so a\n * single-platform app keeps `@usebutr/wallets` out of its bundle.\n */\nconst createWalletSource = (\n subscribe: (onAdapter: (adapter: WalletAdapter) => void) => () => void,\n): WalletSource => ({ subscribe });\n\nexport type { WalletSource };\nexport { createWalletSource };\n","import type { StoredPoolEntry } from \"../storage/persistence\";\nimport type { WalletAdapter, WalletCapabilities } from \"../types\";\n\n/**\n * Loud failure for consumers that called a wallet method without gating\n * on `capabilities.*` (all `false` here) or `reconnectingIds`, before\n * silent reconnect swapped in the live adapter.\n */\nclass ShadowConnectorError extends Error {\n readonly code = \"BUTR_RECONNECTING\";\n readonly connectorId: string;\n readonly method: string;\n constructor(method: string, connectorId: string) {\n super(\n `[butr] ${method} called on shadow connector \"${connectorId}\". Wait for silent reconnect to complete (check reconnectingIds.has(id) before calling).`,\n );\n this.name = \"ShadowConnectorError\";\n this.connectorId = connectorId;\n this.method = method;\n }\n}\n\nconst ALL_FALSE_CAPABILITIES: WalletCapabilities = Object.freeze({\n getBalance: false,\n getTransactionReceipt: false,\n requestAccounts: false,\n sendTransaction: false,\n signIn: false,\n signMessage: false,\n signTransaction: false,\n subscribe: false,\n switchAccount: false,\n switchChain: false,\n});\n\n/**\n * Lets `createWalletStore` flip `isHydrated` synchronously from\n * `initialState`; the hydration coordinator later swaps each shadow for\n * a live adapter, or drops the entry from pool and storage.\n */\nconst createShadowAdapter = (entry: StoredPoolEntry): WalletAdapter => {\n const id = entry.connectorId;\n const name = entry.name;\n const icon = entry.icon;\n\n const reject = (method: string): Promise<never> =>\n Promise.reject(new ShadowConnectorError(method, id));\n\n const base = {\n capabilities: ALL_FALSE_CAPABILITIES,\n connect: () => reject(\"connect\"),\n disconnect: () => reject(\"disconnect\"),\n getAccount: () => reject(\"getAccount\"),\n getBalance: () => reject(\"getBalance\"),\n getSigner: () => reject(\"getSigner\"),\n getTransactionReceipt: () => reject(\"getTransactionReceipt\"),\n icon,\n id,\n name,\n sendTx: () => reject(\"sendTx\"),\n sendTxToChain: () => reject(\"sendTxToChain\"),\n signMessage: () => reject(\"signMessage\"),\n switchChain: () => reject(\"switchChain\"),\n };\n\n switch (entry.chainPlatform) {\n case \"bitcoin\": {\n return { ...base, chainPlatform: \"bitcoin\" };\n }\n case \"evm\": {\n return { ...base, chainPlatform: \"evm\" };\n }\n case \"sui\": {\n return { ...base, chainPlatform: \"sui\" };\n }\n case \"svm\": {\n return { ...base, chainPlatform: \"svm\" };\n }\n case \"polkadot\": {\n return { ...base, chainPlatform: \"polkadot\" };\n }\n default: {\n const _exhaustive: never = entry.chainPlatform;\n void _exhaustive;\n throw new Error(`[butr] unknown chainPlatform: ${entry.chainPlatform as string}`);\n }\n }\n};\n\n/**\n * Structural detection: relies on every live adapter advertising at\n * least one capability, since `getBalance`, `signMessage` and\n * `switchChain` are required on all wallet surfaces.\n */\nconst isShadowAdapter = (adapter: WalletAdapter): boolean => {\n return Object.values(adapter.capabilities).every((flag) => !flag);\n};\n\nexport { createShadowAdapter, isShadowAdapter, ShadowConnectorError };\n","/* eslint-disable no-console -- central logging sink; the one sanctioned console use */\nconst logWarn = (...args: ReadonlyArray<unknown>): void => {\n console.warn(...args);\n};\n\nconst logError = (...args: ReadonlyArray<unknown>): void => {\n console.error(...args);\n};\n/* eslint-enable no-console */\n\nexport { logError, logWarn };\n","import type { StorageDriver } from \"./persistence\";\n\ntype BrowserStorageDrivers = {\n /** Survives app restart (localStorage on web, AsyncStorage/MMKV on RN). */\n persistent: StorageDriver;\n /** Cleared when the app session ends (sessionStorage on web, in-memory on RN). */\n session: StorageDriver;\n};\n\ntype WebStorageKind = \"localStorage\" | \"sessionStorage\";\n\nconst hasWebStorage = (kind: WebStorageKind): boolean => {\n try {\n return (\n typeof globalThis !== \"undefined\" &&\n (globalThis as Record<string, unknown>)[kind] !== undefined\n );\n } catch {\n return false;\n }\n};\n\nconst createMemoryStorageDriver = (): StorageDriver => {\n const memory = new Map<string, string>();\n return {\n getItem(key) {\n return memory.get(key) ?? null;\n },\n removeItem(key) {\n memory.delete(key);\n },\n setItem(key, value) {\n memory.set(key, value);\n },\n };\n};\n\nconst createWebStorageDriver = (kind: WebStorageKind): StorageDriver => {\n if (!hasWebStorage(kind)) {\n return createMemoryStorageDriver();\n }\n\n const storage = kind === \"localStorage\" ? globalThis.localStorage : globalThis.sessionStorage;\n\n return {\n getItem(key) {\n try {\n return storage.getItem(key);\n } catch {\n return null;\n }\n },\n removeItem(key) {\n try {\n storage.removeItem(key);\n } catch {\n void 0;\n }\n },\n setItem(key, value) {\n try {\n storage.setItem(key, value);\n } catch {\n void 0;\n }\n },\n };\n};\n\n/**\n * Default storage drivers for web. `persistent` wraps `localStorage`,\n * `session` wraps `sessionStorage`. Both fall back to in-memory maps\n * when the global isn't available (SSR, non-browser environments).\n */\nconst createBrowserStorageDriver = (): BrowserStorageDrivers => ({\n persistent: createWebStorageDriver(\"localStorage\"),\n session: createWebStorageDriver(\"sessionStorage\"),\n});\n\nexport type { BrowserStorageDrivers };\nexport { createBrowserStorageDriver, createMemoryStorageDriver };\n","import { z } from \"zod\";\n\nimport { logWarn } from \"../logger\";\nimport { CHAIN_PLATFORMS } from \"../types/platform\";\n\nimport type { StoredPoolRecord, StoredSelectionRecord } from \"./persistence\";\n\nconst chainPlatformSchema = z.enum(CHAIN_PLATFORMS);\n\nconst chainSchema = z.looseObject({\n id: z.string(),\n name: z.string(),\n namespace: z.string(),\n reference: z.string(),\n});\n\nconst accountSchema = z.looseObject({\n chain: chainSchema,\n id: z.string(),\n walletAddress: z.string(),\n});\n\nconst storedPoolEntrySchema = z.looseObject({\n account: accountSchema,\n accounts: z.array(accountSchema),\n chainPlatform: chainPlatformSchema,\n connectorId: z.string(),\n icon: z.string().optional(),\n name: z.string().min(1),\n});\n\nconst recordSchema = z.record(z.string(), z.unknown());\n\nconst parseStoredPoolEntry = (key: string, value: unknown) => {\n const parsed = storedPoolEntrySchema.safeParse(value);\n if (!parsed.success || parsed.data.connectorId !== key) {\n return null;\n }\n return parsed.data;\n};\n\nconst DEFAULT_KEY_PREFIX = \"butr\";\n\n/**\n * `WalletStorage` writes these and `readWalletSnapshot` reads them from\n * a cookie jar; any divergence desyncs the SSR-seeded render from the\n * client that rehydrates it, the failure ADR 0003 exists to prevent.\n */\nconst storageKeys = (keyPrefix?: string) => {\n const prefix = keyPrefix === undefined || keyPrefix === \"\" ? DEFAULT_KEY_PREFIX : keyPrefix;\n return {\n active: `${prefix}-active`,\n pool: `${prefix}-pool`,\n selection: `${prefix}-selection`,\n userDisconnected: `${prefix}-user-disconnected`,\n };\n};\n\n/**\n * Never repairs or throws: one corrupt entry must not take down a whole\n * session, and `readWalletSnapshot` may run on a server with no cookie\n * jar to write the eviction to.\n */\nconst decodePool = (raw: string | null | undefined, label = \"[butr]\"): StoredPoolRecord => {\n if (raw === null || raw === undefined || raw === \"\") {\n return {};\n }\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch (error) {\n logWarn(`${label} failed to parse pool from storage:`, error);\n return {};\n }\n const parsed = recordSchema.safeParse(value);\n if (!parsed.success) {\n return {};\n }\n const result: StoredPoolRecord = {};\n for (const [key, entryValue] of Object.entries(parsed.data)) {\n const entry = parseStoredPoolEntry(key, entryValue);\n if (entry === null) {\n logWarn(`${label} dropping invalid pool entry for ${key}`);\n } else {\n result[key] = entry;\n }\n }\n return result;\n};\n\n/** Decode a persisted selection payload. Same contract as `decodePool`. */\nconst decodeSelection = (\n raw: string | null | undefined,\n label = \"[butr]\",\n): StoredSelectionRecord => {\n if (raw === null || raw === undefined || raw === \"\") {\n return {};\n }\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch (error) {\n logWarn(`${label} failed to parse selection from storage:`, error);\n return {};\n }\n const parsed = recordSchema.safeParse(value);\n if (!parsed.success) {\n return {};\n }\n const result: StoredSelectionRecord = {};\n for (const [key, selectionValue] of Object.entries(parsed.data)) {\n const platform = chainPlatformSchema.safeParse(key);\n if (platform.success && typeof selectionValue === \"string\" && selectionValue.length > 0) {\n result[platform.data] = selectionValue;\n }\n }\n return result;\n};\n\nexport { decodePool, decodeSelection, parseStoredPoolEntry, storageKeys };\n","import { logWarn } from \"../logger\";\nimport type { ChainPlatform, ConnectedWallet } from \"../types\";\n\nimport { createBrowserStorageDriver } from \"./browser-storage-driver\";\nimport type {\n StorageDriver,\n StoredPoolEntry,\n StoredPoolRecord,\n StoredSelectionRecord,\n WalletPersistence,\n} from \"./persistence\";\nimport { decodePool, decodeSelection, parseStoredPoolEntry, storageKeys } from \"./validation\";\n\ntype StorageConfig = {\n /** Defaults to `\"butr\"`, matching `readWalletSnapshot`. */\n keyPrefix?: string;\n /** Survives app restart. Defaults to localStorage on web. */\n persistent?: StorageDriver;\n /** Cleared on session end. Defaults to sessionStorage on web. */\n session?: StorageDriver;\n};\n\nclass WalletStorage implements WalletPersistence {\n private readonly poolKey: string;\n private readonly selectionKey: string;\n private readonly activeKey: string;\n private readonly userDisconnectedKey: string;\n private readonly persistent: StorageDriver;\n private readonly session: StorageDriver;\n /**\n * Serializes pool read-modify-writes; without it concurrent `setPool`\n * calls drop each other's entries. Not reentrant, so a queued mutation\n * must read via `readPool`: `getPool` re-enters and deadlocks it.\n */\n private poolMutationQueue: Promise<unknown> = Promise.resolve();\n\n constructor(config: StorageConfig) {\n const keys = storageKeys(config.keyPrefix);\n this.poolKey = keys.pool;\n this.selectionKey = keys.selection;\n this.activeKey = keys.active;\n this.userDisconnectedKey = keys.userDisconnected;\n\n if (config.persistent && config.session) {\n this.persistent = config.persistent;\n this.session = config.session;\n } else {\n const defaults = createBrowserStorageDriver();\n this.persistent = config.persistent ?? defaults.persistent;\n this.session = config.session ?? defaults.session;\n }\n }\n\n /** Chain `fn` after the in-flight pool mutation. */\n private async serializePoolMutation<T>(fn: () => Promise<T>): Promise<T> {\n const previous = this.poolMutationQueue;\n // oxlint-disable-next-line unicorn/consistent-function-scoping -- assigned by Promise constructor below\n let resolve: () => void = () => {};\n this.poolMutationQueue = new Promise<void>((r) => {\n resolve = r;\n });\n try {\n await previous;\n } catch {\n // Previous mutation's failure shouldn't jam the queue; each\n // call site already observes its own rejection.\n }\n try {\n return await fn();\n } finally {\n resolve();\n }\n }\n\n /** Read and decode the pool without touching the mutation queue. Safe to\n * call from inside a queued mutation, unlike `getPool`. */\n private async readPool(): Promise<{ corrupt: boolean; decoded: StoredPoolRecord }> {\n let stored: string | null;\n try {\n stored = await this.persistent.getItem(this.poolKey);\n } catch (error) {\n logWarn(\"[butr] failed to read pool from storage:\", error);\n return { corrupt: false, decoded: {} };\n }\n if (stored === null || stored === \"\") {\n return { corrupt: false, decoded: {} };\n }\n const decoded = decodePool(stored);\n // An empty decode from a non-empty payload means the whole record was\n // unreadable, not that the user has no wallets.\n return { corrupt: Object.keys(decoded).length === 0, decoded };\n }\n\n async getPool(): Promise<StoredPoolRecord> {\n const { corrupt, decoded } = await this.readPool();\n if (corrupt) {\n // Evict the unreadable key directly. Going through `clearPool` would\n // acquire the mutation queue, which self-deadlocks when a queued\n // mutation is what triggered this read.\n try {\n await this.persistent.removeItem(this.poolKey);\n } catch (error) {\n logWarn(\"[butr] failed to clear corrupt pool:\", error);\n }\n }\n return decoded;\n }\n\n /**\n * Additive on purpose: a failed silent reconnect drops the entry from\n * the live pool, and it must survive to be retried next load.\n * Eviction goes through `removePoolEntry` or `clearAll`.\n */\n async setPool(pool: Map<string, ConnectedWallet>): Promise<void> {\n await this.serializePoolMutation(async () => {\n try {\n const { decoded: existing } = await this.readPool();\n const serializable: StoredPoolRecord = { ...existing };\n for (const [connectorId, wallet] of pool) {\n const entry: StoredPoolEntry = {\n account: wallet.account,\n accounts: wallet.accounts,\n chainPlatform: wallet.connector.chainPlatform,\n connectorId,\n icon: wallet.connector.icon,\n name: wallet.connector.name,\n };\n if (parseStoredPoolEntry(connectorId, entry) === null) {\n throw new Error(`[butr] refusing to persist invalid pool entry for ${connectorId}`);\n }\n serializable[connectorId] = entry;\n }\n await this.persistent.setItem(this.poolKey, JSON.stringify(serializable));\n } catch (error) {\n logWarn(\"[butr] failed to persist pool:\", error);\n }\n });\n }\n\n async removePoolEntry(connectorId: string): Promise<void> {\n await this.serializePoolMutation(async () => {\n try {\n const { decoded: stored } = await this.readPool();\n if (stored[connectorId]) {\n const { [connectorId]: _, ...remaining } = stored;\n await this.persistent.setItem(this.poolKey, JSON.stringify(remaining));\n }\n } catch (error) {\n logWarn(`[butr] failed to remove pool entry ${connectorId}:`, error);\n }\n });\n }\n\n async clearPool(): Promise<void> {\n await this.serializePoolMutation(async () => {\n await this.persistent.removeItem(this.poolKey);\n });\n }\n\n async getSelection(): Promise<StoredSelectionRecord> {\n try {\n return decodeSelection(await this.persistent.getItem(this.selectionKey));\n } catch (error) {\n logWarn(\"[butr] failed to read selection from storage:\", error);\n return {};\n }\n }\n\n async setSelection(selection: Map<ChainPlatform, string>): Promise<void> {\n try {\n const serializable: StoredSelectionRecord = {};\n for (const [platform, connectorId] of selection) {\n serializable[platform] = connectorId;\n }\n await this.persistent.setItem(this.selectionKey, JSON.stringify(serializable));\n } catch (error) {\n logWarn(\"[butr] failed to persist selection:\", error);\n }\n }\n\n async getActiveConnectorId(): Promise<string | null> {\n try {\n const value = await this.persistent.getItem(this.activeKey);\n return value !== null && value.length > 0 ? value : null;\n } catch {\n return null;\n }\n }\n\n async setActiveConnectorId(connectorId: string | null): Promise<void> {\n try {\n await (connectorId === null\n ? this.persistent.removeItem(this.activeKey)\n : this.persistent.setItem(this.activeKey, connectorId));\n } catch (error) {\n logWarn(\"[butr] failed to persist active connector id:\", error);\n }\n }\n\n async clearAll(): Promise<void> {\n await Promise.all([\n this.clearPool(),\n this.persistent.removeItem(this.selectionKey),\n this.persistent.removeItem(this.activeKey),\n ]);\n }\n\n /**\n * Kept in the session driver so it survives remounts (unlike a ref)\n * yet clears at session end (unlike the persistent driver): a manual\n * disconnect must suppress auto-connect now, not forever.\n */\n async isUserDisconnected(): Promise<boolean> {\n try {\n const value = await this.session.getItem(this.userDisconnectedKey);\n return value === \"true\";\n } catch {\n return false;\n }\n }\n\n async markUserDisconnected(value: boolean): Promise<void> {\n try {\n await (value\n ? this.session.setItem(this.userDisconnectedKey, \"true\")\n : this.session.removeItem(this.userDisconnectedKey));\n } catch {\n void 0;\n }\n }\n}\n\nexport { WalletStorage };\n","import { logWarn } from \"../logger\";\nimport type { Account, ChainPlatform, Connector } from \"../types\";\n\n/**\n * The bridge owns event-to-handler mapping and the unsubscribe handle;\n * the runtime owns the effects (dispatch, persist, consumer callbacks).\n */\ntype LifecycleHandlers = {\n /** Wallet exposed a new accounts list (or active account swap). The\n * bridge forwards the full array; single-account wallets included.\n * `active` is the address the wallet picked as current. */\n onAccountChanged: (\n connectorId: string,\n accounts: ReadonlyArray<Account>,\n active: Account,\n ) => void;\n /** Wallet disconnected externally (user locked, extension removed,\n * WC session ended on the relay). The bridge has already cleared\n * the subscription for `connectorId` by the time this fires. */\n onDisconnected: (connectorId: string, chainPlatform: ChainPlatform) => void;\n};\n\n/**\n * Owns the \"exactly one subscription per connector\" invariant for the\n * whole runtime; nothing else may call `connector.subscribe`.\n */\ntype ConnectorLifecycle = {\n /**\n * Idempotent: a second `attach` for the same id detaches the previous\n * subscription first. No-op for connectors without `subscribe`.\n */\n attach: (connectorId: string, connector: Connector) => void;\n /** Detach a single connector. Safe to call when no subscription is\n * registered. */\n detach: (connectorId: string) => void;\n /** Detach every active subscription. Used during `reset`. */\n detachAll: () => void;\n};\n\nconst createConnectorLifecycle = (handlers: LifecycleHandlers): ConnectorLifecycle => {\n const unsubscribers = new Map<string, () => void>();\n\n const detach = (connectorId: string) => {\n const unsub = unsubscribers.get(connectorId);\n if (!unsub) {\n return;\n }\n try {\n unsub();\n } catch (error: unknown) {\n logWarn(\"[butr] unsubscribe threw:\", error);\n }\n unsubscribers.delete(connectorId);\n };\n\n return {\n attach: (connectorId, connector) => {\n if (!connector.subscribe) {\n return;\n }\n detach(connectorId);\n try {\n const unsub = connector.subscribe((event) => {\n switch (event.type) {\n case \"accountChanged\": {\n handlers.onAccountChanged(connectorId, event.accounts, event.account);\n break;\n }\n case \"disconnected\": {\n detach(connectorId);\n handlers.onDisconnected(connectorId, connector.chainPlatform);\n break;\n }\n default: {\n const exhaustiveCheck: never = event;\n void exhaustiveCheck;\n }\n }\n });\n unsubscribers.set(connectorId, unsub);\n } catch (error: unknown) {\n logWarn(`[butr] subscribe failed for ${connectorId}:`, error);\n }\n },\n\n detach,\n\n detachAll: () => {\n const ids: Array<string> = [];\n for (const id of unsubscribers.keys()) {\n ids.push(id);\n }\n for (const id of ids) {\n detach(id);\n }\n },\n };\n};\n\nexport type { ConnectorLifecycle, LifecycleHandlers };\nexport { createConnectorLifecycle };\n","import type { StoredPoolEntry, WalletPersistence } from \"../storage\";\nimport { CHAIN_PLATFORMS } from \"../types\";\nimport type {\n Account,\n ChainPlatform,\n ConnectedWallet,\n Connector,\n WalletAdapter,\n WalletManagerConfig,\n} from \"../types\";\n\nconst VALID_CHAIN_PLATFORMS: ReadonlySet<string> = new Set(CHAIN_PLATFORMS);\n\nconst isChainPlatform = (value: string): value is ChainPlatform => VALID_CHAIN_PLATFORMS.has(value);\n\n/**\n * Restore outcome for a single pool entry. `kind: \"ok\"` carries the\n * fully-formed `ConnectedWallet`. `kind: \"fail\"` carries the raw error\n * so the caller can route it to telemetry.\n */\ntype RestoreOutcome =\n | { connectorId: string; entry: ConnectedWallet; kind: \"ok\" }\n | { connectorId: string; error: unknown; kind: \"fail\" };\n\n/**\n * Snapshot returned by `HydrationCoordinator.hydrate()`; everything\n * the reducer needs to compose a `HYDRATED` event plus the metadata the\n * runtime uses to wire subscriptions and surface the outcome.\n */\ntype HydrateResult = {\n activeConnectorId: string | null;\n /** Entries whose restore failed (connect() rejected, the connector\n * threw mid-flight). Reported for telemetry only; storage is\n * preserved so the next load can retry. The most common cause is\n * EIP-1193 `eth_accounts: []` from a locked wallet, which clears as\n * soon as the user unlocks and reloads. */\n dropped: Array<{ connectorId: string; reason: unknown }>;\n isUserDisconnected: boolean;\n /** Entries parked because `createConnector(id)` returned `null` at\n * hydration time (typical for Wallet Standard adapters announced\n * asynchronously). The coordinator keeps an internal record of these\n * and resolves them when the runtime later calls `drainPending`. */\n pendingIds: Array<string>;\n pool: Map<string, ConnectedWallet>;\n selection: Map<ChainPlatform, string>;\n};\n\ntype HydrationCoordinator = {\n /** Storage cleanup on a `fail` outcome is handled internally; the\n * caller only routes the error. */\n drainPending: (connectorId: string) => Promise<RestoreOutcome | null>;\n /** Entries whose adapter is not registered yet are parked, not\n * dropped; the caller must drain them via `drainPending` or those\n * wallets never reconnect. */\n hydrate: () => Promise<HydrateResult>;\n /** Read once right after `hydrate()` resolves, to catch adapters that\n * announced during the hydration window. */\n pendingIds: () => Array<string>;\n};\n\n/** Pick the right `accounts` list: fresh from the connector if it\n * exposes `getAccounts`, otherwise the persisted list, otherwise just\n * the active account. */\nconst resolveHydratedAccounts = async (\n connector: Connector,\n storedAccounts: ReadonlyArray<Account>,\n fallbackAccount: Account,\n): Promise<Array<Account>> => {\n if (connector.getAccounts) {\n const fresh = await connector.getAccounts().catch(() => null);\n if (fresh && fresh.length > 0) {\n return fresh;\n }\n }\n if (storedAccounts.length > 0) {\n return [...storedAccounts];\n }\n return [fallbackAccount];\n};\n\nconst restoreOneEntry = async (\n connectorId: string,\n entry: { account: Account; accounts: ReadonlyArray<Account> },\n connector: WalletAdapter,\n): Promise<RestoreOutcome> => {\n try {\n await connector.connect({ silent: true });\n const freshAccount = await connector.getAccount();\n const accountToUse = freshAccount ?? entry.account;\n const accounts = await resolveHydratedAccounts(connector, entry.accounts, accountToUse);\n return {\n connectorId,\n entry: {\n account: accountToUse,\n accounts,\n connector,\n },\n kind: \"ok\",\n };\n } catch (error) {\n return { connectorId, error, kind: \"fail\" };\n }\n};\n\nconst createHydrationCoordinator = (\n storage: WalletPersistence,\n createConnector: WalletManagerConfig[\"createConnector\"],\n): HydrationCoordinator => {\n const pending = new Map<string, StoredPoolEntry>();\n\n return {\n drainPending: async (connectorId) => {\n const entry = pending.get(connectorId);\n if (!entry) {\n return null;\n }\n const connector = createConnector(connectorId);\n if (!connector) {\n return null;\n }\n const outcome = await restoreOneEntry(connectorId, entry, connector);\n pending.delete(connectorId);\n return outcome;\n },\n\n hydrate: async () => {\n const [storedPool, storedSelection, storedActive, userDisconnected] = await Promise.all([\n storage.getPool(),\n storage.getSelection(),\n storage.getActiveConnectorId(),\n storage.isUserDisconnected(),\n ]);\n\n const pool = new Map<string, ConnectedWallet>();\n const dropped: Array<{ connectorId: string; reason: unknown }> = [];\n\n pending.clear();\n\n const tasks: Array<Promise<RestoreOutcome>> = [];\n for (const [connectorId, entry] of Object.entries(storedPool)) {\n if (!entry) {\n continue;\n }\n const connector = createConnector(connectorId);\n if (!connector) {\n pending.set(connectorId, entry);\n continue;\n }\n tasks.push(restoreOneEntry(connectorId, entry, connector));\n }\n\n const outcomes = await Promise.all(tasks);\n for (const outcome of outcomes) {\n if (outcome.kind === \"ok\") {\n pool.set(outcome.connectorId, outcome.entry);\n continue;\n }\n dropped.push({ connectorId: outcome.connectorId, reason: outcome.error });\n }\n\n const selection = new Map<ChainPlatform, string>();\n for (const [platform, connectorId] of Object.entries(storedSelection)) {\n if (isChainPlatform(platform) && connectorId !== undefined && pool.has(connectorId)) {\n selection.set(platform, connectorId);\n }\n }\n for (const [connectorId, wallet] of pool) {\n const platform = wallet.connector.chainPlatform;\n if (!selection.has(platform)) {\n selection.set(platform, connectorId);\n }\n }\n\n let activeConnectorId: string | null = null;\n if (storedActive !== null && pool.has(storedActive)) {\n activeConnectorId = storedActive;\n } else if (pool.size > 0) {\n activeConnectorId = pool.keys().next().value ?? null;\n }\n\n return {\n activeConnectorId,\n dropped,\n isUserDisconnected: userDisconnected,\n pendingIds: [...pending.keys()],\n pool,\n selection,\n };\n },\n\n pendingIds: () => [...pending.keys()],\n };\n};\n\nexport type { HydrateResult, HydrationCoordinator, RestoreOutcome };\nexport { createHydrationCoordinator };\n","import type { Account, ChainPlatform, ConnectedWallet } from \"../types\";\nimport type { ConnectionError } from \"../types/errors\";\n\n/**\n * The reducer never writes `\"reconnecting\"`; `useConnectionStatus`\n * derives it from `reconnectingIds` so the state machine stays narrow\n * while the public vocabulary matches wagmi's.\n */\ntype ConnectionStatus = \"idle\" | \"connecting\" | \"success\" | \"error\" | \"reconnecting\";\n\ntype State = {\n activeConnectorId: string | null;\n connectingConnectorId: string | null;\n connectionError: ConnectionError | null;\n connectionStatus: ConnectionStatus;\n isHydrated: boolean;\n isUserDisconnected: boolean;\n pool: Map<string, ConnectedWallet>;\n /**\n * Ids still backed by a shadow adapter from `initialState`. Empty\n * without `initialState`; shrinks on `HYDRATED` / `CONNECT_SUCCEEDED`\n * and on `DISCONNECTED` / `RESET`.\n */\n reconnectingIds: ReadonlySet<string>;\n selection: Map<ChainPlatform, string>;\n};\n\n/**\n * Lifecycle events: hydration, full reset, and the explicit\n * user-disconnected flag the runtime sets to suppress eager reconnect.\n */\ntype LifecycleEvent =\n | {\n activeConnectorId: string | null;\n /** Connector ids that were seeded from `initialState` but whose silent\n * reconnect failed. Their pool entries are still shadow-backed, so they\n * are evicted rather than left permanently unusable. */\n dropped: ReadonlyArray<string>;\n isUserDisconnected: boolean;\n pool: Map<string, ConnectedWallet>;\n selection: Map<ChainPlatform, string>;\n type: \"HYDRATED\";\n }\n | { type: \"RESET\" }\n | { type: \"USER_DISCONNECTED_SET\"; value: boolean };\n\n/**\n * None of these mutate the pool; `CONNECT_SUCCEEDED` is the only bridge\n * across to `PoolMutationEvent`.\n */\ntype ConnectionStatusEvent =\n | { connectorId: string; type: \"CONNECT_STARTED\" }\n | { connectorId: string; entry: ConnectedWallet; type: \"CONNECT_SUCCEEDED\" }\n | { connectorId: string; error: ConnectionError; type: \"CONNECT_FAILED\" }\n | { error: ConnectionError | null; type: \"ERROR_SET\" }\n | { type: \"STATUS_RESET\" };\n\n/**\n * Pool-mutation events: changes to the set of connected wallets and\n * their per-wallet account lists. `DISCONNECTED` removes an entry;\n * the refresh events update an existing one in-place.\n */\ntype PoolMutationEvent =\n | {\n /**\n * Deliberately not `CONNECT_SUCCEEDED`: discovery fires this at an\n * arbitrary time, so it must not overwrite the connect-attempt\n * status that the user's own action owns.\n */\n connectorId: string;\n entry: ConnectedWallet;\n type: \"ENTRY_RESTORED\";\n }\n | {\n /** When set, becomes the new active account. Used by paths that\n * know which account should be active (wallet event, manual\n * update). When unset, the reducer preserves the current active\n * if it's still in `accounts`, else picks `accounts[0]`. */\n accounts: Array<Account>;\n active?: Account;\n connectorId: string;\n type: \"ACCOUNTS_REFRESHED\";\n }\n | { connectorId: string; type: \"DISCONNECTED\" }\n | { connectorId: string; type: \"WALLET_REFRESHED\" };\n\n/**\n * Selection events: which connector is active, and which connector\n * serves each chain platform. Pure pointer updates; no pool mutation.\n */\ntype SelectionEvent =\n | { chainPlatform: ChainPlatform; connectorId: string | null; type: \"SELECTION_CHANGED\" }\n | { connectorId: string | null; type: \"ACTIVE_CHANGED\" };\n\n/**\n * The single event type the reducer dispatches on. Grouped above by\n * concern so a reader sees the map before the cases; adding an event\n * means picking the group it belongs to.\n */\ntype Event = ConnectionStatusEvent | LifecycleEvent | PoolMutationEvent | SelectionEvent;\n\nconst initialState: State = {\n activeConnectorId: null,\n connectingConnectorId: null,\n connectionError: null,\n connectionStatus: \"idle\",\n isHydrated: false,\n isUserDisconnected: false,\n pool: new Map(),\n reconnectingIds: new Set(),\n selection: new Map(),\n};\n\n/** Find any connector in the pool serving a given platform. */\nconst findConnectorForPlatform = (\n pool: Map<string, ConnectedWallet>,\n chainPlatform: ChainPlatform,\n): string | undefined => {\n for (const [id, wallet] of pool) {\n if (wallet.connector.chainPlatform === chainPlatform) {\n return id;\n }\n }\n return undefined;\n};\n\n/** Pure reducer: every state transition is expressed as `(state, event) => state`.\n * No I/O, no async, no side effects. Side effects live in the runtime. */\nconst reducer = (state: State, event: Event): State => {\n switch (event.type) {\n case \"HYDRATED\": {\n const pool = new Map<string, ConnectedWallet>(state.pool);\n for (const [id, entry] of event.pool) {\n pool.set(id, entry);\n }\n // A seeded entry whose reconnect failed is still backed by a shadow\n // adapter whose every method rejects. Leaving it in the pool would strand\n // it: nothing else ever clears it, so consumers would read a permanently\n // erroring wallet that reports itself as reconnecting forever.\n for (const id of event.dropped) {\n pool.delete(id);\n }\n const selection = new Map<ChainPlatform, string>(state.selection);\n for (const [platform, id] of event.selection) {\n selection.set(platform, id);\n }\n let activeConnectorId: string | null = null;\n if (event.activeConnectorId !== null && pool.has(event.activeConnectorId)) {\n activeConnectorId = event.activeConnectorId;\n } else if (state.activeConnectorId !== null && pool.has(state.activeConnectorId)) {\n activeConnectorId = state.activeConnectorId;\n } else if (pool.size > 0) {\n activeConnectorId = pool.keys().next().value ?? null;\n }\n let nextReconnecting: ReadonlySet<string> = state.reconnectingIds;\n if (state.reconnectingIds.size > 0) {\n const next = new Set(state.reconnectingIds);\n for (const id of event.pool.keys()) {\n next.delete(id);\n }\n for (const id of event.dropped) {\n next.delete(id);\n }\n if (next.size !== state.reconnectingIds.size) {\n nextReconnecting = next;\n }\n }\n const selectionAfterDrop = new Map(selection);\n for (const [platform, id] of selectionAfterDrop) {\n if (!pool.has(id)) {\n selectionAfterDrop.delete(platform);\n const fallback = findConnectorForPlatform(pool, platform);\n if (fallback !== undefined) {\n selectionAfterDrop.set(platform, fallback);\n }\n }\n }\n return {\n ...state,\n activeConnectorId,\n isHydrated: true,\n isUserDisconnected: event.isUserDisconnected,\n pool,\n reconnectingIds: nextReconnecting,\n selection: selectionAfterDrop,\n };\n }\n\n case \"USER_DISCONNECTED_SET\": {\n return { ...state, isUserDisconnected: event.value };\n }\n\n case \"CONNECT_STARTED\": {\n return {\n ...state,\n connectingConnectorId: event.connectorId,\n connectionError: null,\n connectionStatus: \"connecting\",\n };\n }\n\n case \"CONNECT_SUCCEEDED\": {\n const { connectorId, entry } = event;\n const existing = state.pool.get(connectorId);\n\n const nextReconnecting: ReadonlySet<string> = state.reconnectingIds.has(connectorId)\n ? new Set([...state.reconnectingIds].filter((id) => id !== connectorId))\n : state.reconnectingIds;\n\n if (\n existing &&\n existing.account.walletAddress.toLowerCase() === entry.account.walletAddress.toLowerCase()\n ) {\n return {\n ...state,\n activeConnectorId: connectorId,\n connectingConnectorId: null,\n connectionError: null,\n connectionStatus: \"success\",\n pool:\n existing.connector === entry.connector\n ? state.pool\n : new Map([...state.pool, [connectorId, entry] as const]),\n reconnectingIds: nextReconnecting,\n };\n }\n\n const newPool = new Map([...state.pool, [connectorId, entry] as const]);\n const newSelection = new Map([\n ...state.selection,\n [entry.connector.chainPlatform, connectorId] as const,\n ]);\n\n return {\n ...state,\n activeConnectorId: connectorId,\n connectingConnectorId: null,\n connectionError: null,\n connectionStatus: \"success\",\n pool: newPool,\n reconnectingIds: nextReconnecting,\n selection: newSelection,\n };\n }\n\n case \"ENTRY_RESTORED\": {\n const { connectorId, entry } = event;\n const nextReconnecting: ReadonlySet<string> = state.reconnectingIds.has(connectorId)\n ? new Set([...state.reconnectingIds].filter((id) => id !== connectorId))\n : state.reconnectingIds;\n\n const platform = entry.connector.chainPlatform;\n const selection = state.selection.has(platform)\n ? state.selection\n : new Map([...state.selection, [platform, connectorId] as const]);\n\n return {\n ...state,\n // Only adopt the restored wallet as active when nothing else is. A\n // background restore must not steal focus from an explicit selection\n // or from the seeded active id.\n activeConnectorId: state.activeConnectorId ?? connectorId,\n pool: new Map([...state.pool, [connectorId, entry] as const]),\n reconnectingIds: nextReconnecting,\n selection,\n };\n }\n\n case \"CONNECT_FAILED\": {\n // Ignore a failure from a superseded attempt; only the connect currently\n // in flight owns the status triple.\n if (state.connectingConnectorId !== event.connectorId) {\n return state;\n }\n return {\n ...state,\n connectingConnectorId: null,\n connectionError: event.error,\n connectionStatus: \"error\",\n };\n }\n\n case \"DISCONNECTED\": {\n const wallet = state.pool.get(event.connectorId);\n if (!wallet) {\n return state;\n }\n\n const newPool = new Map(state.pool);\n newPool.delete(event.connectorId);\n\n const newSelection = new Map(state.selection);\n const platform = wallet.connector.chainPlatform;\n if (newSelection.get(platform) === event.connectorId) {\n newSelection.delete(platform);\n const fallback = findConnectorForPlatform(newPool, platform);\n if (fallback !== undefined) {\n newSelection.set(platform, fallback);\n }\n }\n\n const firstId = newPool.keys().next();\n const activeConnectorId =\n state.activeConnectorId === event.connectorId\n ? (firstId.value ?? null)\n : state.activeConnectorId;\n\n const nextReconnecting: ReadonlySet<string> = state.reconnectingIds.has(event.connectorId)\n ? new Set([...state.reconnectingIds].filter((id) => id !== event.connectorId))\n : state.reconnectingIds;\n\n return {\n ...state,\n activeConnectorId,\n pool: newPool,\n reconnectingIds: nextReconnecting,\n selection: newSelection,\n };\n }\n\n case \"ACCOUNTS_REFRESHED\": {\n const wallet = state.pool.get(event.connectorId);\n if (!wallet) {\n return state;\n }\n let nextAccount: Account;\n if (event.active) {\n nextAccount = event.active;\n } else {\n const stillHasCurrent = event.accounts.some(\n (a) =>\n a.walletAddress === wallet.account.walletAddress &&\n a.chain.id === wallet.account.chain.id,\n );\n nextAccount = stillHasCurrent ? wallet.account : (event.accounts[0] ?? wallet.account);\n }\n const sameAccount =\n nextAccount.walletAddress === wallet.account.walletAddress &&\n nextAccount.chain.id === wallet.account.chain.id;\n const sameAccountsShape =\n event.accounts.length === wallet.accounts.length &&\n event.accounts.every((a, i) => a.walletAddress === wallet.accounts[i]?.walletAddress);\n if (sameAccount && sameAccountsShape) {\n return state;\n }\n const updated: ConnectedWallet = {\n ...wallet,\n account: nextAccount,\n accounts: [...event.accounts],\n };\n const newPool = new Map([...state.pool, [event.connectorId, updated] as const]);\n return { ...state, pool: newPool };\n }\n\n case \"WALLET_REFRESHED\": {\n const wallet = state.pool.get(event.connectorId);\n if (!wallet) {\n return state;\n }\n const newPool = new Map([...state.pool, [event.connectorId, { ...wallet }] as const]);\n return { ...state, pool: newPool };\n }\n\n case \"ACTIVE_CHANGED\": {\n return { ...state, activeConnectorId: event.connectorId };\n }\n\n case \"SELECTION_CHANGED\": {\n const newSelection = new Map(state.selection);\n if (event.connectorId === null) {\n newSelection.delete(event.chainPlatform);\n } else {\n newSelection.set(event.chainPlatform, event.connectorId);\n }\n return { ...state, selection: newSelection };\n }\n\n case \"STATUS_RESET\": {\n return {\n ...state,\n connectingConnectorId: null,\n connectionError: null,\n connectionStatus: \"idle\",\n };\n }\n\n case \"ERROR_SET\": {\n return {\n ...state,\n connectionError: event.error,\n connectionStatus: event.error ? \"error\" : \"idle\",\n };\n }\n\n case \"RESET\": {\n return {\n ...initialState,\n isHydrated: state.isHydrated,\n isUserDisconnected: true,\n reconnectingIds: new Set(),\n };\n }\n\n default: {\n const exhaustiveCheck: never = event;\n void exhaustiveCheck;\n return state;\n }\n }\n};\n\nexport type {\n ConnectionStatus,\n ConnectionStatusEvent,\n Event,\n LifecycleEvent,\n PoolMutationEvent,\n SelectionEvent,\n State,\n};\nexport { initialState, reducer };\n","/** Run an async operation fire-and-forget, calling onError if it throws. */\nconst run = async (fn: () => Promise<void>, onError: (e: unknown) => void): Promise<void> => {\n try {\n await fn();\n } catch (error) {\n onError(error);\n }\n};\n\nexport { run };\n","import { createStore } from \"zustand/vanilla\";\n\nimport { logError, logWarn } from \"../logger\";\nimport type { WalletPersistence, WalletSnapshot } from \"../storage\";\nimport { WalletStorage } from \"../storage/wallet-storage\";\nimport { CHAIN_PLATFORMS } from \"../types\";\nimport type {\n Account,\n ChainPlatform,\n ConnectedWallet,\n WalletAdapter,\n WalletManagerConfig,\n} from \"../types\";\nimport type { ConnectionError } from \"../types/errors\";\nimport { mapConnectionError } from \"../types/errors\";\n\nimport { createConnectorLifecycle } from \"./connector-lifecycle\";\nimport { createHydrationCoordinator } from \"./hydration\";\nimport { type Event, type State, initialState, reducer } from \"./reducer\";\nimport { createShadowAdapter } from \"./shadow-adapter\";\nimport { run } from \"./wallet-store-helpers\";\n\nconst VALID_CHAIN_PLATFORMS: ReadonlySet<string> = new Set(CHAIN_PLATFORMS);\n\nconst isChainPlatform = (value: string): value is ChainPlatform => VALID_CHAIN_PLATFORMS.has(value);\n\n/**\n * `isHydrated` is true from the first render on this path, so\n * `reconnectingIds` (not `isHydrated`) is the \"is this connection\n * verified\" signal until silent reconnect lands.\n */\nconst seedStateFromSnapshot = (snapshot: WalletSnapshot): State => {\n const pool = new Map<string, ConnectedWallet>();\n const reconnectingIds = new Set<string>();\n for (const [connectorId, entry] of Object.entries(snapshot.pool)) {\n if (!entry) {\n continue;\n }\n const connector: WalletAdapter = createShadowAdapter(entry);\n pool.set(connectorId, {\n account: entry.account,\n accounts: [...entry.accounts],\n connector,\n });\n reconnectingIds.add(connectorId);\n }\n const selection = new Map<ChainPlatform, string>();\n for (const [platform, connectorId] of Object.entries(snapshot.selection)) {\n if (isChainPlatform(platform) && connectorId !== undefined && pool.has(connectorId)) {\n selection.set(platform, connectorId);\n }\n }\n const activeConnectorId =\n snapshot.activeConnectorId !== null && pool.has(snapshot.activeConnectorId)\n ? snapshot.activeConnectorId\n : (pool.keys().next().value ?? null);\n return {\n ...initialState,\n activeConnectorId,\n isHydrated: true,\n pool,\n reconnectingIds,\n selection,\n };\n};\n\nconst CONNECT_TIMEOUT_MS = 90_000;\nconst DEFAULT_SLOW_CONNECT_THRESHOLD_MS = 5000;\n\nconst normaliseAddress = (addr: string): string => addr.toLowerCase();\n\ntype ExtractState<S> = S extends { getState: () => infer T } ? T : never;\n\ntype RuntimeMembers = {\n _config: WalletManagerConfig;\n _storage: WalletPersistence;\n connectWallet: (\n connectorId: string,\n onSuccess?: (wallet: ConnectedWallet) => void,\n onError?: (error: Error) => void,\n ) => Promise<void>;\n disconnectWallet: (connectorId: string) => void;\n getConnectorInstance: (id: string) => ReturnType<WalletManagerConfig[\"createConnector\"]>;\n hydrateWallets: () => Promise<void>;\n refreshWallet: (connectorId: string) => void;\n requestAccounts: (connectorId: string) => Promise<void>;\n reset: () => void;\n resetConnectionStatus: () => void;\n setActiveConnector: (connectorId: string | null) => void;\n setConnectionError: (error: ConnectionError | null) => void;\n setSelection: (chainPlatform: ChainPlatform, connectorId: string | null) => void;\n setUserDisconnected: (value: boolean) => void;\n tryRestoreFromPending: (connectorId: string) => Promise<void>;\n updateWalletAccount: (connectorId: string, account: Account) => void;\n};\n\ntype WalletStore = ReturnType<typeof createWalletStore>;\ntype WalletStoreState = ExtractState<WalletStore>;\n\nconst createWalletStore = (config: WalletManagerConfig) => {\n const storage = config.storage ?? new WalletStorage({ keyPrefix: config.storageKeyPrefix });\n\n const reportStorageError = (context: string) => (error: unknown) => {\n if (config.onStorageError) {\n try {\n config.onStorageError(error, context);\n } catch (cbError: unknown) {\n logWarn(\"[butr] onStorageError threw:\", cbError);\n }\n return;\n }\n logWarn(`[butr] ${context}:`, error);\n };\n\n const hydration = createHydrationCoordinator(storage, config.createConnector);\n\n return createStore<State & RuntimeMembers>()((set, get) => {\n const dispatch = (event: Event) => {\n set((prev) => reducer(prev, event), false);\n };\n\n const persistPool = (): Promise<void> =>\n run(() => storage.setPool(get().pool), reportStorageError(\"failed to persist pool\"));\n\n const persistSelection = (): Promise<void> =>\n run(\n () => storage.setSelection(get().selection),\n reportStorageError(\"failed to persist selection\"),\n );\n\n const persistActive = (): Promise<void> =>\n run(\n () => storage.setActiveConnectorId(get().activeConnectorId),\n reportStorageError(\"failed to persist active connector\"),\n );\n\n const refreshPoolEntry = (connectorId: string, accounts: Array<Account>, active?: Account) => {\n dispatch({ accounts, active, connectorId, type: \"ACCOUNTS_REFRESHED\" });\n void persistPool();\n };\n\n const lifecycle = createConnectorLifecycle({\n onAccountChanged: (connectorId, accounts, active) => {\n refreshPoolEntry(connectorId, [...accounts], active);\n },\n onDisconnected: (connectorId, chainPlatform) => {\n // Tear the connector down as well as dropping it from the pool. The\n // adapter instance is cached by discovery and handed back on the next\n // connect, so an adapter that reported itself disconnected while\n // holding a live session would be reused in that state.\n const wallet = get().pool.get(connectorId);\n if (wallet) {\n void run(() => wallet.connector.disconnect?.() ?? Promise.resolve(), logError);\n }\n dispatch({ connectorId, type: \"DISCONNECTED\" });\n config.onDisconnect?.(chainPlatform);\n },\n });\n\n const seeded: State = config.initialState\n ? seedStateFromSnapshot(config.initialState)\n : initialState;\n\n return {\n ...seeded,\n _config: config,\n _storage: storage,\n connectWallet: async (connectorId, onSuccess, onError) => {\n get().setUserDisconnected(false);\n\n const connector = config.createConnector(connectorId);\n if (!connector) {\n throw new Error(`Failed to create connector for ${connectorId}`);\n }\n\n dispatch({ connectorId, type: \"CONNECT_STARTED\" });\n\n const slowThreshold = config.slowConnectThresholdMs ?? DEFAULT_SLOW_CONNECT_THRESHOLD_MS;\n const slowTimer = config.onSlowConnect\n ? setTimeout(() => {\n try {\n config.onSlowConnect?.(connectorId);\n } catch (cbError: unknown) {\n logWarn(\"[butr] onSlowConnect threw:\", cbError);\n }\n }, slowThreshold)\n : null;\n\n let connectTimeoutId: ReturnType<typeof setTimeout> | undefined;\n\n try {\n const connectPromise = connector.connect();\n // oxlint-disable-next-line promise/prefer-await-to-then -- suppress unhandled rejection; we await via Promise.race below\n void connectPromise.catch(() => {});\n await Promise.race([\n connectPromise,\n new Promise((_, reject) => {\n connectTimeoutId = setTimeout(() => {\n reject(new Error(\"Connection timeout\"));\n }, CONNECT_TIMEOUT_MS);\n }),\n ]);\n\n const account = await connector.getAccount();\n if (!account) {\n throw new Error(\"Failed to get account\");\n }\n\n const fetchedAccounts = connector.getAccounts\n ? await connector.getAccounts().catch(() => null)\n : null;\n const accounts =\n fetchedAccounts && fetchedAccounts.length > 0 ? fetchedAccounts : [account];\n\n const entry: ConnectedWallet = { account, accounts, connector };\n dispatch({ connectorId, entry, type: \"CONNECT_SUCCEEDED\" });\n\n lifecycle.attach(connectorId, connector);\n\n await Promise.all([persistPool(), persistSelection(), persistActive()]);\n\n config.onConnect?.(entry);\n onSuccess?.(entry);\n } catch (error) {\n const normalised = mapConnectionError(error);\n dispatch({ connectorId, error: normalised, type: \"CONNECT_FAILED\" });\n try {\n await connector.disconnect?.();\n } catch (disconnectError: unknown) {\n logWarn(\"[butr] disconnect during error recovery failed:\", disconnectError);\n }\n try {\n config.onConnectError?.(normalised, connectorId);\n } catch (cbError: unknown) {\n logWarn(\"[butr] onConnectError threw:\", cbError);\n }\n onError?.(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n clearTimeout(connectTimeoutId);\n if (slowTimer) {\n clearTimeout(slowTimer);\n }\n }\n },\n\n disconnectWallet: (connectorId) => {\n get().setUserDisconnected(true);\n\n const state = get();\n if (!state.isHydrated) {\n return;\n }\n const wallet = state.pool.get(connectorId);\n if (!wallet) {\n return;\n }\n\n lifecycle.detach(connectorId);\n\n void run(() => wallet.connector.disconnect?.() ?? Promise.resolve(), logError);\n\n const platform = wallet.connector.chainPlatform;\n dispatch({ connectorId, type: \"DISCONNECTED\" });\n\n if (get().pool.size === 0) {\n void run(() => storage.clearAll(), reportStorageError(\"failed to clear storage\"));\n } else {\n void run(\n () => storage.removePoolEntry(connectorId),\n reportStorageError(\"failed to remove pool entry\"),\n );\n void persistSelection();\n void persistActive();\n }\n\n config.onDisconnect?.(platform);\n },\n\n getConnectorInstance: (id) => config.createConnector(id),\n\n hydrateWallets: async () => {\n const result = await hydration.hydrate();\n dispatch({\n activeConnectorId: result.activeConnectorId,\n dropped: result.dropped.map((d) => d.connectorId),\n isUserDisconnected: result.isUserDisconnected,\n pool: result.pool,\n selection: result.selection,\n type: \"HYDRATED\",\n });\n for (const [connectorId, wallet] of result.pool) {\n lifecycle.attach(connectorId, wallet.connector);\n }\n await Promise.all([persistSelection(), persistActive()]);\n for (const id of hydration.pendingIds()) {\n void run(\n () => get().tryRestoreFromPending(id),\n (e) => {\n logWarn(`[butr] late restore rejected for ${id}:`, e);\n },\n );\n }\n if (config.onHydrated) {\n try {\n config.onHydrated({\n dropped: result.dropped,\n pendingIds: [...result.pendingIds],\n restoredIds: [...result.pool.keys()],\n });\n } catch (cbError: unknown) {\n logWarn(\"[butr] onHydrated threw:\", cbError);\n }\n } else if (result.dropped.length > 0) {\n for (const { connectorId, reason } of result.dropped) {\n logWarn(`[butr] failed to restore connector ${connectorId}:`, reason);\n }\n }\n },\n refreshWallet: (connectorId) => {\n dispatch({ connectorId, type: \"WALLET_REFRESHED\" });\n },\n\n requestAccounts: async (connectorId) => {\n const entry = get().pool.get(connectorId);\n if (!entry) {\n return;\n }\n await entry.connector.requestAccounts?.();\n const fresh = entry.connector.getAccounts\n ? await entry.connector.getAccounts().catch(() => null)\n : null;\n if (!fresh || fresh.length === 0) {\n return;\n }\n refreshPoolEntry(connectorId, fresh);\n },\n\n reset: () => {\n get().setUserDisconnected(true);\n\n const state = get();\n if (!state.isHydrated) {\n return;\n }\n\n lifecycle.detachAll();\n\n for (const wallet of state.pool.values()) {\n void run(() => wallet.connector.disconnect?.() ?? Promise.resolve(), logError);\n }\n\n void run(() => storage.clearAll(), reportStorageError(\"failed to clear storage\"));\n\n if (config.onReset) {\n const onReset = config.onReset;\n void run(() => Promise.resolve(onReset()), logError);\n }\n\n dispatch({ type: \"RESET\" });\n },\n\n resetConnectionStatus: () => {\n dispatch({ type: \"STATUS_RESET\" });\n },\n\n setActiveConnector: (connectorId) => {\n dispatch({ connectorId, type: \"ACTIVE_CHANGED\" });\n void persistActive();\n },\n\n setConnectionError: (error) => {\n dispatch({ error, type: \"ERROR_SET\" });\n },\n\n setSelection: (chainPlatform, connectorId) => {\n dispatch({ chainPlatform, connectorId, type: \"SELECTION_CHANGED\" });\n void persistSelection();\n },\n\n setUserDisconnected: (value: boolean) => {\n dispatch({ type: \"USER_DISCONNECTED_SET\", value });\n void run(\n () => storage.markUserDisconnected(value),\n reportStorageError(\"failed to persist disconnect intent\"),\n );\n },\n\n tryRestoreFromPending: async (connectorId) => {\n const outcome = await hydration.drainPending(connectorId);\n if (!outcome) {\n return;\n }\n if (outcome.kind === \"fail\") {\n logWarn(`[butr] late restore failed for ${connectorId}:`, outcome.error);\n return;\n }\n dispatch({ connectorId, entry: outcome.entry, type: \"ENTRY_RESTORED\" });\n lifecycle.attach(connectorId, outcome.entry.connector);\n await Promise.all([persistPool(), persistSelection(), persistActive()]);\n config.onConnect?.(outcome.entry);\n },\n\n updateWalletAccount: (connectorId, account) => {\n const entry = get().pool.get(connectorId);\n if (!entry) {\n return;\n }\n const newChain = account.chain;\n const remapped = entry.accounts.map((a) =>\n a.chain.id === newChain.id\n ? a\n : {\n chain: newChain,\n id: `${newChain.id}:${normaliseAddress(a.walletAddress)}`,\n walletAddress: a.walletAddress,\n },\n );\n const seen = remapped.some(\n (a) => normaliseAddress(a.walletAddress) === normaliseAddress(account.walletAddress),\n );\n const accounts = seen ? remapped : [...remapped, account];\n refreshPoolEntry(connectorId, accounts, account);\n },\n };\n });\n};\n\nexport type { WalletStore, WalletStoreState };\nexport { createWalletStore };\n","import type { StorageDriver } from \"./persistence\";\n\ntype InitialCookies = Iterable<[string, string]> | Readonly<Record<string, string>>;\n\ntype CookieDriverOptions = {\n /**\n * Cookie `domain` attribute. Omit to scope to the current host.\n * Set to a parent domain (e.g. `.example.com`) to share state\n * across subdomains.\n */\n domain?: string;\n /**\n * Server-side cookie snapshot (Next.js' `cookies()`, a parsed\n * `req.headers.cookie`, …) read only when `document` is unavailable,\n * so the SSR pass sees the state the client will hydrate with.\n */\n initialCookies?: InitialCookies;\n /**\n * Lifetime in seconds. Defaults to 30 days.\n */\n maxAgeSeconds?: number;\n /**\n * URL path the cookie applies to. Defaults to `/` (whole origin).\n */\n path?: string;\n /**\n * `SameSite` attribute. Defaults to `\"lax\"`; restrictive enough\n * to avoid CSRF on cross-origin POSTs, permissive enough for\n * top-level navigations.\n */\n sameSite?: \"lax\" | \"strict\" | \"none\";\n /**\n * `Secure` attribute. Defaults to `true` (cookies only sent over\n * HTTPS). Force `false` for local development on plain `http://`.\n */\n secure?: boolean;\n};\n\nconst DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;\n\nconst encode = (value: string): string => encodeURIComponent(value);\nconst decode = (value: string): string => decodeURIComponent(value);\n\nconst readCookies = (): Map<string, string> => {\n const out = new Map<string, string>();\n if (typeof document === \"undefined\") {\n return out;\n }\n const cookieString = document.cookie;\n if (!cookieString) {\n return out;\n }\n for (const segment of cookieString.split(\";\")) {\n const trimmed = segment.trim();\n if (!trimmed) {\n continue;\n }\n const eq = trimmed.indexOf(\"=\");\n if (eq === -1) {\n continue;\n }\n const name = trimmed.slice(0, eq);\n const raw = trimmed.slice(eq + 1);\n try {\n out.set(name, decode(raw));\n } catch {\n void 0;\n }\n }\n return out;\n};\n\nconst buildCookieString = (\n name: string,\n value: string,\n options: CookieDriverOptions,\n expired = false,\n): string => {\n const parts: Array<string> = [`${name}=${encode(value)}`, `Path=${options.path ?? \"/\"}`];\n if (options.domain !== undefined && options.domain !== \"\") {\n parts.push(`Domain=${options.domain}`);\n }\n if (expired) {\n parts.push(\"Max-Age=0\");\n } else {\n const maxAge = options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS;\n parts.push(`Max-Age=${maxAge}`);\n }\n parts.push(`SameSite=${options.sameSite ?? \"lax\"}`);\n if (options.secure ?? true) {\n parts.push(\"Secure\");\n }\n return parts.join(\"; \");\n};\n\nconst toCookieMap = (input: InitialCookies | undefined): Map<string, string> | null => {\n if (!input) {\n return null;\n }\n if (Symbol.iterator in input) {\n return new Map(input);\n }\n return new Map(Object.entries(input));\n};\n\n/**\n * Server-side writes are no-ops: `Set-Cookie` needs the framework's\n * response object. Cookies ride every request, so use this driver for\n * the `persistent` slot only and leave `session` on `sessionStorage`.\n */\nconst createCookieStorageDriver = (options: CookieDriverOptions = {}): StorageDriver => {\n const seeded = toCookieMap(options.initialCookies);\n\n if (typeof document === \"undefined\") {\n if (!seeded) {\n return {\n getItem() {\n return null;\n },\n removeItem() {},\n setItem() {},\n };\n }\n return {\n getItem(key) {\n return seeded.get(key) ?? null;\n },\n removeItem() {},\n setItem() {},\n };\n }\n return {\n getItem(key) {\n return readCookies().get(key) ?? null;\n },\n removeItem(key) {\n // eslint-disable-next-line unicorn/no-document-cookie -- cookie storage driver is the document.cookie abstraction by design\n document.cookie = buildCookieString(key, \"\", options, true);\n },\n setItem(key, value) {\n // eslint-disable-next-line unicorn/no-document-cookie -- cookie storage driver is the document.cookie abstraction by design\n document.cookie = buildCookieString(key, value, options);\n },\n };\n};\n\nexport type { CookieDriverOptions, InitialCookies };\nexport { createCookieStorageDriver };\n","import type { StoredPoolRecord, StoredSelectionRecord } from \"./persistence\";\nimport { decodePool, decodeSelection, storageKeys } from \"./validation\";\n\n/**\n * Carries no `Connector` by design: a wallet extension exists only in\n * the browser, so a server render can name the wallet and its address\n * but can never dispatch on it.\n */\ntype WalletSnapshot = {\n activeConnectorId: string | null;\n pool: StoredPoolRecord;\n selection: StoredSelectionRecord;\n};\n\ntype CookieSource =\n | Iterable<{ name: string; value: string }>\n | Iterable<[string, string]>\n | Readonly<Record<string, string>>;\n\ntype SnapshotOptions = {\n /**\n * Same prefix passed to `WalletManagerProvider` / `WalletStorage`.\n * Defaults to `\"butr\"` to match the library default.\n */\n keyPrefix?: string;\n};\n\nconst EMPTY_SNAPSHOT: WalletSnapshot = Object.freeze({\n activeConnectorId: null,\n pool: Object.freeze({}) as StoredPoolRecord,\n selection: Object.freeze({}) as StoredSelectionRecord,\n});\n\nconst toCookieMap = (input: CookieSource): Map<string, string> => {\n if (!(Symbol.iterator in input)) {\n return new Map(Object.entries(input));\n }\n const out = new Map<string, string>();\n for (const entry of input) {\n if (Array.isArray(entry)) {\n const [name, value] = entry;\n if (typeof name === \"string\" && typeof value === \"string\") {\n out.set(name, value);\n }\n continue;\n }\n if (typeof entry.name === \"string\" && typeof entry.value === \"string\") {\n out.set(entry.name, entry.value);\n }\n }\n return out;\n};\n\nconst SNAPSHOT_LABEL = \"[butr] readWalletSnapshot:\";\n\n/**\n * Optimistic: only what the browser last persisted, so an uninstall or\n * other-tab disconnect makes it stale. Authoritative once the entry\n * leaves `reconnectingIds`; `isHydrated` is true from render one.\n */\nconst readWalletSnapshot = (\n source: CookieSource,\n options: SnapshotOptions = {},\n): WalletSnapshot => {\n const keys = storageKeys(options.keyPrefix);\n const cookies = toCookieMap(source);\n\n const pool = decodePool(cookies.get(keys.pool), SNAPSHOT_LABEL);\n const selection = decodeSelection(cookies.get(keys.selection), SNAPSHOT_LABEL);\n\n const rawActive = cookies.get(keys.active);\n let activeConnectorId: string | null = null;\n if (rawActive !== undefined && rawActive.length > 0 && pool[rawActive] !== undefined) {\n activeConnectorId = rawActive;\n } else {\n const firstKey = Object.keys(pool)[0];\n if (firstKey) {\n activeConnectorId = firstKey;\n }\n }\n\n return { activeConnectorId, pool, selection };\n};\n\nexport type { CookieSource, SnapshotOptions, WalletSnapshot };\nexport { EMPTY_SNAPSHOT, readWalletSnapshot };\n","import type { ChainPlatform } from \"./types/platform\";\nimport { CHAIN_PLATFORMS } from \"./types/platform\";\n\n/**\n * A multi-chain wallet announces one adapter per platform, so brands\n * repeat in the flat list. Keys follow `CHAIN_PLATFORMS` order and empty\n * platforms are omitted, so `[...groups]` needs no emptiness filter.\n */\nconst groupByPlatform = <T>(\n items: ReadonlyArray<T>,\n getPlatform: (item: T) => ChainPlatform,\n): Map<ChainPlatform, Array<T>> => {\n const buckets = new Map<ChainPlatform, Array<T>>();\n for (const item of items) {\n const platform = getPlatform(item);\n const bucket = buckets.get(platform);\n if (bucket === undefined) {\n buckets.set(platform, [item]);\n } else {\n bucket.push(item);\n }\n }\n\n const ordered = new Map<ChainPlatform, Array<T>>();\n for (const platform of CHAIN_PLATFORMS) {\n const bucket = buckets.get(platform);\n if (bucket !== undefined) {\n ordered.set(platform, bucket);\n }\n }\n return ordered;\n};\n\nexport { groupByPlatform };\n","/**\n * Hex prefixing diverges by chain (bare for Bitcoin and Ledger, `0x` for\n * EVM and Polkadot), so the variants stay explicit: these sit on the\n * signing path, where a silent mismatch corrupts one chain's signatures.\n */\n\n/** Bitcoin/Solana alphabet; omits the visually ambiguous `0`, `O`, `I`, `l`. */\nconst BASE58_ALPHABET = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n\nconst BASE58_INDEX = new Map<string, number>();\nfor (let i = 0; i < BASE58_ALPHABET.length; i += 1) {\n BASE58_INDEX.set(BASE58_ALPHABET[i] ?? \"\", i);\n}\n\n/** Bare lowercase hex, no `0x` prefix (Bitcoin, Ledger). */\nconst bytesToHex = (bytes: Uint8Array): string => {\n let hex = \"\";\n for (const byte of bytes) {\n hex += byte.toString(16).padStart(2, \"0\");\n }\n return hex;\n};\n\n/** `0x`-prefixed lowercase hex (EVM, Polkadot). */\nconst bytesToHexPrefixed = (bytes: Uint8Array): string => `0x${bytesToHex(bytes)}`;\n\n/**\n * Decode hex (with or without a leading `0x`) into raw bytes. Throws on\n * odd-length input or non-hex characters rather than silently producing\n * `NaN`-filled bytes.\n */\nconst hexToBytes = (hex: string): Uint8Array => {\n const clean = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n if (clean.length % 2 !== 0) {\n throw new TypeError(\"Invalid hex: odd length\");\n }\n const out = new Uint8Array(clean.length / 2);\n for (let i = 0; i < out.length; i += 1) {\n const byte = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n if (Number.isNaN(byte)) {\n throw new TypeError(`Invalid hex character at offset ${i * 2}`);\n }\n out[i] = byte;\n }\n return out;\n};\n\n/**\n * Cross-platform base64 → `Uint8Array`. `atob` is available everywhere\n * butr runs (browsers, RN since Hermes, Node 16+, Bun, Deno).\n */\nconst base64ToBytes = (b64: string): Uint8Array => {\n const binary = atob(b64);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) {\n out[i] = binary.codePointAt(i) ?? 0;\n }\n return out;\n};\n\n/** Cross-platform `Uint8Array` → base64. */\nconst bytesToBase64 = (bytes: Uint8Array): string => {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCodePoint(byte);\n }\n return btoa(binary);\n};\n\n/**\n * `Uint8Array` → base58 (Solana addresses and signatures). Leading zero\n * bytes are significant in base58 and survive the BigInt round-trip only\n * because they're re-prefixed as `1`s afterwards.\n */\nconst bytesToBase58 = (bytes: Uint8Array): string => {\n let intVal = 0n;\n for (const byte of bytes) {\n intVal = (intVal << 8n) | BigInt(byte);\n }\n let out = \"\";\n while (intVal > 0n) {\n const remainder = intVal % 58n;\n intVal /= 58n;\n out = BASE58_ALPHABET[Number(remainder)] + out;\n }\n for (const byte of bytes) {\n if (byte !== 0) {\n break;\n }\n out = `1${out}`;\n }\n return out;\n};\n\n/** Decode base58 into raw bytes. Throws on characters outside the alphabet\n * rather than silently dropping them. */\nconst base58ToBytes = (input: string): Uint8Array => {\n let intVal = 0n;\n let leadingZeros = 0;\n let stillLeading = true;\n for (const char of input) {\n if (stillLeading && char === \"1\") {\n leadingZeros += 1;\n } else {\n stillLeading = false;\n }\n const digit = BASE58_INDEX.get(char);\n if (digit === undefined) {\n throw new Error(`Invalid base58 character \"${char}\"`);\n }\n intVal = intVal * 58n + BigInt(digit);\n }\n const bytes: Array<number> = [];\n const byteMask = 255n;\n while (intVal > 0n) {\n bytes.unshift(Number(intVal & byteMask));\n intVal >>= 8n;\n }\n for (let i = 0; i < leadingZeros; i += 1) {\n bytes.unshift(0);\n }\n return Uint8Array.from(bytes);\n};\n\nexport {\n base58ToBytes,\n base64ToBytes,\n bytesToBase58,\n bytesToBase64,\n bytesToHex,\n bytesToHexPrefixed,\n hexToBytes,\n};\n","import { bytesToBase64 } from \"../encoding/bytes\";\nimport type { Account, ConnectedWallet } from \"../types\";\n\n/**\n * Verify against `signedMessage`, not `message`: Solana Wallet Standard\n * wallets may prefix or re-encode what they sign. Base64 mirrors exist\n * because `Uint8Array` does not survive `JSON.stringify`.\n */\ntype SignInResult = {\n account: Account;\n /** The message handed to the wallet. Absent on the SIWS path, where the\n * wallet composes the message itself. */\n message?: string;\n nonce: string;\n signature: Uint8Array;\n /** Base64 of `signature`. */\n signatureBase64: string;\n signedMessage: Uint8Array;\n /** Base64 of `signedMessage`; verify against this. */\n signedMessageBase64: string;\n wallet: ConnectedWallet;\n};\n\ntype SignInMessageContext = {\n account: Account;\n nonce: string;\n wallet: ConnectedWallet;\n};\n\ntype SignInFlowOptions = {\n /**\n * butr ships no wire format: a server-parsed message is an auth spec,\n * and SIWE / SIWS already fill that role. Pass what your backend\n * expects. Unused on the SIWS path, where the wallet composes it.\n */\n buildMessage?: (ctx: SignInMessageContext) => string;\n /** Fetch a single-use nonce from your backend. */\n getNonce: (ctx: { account: Account; wallet: ConnectedWallet }) => Promise<string>;\n /**\n * Skip the Sign In With Solana path even on wallets that advertise it,\n * forcing every platform down the same `signMessage` route. Useful when\n * one backend verifier has to handle every chain identically.\n */\n preferSignMessage?: boolean;\n /** Hand the signed result to your backend. Throw to fail the flow. */\n verify: (result: SignInResult) => Promise<void>;\n};\n\n/** Thrown before any wallet interaction when the wallet can't sign at\n * all. Distinct from a rejection: nothing was asked of the user, so UI\n * should say \"this wallet can't sign in\" rather than \"you declined\". */\nclass SignInUnsupportedError extends Error {\n readonly connectorId: string;\n\n constructor(connectorId: string) {\n super(\n `Wallet \"${connectorId}\" reports capabilities.signMessage === false, so it cannot sign in.`,\n );\n this.connectorId = connectorId;\n this.name = \"SignInUnsupportedError\";\n }\n}\n\nconst defaultBuildMessage = ({ account, nonce }: SignInMessageContext): string =>\n `${account.walletAddress} signs in.\\nNonce: ${nonce}`;\n\n/**\n * Solana wallets advertising `solana:signIn` take the SIWS path, so\n * `result.signedMessage` holds the wallet-composed statement and\n * `result.message` is absent. `preferSignMessage` opts out.\n */\nconst createSignInFlow = (\n options: SignInFlowOptions,\n): { signIn: (wallet: ConnectedWallet, account?: Account) => Promise<SignInResult> } => {\n const buildMessage = options.buildMessage ?? defaultBuildMessage;\n\n const sign = async (wallet: ConnectedWallet, account?: Account): Promise<SignInResult> => {\n const { connector } = wallet;\n const signingAccount = account ?? wallet.account;\n\n if (!connector.capabilities.signMessage) {\n throw new SignInUnsupportedError(connector.id);\n }\n\n const nonce = await options.getNonce({ account: signingAccount, wallet });\n\n if (\n options.preferSignMessage !== true &&\n connector.chainPlatform === \"svm\" &&\n connector.capabilities.signIn &&\n connector.signIn !== undefined\n ) {\n const output = await connector.signIn({ nonce });\n return {\n account: output.account,\n nonce,\n signature: output.signature,\n signatureBase64: bytesToBase64(output.signature),\n signedMessage: output.signedMessage,\n signedMessageBase64: bytesToBase64(output.signedMessage),\n wallet,\n };\n }\n\n const message = buildMessage({ account: signingAccount, nonce, wallet });\n const { signature, signedMessage } = await connector.signMessage(\n new TextEncoder().encode(message),\n signingAccount,\n );\n\n return {\n account: signingAccount,\n message,\n nonce,\n signature,\n signatureBase64: bytesToBase64(signature),\n signedMessage,\n signedMessageBase64: bytesToBase64(signedMessage),\n wallet,\n };\n };\n\n return {\n signIn: async (wallet, account) => {\n const result = await sign(wallet, account);\n await options.verify(result);\n return result;\n },\n };\n};\n\nexport type { SignInFlowOptions, SignInMessageContext, SignInResult };\nexport { SignInUnsupportedError, createSignInFlow };\n","import type { ConnectedWallet } from \"./types\";\n\n/**\n * The adapter is compared by reference, not `connector.id`: hydration\n * swaps a shadow adapter for the live one under an unchanged id, and an\n * id check would strand consumers on the throwing placeholder.\n */\nconst walletEqual = (a: ConnectedWallet | undefined, b: ConnectedWallet | undefined): boolean => {\n if (a === b) {\n return true;\n }\n if (!a || !b) {\n return false;\n }\n return (\n a.connector === b.connector &&\n a.account.walletAddress === b.account.walletAddress &&\n a.account.chain.id === b.account.chain.id\n );\n};\n\nexport { walletEqual };\n","/**\n * Some wallets announce data-URI icons wrapped in whitespace, which\n * makes Next.js `<Image>` throw on a leading control character.\n * Discovery already applies this; only hand-built metadata needs it.\n */\nconst sanitizeIcon = (icon: string | undefined): string | undefined => {\n if (icon === undefined) {\n return undefined;\n }\n const trimmed = icon.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n};\n\nexport { sanitizeIcon };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["VALID_CHAIN_PLATFORMS","isChainPlatform","toCookieMap"],"sources":["../src/types/account.ts","../src/types/chains-by-platform.ts","../src/types/errors.ts","../src/types/platform.ts","../src/wallet-source.ts","../src/store/shadow-adapter.ts","../src/logger.ts","../src/storage/browser-storage-driver.ts","../src/storage/validation.ts","../src/storage/wallet-storage.ts","../src/store/connector-lifecycle.ts","../src/store/hydration.ts","../src/store/reducer.ts","../src/store/wallet-store-helpers.ts","../src/store/wallet-store.ts","../src/storage/cookie-storage-driver.ts","../src/storage/snapshot.ts","../src/group-by-platform.ts","../src/encoding/bytes.ts","../src/sign-in/sign-in-flow.ts","../src/wallet-equal.ts","../src/sanitize-icon.ts"],"sourcesContent":["import type { ChainBase } from \"./chain\";\n\ntype Account = {\n chain: ChainBase;\n id: string;\n walletAddress: string;\n};\n\n/**\n * The reducer compares accounts by the composite `<chain>:<address>`\n * id, so every adapter must build accounts here or reproduce that\n * format byte for byte.\n */\nconst buildAccount = (address: string, chain: ChainBase): Account => ({\n chain,\n id: `${chain.id}:${address}`,\n walletAddress: address,\n});\n\ntype Balance = {\n /** Token decimals (e.g. 9 for SOL, 18 for ETH) */\n decimals: number;\n /** Human-readable string, trimmed of trailing zeros */\n formatted: string;\n /** Token symbol (e.g. \"SOL\", \"ETH\") */\n symbol: string;\n /** Raw integer amount */\n value: bigint;\n};\n\nexport type { Account, Balance };\nexport { buildAccount };\n","import type { ChainBase } from \"./chain\";\nimport type { ChainPlatform } from \"./platform\";\n\n/**\n * Values come from the per-platform packages (`EVM_CHAINS_LIST`,\n * `SVM_CHAINS_LIST`, …); an empty list opts that platform out of the\n * consumer's chain UI.\n */\ntype ChainsByPlatform = Readonly<Record<ChainPlatform, ReadonlyArray<ChainBase>>>;\n\n/**\n * Naming only the platforms an app targets keeps the other packages'\n * chain registries out of its bundle. Apps that want all of them import\n * `CHAINS_BY_PLATFORM` from `@usebutr/wallets`.\n */\nconst buildChainsByPlatform = (partial: Partial<ChainsByPlatform>) =>\n ({\n bitcoin: partial.bitcoin ?? [],\n evm: partial.evm ?? [],\n polkadot: partial.polkadot ?? [],\n sui: partial.sui ?? [],\n svm: partial.svm ?? [],\n }) satisfies ChainsByPlatform;\n\nexport type { ChainsByPlatform };\nexport { buildChainsByPlatform };\n","/**\n * Wallet SDKs disagree on error shape (EIP-1193 codes, bare strings,\n * bespoke classes), so consumers branch on `kind` rather than regexing\n * messages. `cause` keeps the original value for the `Unknown` case.\n */\ntype ConnectionError =\n | { kind: \"UserRejected\"; message: string }\n | { kind: \"RequestPending\"; message: string }\n | { kind: \"WalletLocked\"; message: string }\n | { actualChain?: string; expectedChain?: string; kind: \"ChainMismatch\"; message: string }\n | { kind: \"NotConnected\"; message: string }\n | { kind: \"Timeout\"; message: string }\n | { cause?: ErrorCause; kind: \"Unknown\"; message: string };\n\ntype ConnectionErrorKind = ConnectionError[\"kind\"];\ntype ErrorCause = Error | string;\n\ntype CodedError = Error & { code: number | string };\n\nconst isCodedError = (error: Error): error is CodedError => \"code\" in error;\n\nconst toErrorCause = (value: ErrorCause): ErrorCause => value;\n\n/**\n * EIP-1193 codes: `4001` rejected, `-32002` pending, `4100`/`4900`/`4901`\n * unauthorized or disconnected. Message-substring matching is the last\n * resort for SDKs that ship no codes at all.\n */\nconst mapConnectionError = (raw: ErrorCause): ConnectionError => {\n if (raw instanceof Error) {\n const message = raw.message;\n const lower = message.toLowerCase();\n\n if (message === \"Connection timeout\") {\n return { kind: \"Timeout\", message };\n }\n if (message === \"Failed to get account\" || lower.includes(\"not connected\")) {\n return { kind: \"NotConnected\", message };\n }\n\n const code = isCodedError(raw) ? raw.code : undefined;\n if (code === 4001) {\n return { kind: \"UserRejected\", message };\n }\n if (code === -32_002) {\n return { kind: \"RequestPending\", message };\n }\n if (code === 4100 || code === 4900 || code === 4901) {\n return { kind: \"NotConnected\", message };\n }\n\n if (lower.includes(\"user rejected\") || lower.includes(\"user denied\")) {\n return { kind: \"UserRejected\", message };\n }\n if (lower.includes(\"locked\")) {\n return { kind: \"WalletLocked\", message };\n }\n if (lower.includes(\"chain\") && (lower.includes(\"mismatch\") || lower.includes(\"unsupported\"))) {\n return { kind: \"ChainMismatch\", message };\n }\n\n return { cause: raw, kind: \"Unknown\", message };\n }\n\n if (typeof raw === \"string\") {\n return { kind: \"Unknown\", message: raw };\n }\n\n return { cause: raw, kind: \"Unknown\", message: \"Connection failed\" };\n};\n\nexport type { CodedError, ConnectionError, ConnectionErrorKind, ErrorCause };\nexport { mapConnectionError, toErrorCause };\n","/**\n * Single runtime source of truth: `ChainPlatform` and the storage\n * validators' allowlists both derive from it. Omitting a platform here\n * silently stops its connections from persisting.\n */\nconst CHAIN_PLATFORMS = [\"evm\", \"svm\", \"sui\", \"bitcoin\", \"polkadot\"] as const;\n\ntype ChainPlatform = (typeof CHAIN_PLATFORMS)[number];\n\nexport type { ChainPlatform };\nexport { CHAIN_PLATFORMS };\n","import type { WalletAdapter } from \"./types\";\n\n/**\n * The discovery seam: implementable by third parties without depending\n * on `@usebutr/wallets`, which itself just composes the per-platform\n * sources into one.\n */\ntype WalletSource = {\n subscribe: (onAdapter: (adapter: WalletAdapter) => void) => () => void;\n};\n\n/**\n * Takes the exact shape of `discoverEvmAdapters` and friends, so a\n * single-platform app keeps `@usebutr/wallets` out of its bundle.\n */\nconst createWalletSource = (\n subscribe: (onAdapter: (adapter: WalletAdapter) => void) => () => void,\n): WalletSource => ({ subscribe });\n\nexport type { WalletSource };\nexport { createWalletSource };\n","import type { StoredPoolEntry } from \"../storage/persistence\";\nimport type { CodedError, WalletAdapter, WalletCapabilities } from \"../types\";\n\n/**\n * Loud failure for consumers that called a wallet method without gating\n * on `capabilities.*` (all `false` here) or `reconnectingIds`, before\n * silent reconnect swapped in the live adapter.\n */\nclass ShadowConnectorError extends Error implements CodedError {\n readonly code = \"BUTR_RECONNECTING\";\n readonly connectorId: string;\n readonly method: string;\n constructor(method: string, connectorId: string) {\n super(\n `[butr] ${method} called on shadow connector \"${connectorId}\". Wait for silent reconnect to complete (check reconnectingIds.has(id) before calling).`,\n );\n this.name = \"ShadowConnectorError\";\n this.connectorId = connectorId;\n this.method = method;\n }\n}\n\nconst ALL_FALSE_CAPABILITIES: WalletCapabilities = Object.freeze({\n getBalance: false,\n getTransactionReceipt: false,\n requestAccounts: false,\n sendTransaction: false,\n signIn: false,\n signMessage: false,\n signTransaction: false,\n subscribe: false,\n switchAccount: false,\n switchChain: false,\n});\n\n/**\n * Lets `createWalletStore` flip `isHydrated` synchronously from\n * `initialState`; the hydration coordinator later swaps each shadow for\n * a live adapter, or drops the entry from pool and storage.\n */\nconst createShadowAdapter = (entry: StoredPoolEntry): WalletAdapter => {\n const id = entry.connectorId;\n const name = entry.name;\n const icon = entry.icon;\n\n const reject = (method: string): Promise<never> =>\n Promise.reject(new ShadowConnectorError(method, id));\n\n const base = {\n capabilities: ALL_FALSE_CAPABILITIES,\n connect: () => reject(\"connect\"),\n disconnect: () => reject(\"disconnect\"),\n getAccount: () => reject(\"getAccount\"),\n getBalance: () => reject(\"getBalance\"),\n getSigner: () => reject(\"getSigner\"),\n getTransactionReceipt: () => reject(\"getTransactionReceipt\"),\n icon,\n id,\n name,\n sendTx: () => reject(\"sendTx\"),\n sendTxToChain: () => reject(\"sendTxToChain\"),\n signMessage: () => reject(\"signMessage\"),\n switchChain: () => reject(\"switchChain\"),\n };\n\n switch (entry.chainPlatform) {\n case \"bitcoin\": {\n return { ...base, chainPlatform: \"bitcoin\" };\n }\n case \"evm\": {\n return { ...base, chainPlatform: \"evm\" };\n }\n case \"sui\": {\n return { ...base, chainPlatform: \"sui\" };\n }\n case \"svm\": {\n return { ...base, chainPlatform: \"svm\" };\n }\n case \"polkadot\": {\n return { ...base, chainPlatform: \"polkadot\" };\n }\n default: {\n const _exhaustive: never = entry.chainPlatform;\n void _exhaustive;\n throw new Error(`[butr] unknown chainPlatform: ${String(entry.chainPlatform)}`);\n }\n }\n};\n\n/**\n * Structural detection: relies on every live adapter advertising at\n * least one capability, since `getBalance`, `signMessage` and\n * `switchChain` are required on all wallet surfaces.\n */\nconst isShadowAdapter = (adapter: WalletAdapter): boolean => {\n return Object.values(adapter.capabilities).every((flag) => !flag);\n};\n\nexport { createShadowAdapter, isShadowAdapter, ShadowConnectorError };\n","/* eslint-disable no-console -- central logging sink; the one sanctioned console use */\nconst logWarn = (...args: ReadonlyArray<unknown>): void => {\n console.warn(...args);\n};\n\nconst logError = (...args: ReadonlyArray<unknown>): void => {\n console.error(...args);\n};\n/* eslint-enable no-console */\n\nexport { logError, logWarn };\n","import type { StorageDriver } from \"./persistence\";\n\ntype BrowserStorageDrivers = {\n /** Survives app restart (localStorage on web, AsyncStorage/MMKV on RN). */\n persistent: StorageDriver;\n /** Cleared when the app session ends (sessionStorage on web, in-memory on RN). */\n session: StorageDriver;\n};\n\ntype WebStorageKind = \"localStorage\" | \"sessionStorage\";\n\nconst hasWebStorage = (kind: WebStorageKind): boolean => {\n try {\n return kind === \"localStorage\"\n ? globalThis.localStorage !== undefined\n : globalThis.sessionStorage !== undefined;\n } catch {\n return false;\n }\n};\n\nconst createMemoryStorageDriver = (): StorageDriver => {\n const memory = new Map<string, string>();\n return {\n getItem(key) {\n return memory.get(key) ?? null;\n },\n removeItem(key) {\n memory.delete(key);\n },\n setItem(key, value) {\n memory.set(key, value);\n },\n };\n};\n\nconst createWebStorageDriver = (kind: WebStorageKind): StorageDriver => {\n if (!hasWebStorage(kind)) {\n return createMemoryStorageDriver();\n }\n\n const storage = kind === \"localStorage\" ? globalThis.localStorage : globalThis.sessionStorage;\n\n return {\n getItem(key) {\n try {\n return storage.getItem(key);\n } catch {\n return null;\n }\n },\n removeItem(key) {\n try {\n storage.removeItem(key);\n } catch {\n void 0;\n }\n },\n setItem(key, value) {\n try {\n storage.setItem(key, value);\n } catch {\n void 0;\n }\n },\n };\n};\n\n/**\n * Default storage drivers for web. `persistent` wraps `localStorage`,\n * `session` wraps `sessionStorage`. Both fall back to in-memory maps\n * when the global isn't available (SSR, non-browser environments).\n */\nconst createBrowserStorageDriver = (): BrowserStorageDrivers => ({\n persistent: createWebStorageDriver(\"localStorage\"),\n session: createWebStorageDriver(\"sessionStorage\"),\n});\n\nexport type { BrowserStorageDrivers };\nexport { createBrowserStorageDriver, createMemoryStorageDriver };\n","import { z } from \"zod\";\n\nimport { logWarn } from \"../logger\";\nimport { CHAIN_PLATFORMS } from \"../types/platform\";\n\nimport type { StoredPoolEntry, StoredPoolRecord, StoredSelectionRecord } from \"./persistence\";\n\nconst chainPlatformSchema = z.enum(CHAIN_PLATFORMS);\n\nconst chainSchema = z.looseObject({\n id: z.string(),\n name: z.string(),\n namespace: z.string(),\n reference: z.string(),\n});\n\nconst accountSchema = z.looseObject({\n chain: chainSchema,\n id: z.string(),\n walletAddress: z.string(),\n});\n\nconst storedPoolEntrySchema = z.looseObject({\n account: accountSchema,\n accounts: z.array(accountSchema),\n chainPlatform: chainPlatformSchema,\n connectorId: z.string(),\n icon: z.string().optional(),\n name: z.string().min(1),\n});\n\nconst recordSchema = z.record(z.string(), z.unknown());\n\nconst parseStoredPoolEntry = (key: string, value: StoredPoolEntry) => {\n const parsed = storedPoolEntrySchema.safeParse(value);\n if (!parsed.success || parsed.data.connectorId !== key) {\n return null;\n }\n return parsed.data;\n};\n\nconst DEFAULT_KEY_PREFIX = \"butr\";\n\n/**\n * `WalletStorage` writes these and `readWalletSnapshot` reads them from\n * a cookie jar; any divergence desyncs the SSR-seeded render from the\n * client that rehydrates it, the failure ADR 0003 exists to prevent.\n */\nconst storageKeys = (keyPrefix?: string) => {\n const prefix = keyPrefix === undefined || keyPrefix === \"\" ? DEFAULT_KEY_PREFIX : keyPrefix;\n return {\n active: `${prefix}-active`,\n pool: `${prefix}-pool`,\n selection: `${prefix}-selection`,\n userDisconnected: `${prefix}-user-disconnected`,\n };\n};\n\n/**\n * Never repairs or throws: one corrupt entry must not take down a whole\n * session, and `readWalletSnapshot` may run on a server with no cookie\n * jar to write the eviction to.\n */\nconst decodePool = (raw: string | null | undefined, label = \"[butr]\"): StoredPoolRecord => {\n if (raw === null || raw === undefined || raw === \"\") {\n return {};\n }\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch (error) {\n logWarn(`${label} failed to parse pool from storage:`, error);\n return {};\n }\n const parsed = recordSchema.safeParse(value);\n if (!parsed.success) {\n return {};\n }\n const result: StoredPoolRecord = {};\n for (const [key, entryValue] of Object.entries(parsed.data)) {\n const candidate = storedPoolEntrySchema.safeParse(entryValue);\n const entry = candidate.success ? parseStoredPoolEntry(key, candidate.data) : null;\n if (entry === null) {\n logWarn(`${label} dropping invalid pool entry for ${key}`);\n } else {\n result[key] = entry;\n }\n }\n return result;\n};\n\n/** Decode a persisted selection payload. Same contract as `decodePool`. */\nconst decodeSelection = (\n raw: string | null | undefined,\n label = \"[butr]\",\n): StoredSelectionRecord => {\n if (raw === null || raw === undefined || raw === \"\") {\n return {};\n }\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch (error) {\n logWarn(`${label} failed to parse selection from storage:`, error);\n return {};\n }\n const parsed = recordSchema.safeParse(value);\n if (!parsed.success) {\n return {};\n }\n const result: StoredSelectionRecord = {};\n for (const [key, selectionValue] of Object.entries(parsed.data)) {\n const platform = chainPlatformSchema.safeParse(key);\n if (platform.success && typeof selectionValue === \"string\" && selectionValue.length > 0) {\n result[platform.data] = selectionValue;\n }\n }\n return result;\n};\n\nexport { decodePool, decodeSelection, parseStoredPoolEntry, storageKeys };\n","import { logWarn } from \"../logger\";\nimport type { ChainPlatform, ConnectedWallet } from \"../types\";\n\nimport { createBrowserStorageDriver } from \"./browser-storage-driver\";\nimport type {\n StorageDriver,\n StoredPoolEntry,\n StoredPoolRecord,\n StoredSelectionRecord,\n WalletPersistence,\n} from \"./persistence\";\nimport { decodePool, decodeSelection, parseStoredPoolEntry, storageKeys } from \"./validation\";\n\ntype StorageConfig = {\n /** Defaults to `\"butr\"`, matching `readWalletSnapshot`. */\n keyPrefix?: string;\n /** Survives app restart. Defaults to localStorage on web. */\n persistent?: StorageDriver;\n /** Cleared on session end. Defaults to sessionStorage on web. */\n session?: StorageDriver;\n};\n\nclass WalletStorage implements WalletPersistence {\n private readonly poolKey: string;\n private readonly selectionKey: string;\n private readonly activeKey: string;\n private readonly userDisconnectedKey: string;\n private readonly persistent: StorageDriver;\n private readonly session: StorageDriver;\n /**\n * Serializes pool read-modify-writes; without it concurrent `setPool`\n * calls drop each other's entries. Not reentrant, so a queued mutation\n * must read via `readPool`: `getPool` re-enters and deadlocks it.\n */\n private poolMutationQueue: Promise<unknown> = Promise.resolve();\n\n constructor(config: StorageConfig) {\n const keys = storageKeys(config.keyPrefix);\n this.poolKey = keys.pool;\n this.selectionKey = keys.selection;\n this.activeKey = keys.active;\n this.userDisconnectedKey = keys.userDisconnected;\n\n if (config.persistent && config.session) {\n this.persistent = config.persistent;\n this.session = config.session;\n } else {\n const defaults = createBrowserStorageDriver();\n this.persistent = config.persistent ?? defaults.persistent;\n this.session = config.session ?? defaults.session;\n }\n }\n\n /** Chain `fn` after the in-flight pool mutation. */\n private async serializePoolMutation<T>(fn: () => Promise<T>): Promise<T> {\n const previous = this.poolMutationQueue;\n // oxlint-disable-next-line unicorn/consistent-function-scoping -- assigned by Promise constructor below\n let resolve: () => void = () => {};\n this.poolMutationQueue = new Promise<void>((r) => {\n resolve = r;\n });\n try {\n await previous;\n } catch {\n // Previous mutation's failure shouldn't jam the queue; each\n // call site already observes its own rejection.\n }\n try {\n return await fn();\n } finally {\n resolve();\n }\n }\n\n /** Read and decode the pool without touching the mutation queue. Safe to\n * call from inside a queued mutation, unlike `getPool`. */\n private async readPool(): Promise<{ corrupt: boolean; decoded: StoredPoolRecord }> {\n let stored: string | null;\n try {\n stored = await this.persistent.getItem(this.poolKey);\n } catch (error) {\n logWarn(\"[butr] failed to read pool from storage:\", error);\n return { corrupt: false, decoded: {} };\n }\n if (stored === null || stored === \"\") {\n return { corrupt: false, decoded: {} };\n }\n const decoded = decodePool(stored);\n // An empty decode from a non-empty payload means the whole record was\n // unreadable, not that the user has no wallets.\n return { corrupt: Object.keys(decoded).length === 0, decoded };\n }\n\n async getPool(): Promise<StoredPoolRecord> {\n const { corrupt, decoded } = await this.readPool();\n if (corrupt) {\n // Evict the unreadable key directly. Going through `clearPool` would\n // acquire the mutation queue, which self-deadlocks when a queued\n // mutation is what triggered this read.\n try {\n await this.persistent.removeItem(this.poolKey);\n } catch (error) {\n logWarn(\"[butr] failed to clear corrupt pool:\", error);\n }\n }\n return decoded;\n }\n\n /**\n * Additive on purpose: a failed silent reconnect drops the entry from\n * the live pool, and it must survive to be retried next load.\n * Eviction goes through `removePoolEntry` or `clearAll`.\n */\n async setPool(pool: Map<string, ConnectedWallet>): Promise<void> {\n await this.serializePoolMutation(async () => {\n try {\n const { decoded: existing } = await this.readPool();\n const serializable: StoredPoolRecord = { ...existing };\n for (const [connectorId, wallet] of pool) {\n const entry: StoredPoolEntry = {\n account: wallet.account,\n accounts: wallet.accounts,\n chainPlatform: wallet.connector.chainPlatform,\n connectorId,\n icon: wallet.connector.icon,\n name: wallet.connector.name,\n };\n if (parseStoredPoolEntry(connectorId, entry) === null) {\n throw new Error(`[butr] refusing to persist invalid pool entry for ${connectorId}`);\n }\n serializable[connectorId] = entry;\n }\n await this.persistent.setItem(this.poolKey, JSON.stringify(serializable));\n } catch (error) {\n logWarn(\"[butr] failed to persist pool:\", error);\n }\n });\n }\n\n async removePoolEntry(connectorId: string): Promise<void> {\n await this.serializePoolMutation(async () => {\n try {\n const { decoded: stored } = await this.readPool();\n if (stored[connectorId]) {\n const { [connectorId]: _, ...remaining } = stored;\n await this.persistent.setItem(this.poolKey, JSON.stringify(remaining));\n }\n } catch (error) {\n logWarn(`[butr] failed to remove pool entry ${connectorId}:`, error);\n }\n });\n }\n\n async clearPool(): Promise<void> {\n await this.serializePoolMutation(async () => {\n await this.persistent.removeItem(this.poolKey);\n });\n }\n\n async getSelection(): Promise<StoredSelectionRecord> {\n try {\n return decodeSelection(await this.persistent.getItem(this.selectionKey));\n } catch (error) {\n logWarn(\"[butr] failed to read selection from storage:\", error);\n return {};\n }\n }\n\n async setSelection(selection: Map<ChainPlatform, string>): Promise<void> {\n try {\n const serializable: StoredSelectionRecord = {};\n for (const [platform, connectorId] of selection) {\n serializable[platform] = connectorId;\n }\n await this.persistent.setItem(this.selectionKey, JSON.stringify(serializable));\n } catch (error) {\n logWarn(\"[butr] failed to persist selection:\", error);\n }\n }\n\n async getActiveConnectorId(): Promise<string | null> {\n try {\n const value = await this.persistent.getItem(this.activeKey);\n return value !== null && value.length > 0 ? value : null;\n } catch {\n return null;\n }\n }\n\n async setActiveConnectorId(connectorId: string | null): Promise<void> {\n try {\n await (connectorId === null\n ? this.persistent.removeItem(this.activeKey)\n : this.persistent.setItem(this.activeKey, connectorId));\n } catch (error) {\n logWarn(\"[butr] failed to persist active connector id:\", error);\n }\n }\n\n async clearAll(): Promise<void> {\n await Promise.all([\n this.clearPool(),\n this.persistent.removeItem(this.selectionKey),\n this.persistent.removeItem(this.activeKey),\n ]);\n }\n\n /**\n * Kept in the session driver so it survives remounts (unlike a ref)\n * yet clears at session end (unlike the persistent driver): a manual\n * disconnect must suppress auto-connect now, not forever.\n */\n async isUserDisconnected(): Promise<boolean> {\n try {\n const value = await this.session.getItem(this.userDisconnectedKey);\n return value === \"true\";\n } catch {\n return false;\n }\n }\n\n async markUserDisconnected(value: boolean): Promise<void> {\n try {\n await (value\n ? this.session.setItem(this.userDisconnectedKey, \"true\")\n : this.session.removeItem(this.userDisconnectedKey));\n } catch {\n void 0;\n }\n }\n}\n\nexport { WalletStorage };\n","import { logWarn } from \"../logger\";\nimport type { Account, ChainPlatform, Connector } from \"../types\";\n\n/**\n * The bridge owns event-to-handler mapping and the unsubscribe handle;\n * the runtime owns the effects (dispatch, persist, consumer callbacks).\n */\ntype LifecycleHandlers = {\n /** Wallet exposed a new accounts list (or active account swap). The\n * bridge forwards the full array; single-account wallets included.\n * `active` is the address the wallet picked as current. */\n onAccountChanged: (\n connectorId: string,\n accounts: ReadonlyArray<Account>,\n active: Account,\n ) => void;\n /** Wallet disconnected externally (user locked, extension removed,\n * WC session ended on the relay). The bridge has already cleared\n * the subscription for `connectorId` by the time this fires. */\n onDisconnected: (connectorId: string, chainPlatform: ChainPlatform) => void;\n};\n\n/**\n * Owns the \"exactly one subscription per connector\" invariant for the\n * whole runtime; nothing else may call `connector.subscribe`.\n */\ntype ConnectorLifecycle = {\n /**\n * Idempotent: a second `attach` for the same id detaches the previous\n * subscription first. No-op for connectors without `subscribe`.\n */\n attach: (connectorId: string, connector: Connector) => void;\n /** Detach a single connector. Safe to call when no subscription is\n * registered. */\n detach: (connectorId: string) => void;\n /** Detach every active subscription. Used during `reset`. */\n detachAll: () => void;\n};\n\nconst createConnectorLifecycle = (handlers: LifecycleHandlers): ConnectorLifecycle => {\n const unsubscribers = new Map<string, () => void>();\n\n const detach = (connectorId: string) => {\n const unsub = unsubscribers.get(connectorId);\n if (!unsub) {\n return;\n }\n try {\n unsub();\n } catch (error: unknown) {\n logWarn(\"[butr] unsubscribe threw:\", error);\n }\n unsubscribers.delete(connectorId);\n };\n\n return {\n attach: (connectorId, connector) => {\n if (!connector.subscribe) {\n return;\n }\n detach(connectorId);\n try {\n const unsub = connector.subscribe((event) => {\n switch (event.type) {\n case \"accountChanged\": {\n handlers.onAccountChanged(connectorId, event.accounts, event.account);\n break;\n }\n case \"disconnected\": {\n detach(connectorId);\n handlers.onDisconnected(connectorId, connector.chainPlatform);\n break;\n }\n default: {\n const exhaustiveCheck: never = event;\n void exhaustiveCheck;\n }\n }\n });\n unsubscribers.set(connectorId, unsub);\n } catch (error: unknown) {\n logWarn(`[butr] subscribe failed for ${connectorId}:`, error);\n }\n },\n\n detach,\n\n detachAll: () => {\n const ids: Array<string> = [];\n for (const id of unsubscribers.keys()) {\n ids.push(id);\n }\n for (const id of ids) {\n detach(id);\n }\n },\n };\n};\n\nexport type { ConnectorLifecycle, LifecycleHandlers };\nexport { createConnectorLifecycle };\n","import type { StoredPoolEntry, WalletPersistence } from \"../storage\";\nimport type {\n Account,\n ChainPlatform,\n ConnectedWallet,\n Connector,\n WalletAdapter,\n WalletManagerConfig,\n} from \"../types\";\nimport type { ErrorCause } from \"../types/errors\";\nimport { toErrorCause } from \"../types/errors\";\nimport { CHAIN_PLATFORMS } from \"../types/platform\";\n\nconst VALID_CHAIN_PLATFORMS: ReadonlySet<string> = new Set(CHAIN_PLATFORMS);\n\nconst isChainPlatform = (value: string): value is ChainPlatform => VALID_CHAIN_PLATFORMS.has(value);\n\n/**\n * Restore outcome for a single pool entry. `kind: \"ok\"` carries the\n * fully-formed `ConnectedWallet`. `kind: \"fail\"` carries the raw error\n * so the caller can route it to telemetry.\n */\ntype RestoreOutcome =\n | { connectorId: string; entry: ConnectedWallet; kind: \"ok\" }\n | { connectorId: string; error: ErrorCause; kind: \"fail\" };\n\n/**\n * Snapshot returned by `HydrationCoordinator.hydrate()`; everything\n * the reducer needs to compose a `HYDRATED` event plus the metadata the\n * runtime uses to wire subscriptions and surface the outcome.\n */\ntype HydrateResult = {\n activeConnectorId: string | null;\n /** Entries whose restore failed (connect() rejected, the connector\n * threw mid-flight). Reported for telemetry only; storage is\n * preserved so the next load can retry. The most common cause is\n * EIP-1193 `eth_accounts: []` from a locked wallet, which clears as\n * soon as the user unlocks and reloads. */\n dropped: Array<{ connectorId: string; reason: ErrorCause }>;\n isUserDisconnected: boolean;\n /** Entries parked because `createConnector(id)` returned `null` at\n * hydration time (typical for Wallet Standard adapters announced\n * asynchronously). The coordinator keeps an internal record of these\n * and resolves them when the runtime later calls `drainPending`. */\n pendingIds: Array<string>;\n pool: Map<string, ConnectedWallet>;\n selection: Map<ChainPlatform, string>;\n};\n\ntype HydrationCoordinator = {\n /** Storage cleanup on a `fail` outcome is handled internally; the\n * caller only routes the error. */\n drainPending: (connectorId: string) => Promise<RestoreOutcome | null>;\n /** Entries whose adapter is not registered yet are parked, not\n * dropped; the caller must drain them via `drainPending` or those\n * wallets never reconnect. */\n hydrate: () => Promise<HydrateResult>;\n /** Read once right after `hydrate()` resolves, to catch adapters that\n * announced during the hydration window. */\n pendingIds: () => Array<string>;\n};\n\n/** Pick the right `accounts` list: fresh from the connector if it\n * exposes `getAccounts`, otherwise the persisted list, otherwise just\n * the active account. */\nconst resolveHydratedAccounts = async (\n connector: Connector,\n storedAccounts: ReadonlyArray<Account>,\n fallbackAccount: Account,\n): Promise<Array<Account>> => {\n if (connector.getAccounts) {\n const fresh = await connector.getAccounts().catch(() => null);\n if (fresh && fresh.length > 0) {\n return fresh;\n }\n }\n if (storedAccounts.length > 0) {\n return [...storedAccounts];\n }\n return [fallbackAccount];\n};\n\nconst restoreOneEntry = async (\n connectorId: string,\n entry: { account: Account; accounts: ReadonlyArray<Account> },\n connector: WalletAdapter,\n): Promise<RestoreOutcome> => {\n try {\n await connector.connect({ silent: true });\n const freshAccount = await connector.getAccount();\n const accountToUse = freshAccount ?? entry.account;\n const accounts = await resolveHydratedAccounts(connector, entry.accounts, accountToUse);\n return {\n connectorId,\n entry: {\n account: accountToUse,\n accounts,\n connector,\n },\n kind: \"ok\",\n };\n } catch (error) {\n return {\n connectorId,\n error: toErrorCause(error instanceof Error ? error : String(error)),\n kind: \"fail\",\n };\n }\n};\n\nconst createHydrationCoordinator = (\n storage: WalletPersistence,\n createConnector: WalletManagerConfig[\"createConnector\"],\n): HydrationCoordinator => {\n const pending = new Map<string, StoredPoolEntry>();\n\n return {\n drainPending: async (connectorId) => {\n const entry = pending.get(connectorId);\n if (!entry) {\n return null;\n }\n const connector = createConnector(connectorId);\n if (!connector) {\n return null;\n }\n const outcome = await restoreOneEntry(connectorId, entry, connector);\n pending.delete(connectorId);\n return outcome;\n },\n\n hydrate: async () => {\n const [storedPool, storedSelection, storedActive, userDisconnected] = await Promise.all([\n storage.getPool(),\n storage.getSelection(),\n storage.getActiveConnectorId(),\n storage.isUserDisconnected(),\n ]);\n\n const pool = new Map<string, ConnectedWallet>();\n const dropped: Array<{ connectorId: string; reason: ErrorCause }> = [];\n\n pending.clear();\n\n const tasks: Array<Promise<RestoreOutcome>> = [];\n for (const [connectorId, entry] of Object.entries(storedPool)) {\n if (!entry) {\n continue;\n }\n const connector = createConnector(connectorId);\n if (!connector) {\n pending.set(connectorId, entry);\n continue;\n }\n tasks.push(restoreOneEntry(connectorId, entry, connector));\n }\n\n const outcomes = await Promise.all(tasks);\n for (const outcome of outcomes) {\n if (outcome.kind === \"ok\") {\n pool.set(outcome.connectorId, outcome.entry);\n continue;\n }\n dropped.push({ connectorId: outcome.connectorId, reason: outcome.error });\n }\n\n const selection = new Map<ChainPlatform, string>();\n for (const [platform, connectorId] of Object.entries(storedSelection)) {\n if (isChainPlatform(platform) && connectorId !== undefined && pool.has(connectorId)) {\n selection.set(platform, connectorId);\n }\n }\n for (const [connectorId, wallet] of pool) {\n const platform = wallet.connector.chainPlatform;\n if (!selection.has(platform)) {\n selection.set(platform, connectorId);\n }\n }\n\n let activeConnectorId: string | null = null;\n if (storedActive !== null && pool.has(storedActive)) {\n activeConnectorId = storedActive;\n } else if (pool.size > 0) {\n activeConnectorId = pool.keys().next().value ?? null;\n }\n\n return {\n activeConnectorId,\n dropped,\n isUserDisconnected: userDisconnected,\n pendingIds: [...pending.keys()],\n pool,\n selection,\n };\n },\n\n pendingIds: () => [...pending.keys()],\n };\n};\n\nexport type { HydrateResult, HydrationCoordinator, RestoreOutcome };\nexport { createHydrationCoordinator };\n","import type { Account, ChainPlatform, ConnectedWallet } from \"../types\";\nimport type { ConnectionError } from \"../types/errors\";\n\n/**\n * The reducer never writes `\"reconnecting\"`; `useConnectionStatus`\n * derives it from `reconnectingIds` so the state machine stays narrow\n * while the public vocabulary matches wagmi's.\n */\ntype ConnectionStatus = \"idle\" | \"connecting\" | \"success\" | \"error\" | \"reconnecting\";\n\ntype State = {\n activeConnectorId: string | null;\n connectingConnectorId: string | null;\n connectionError: ConnectionError | null;\n connectionStatus: ConnectionStatus;\n isHydrated: boolean;\n isUserDisconnected: boolean;\n pool: Map<string, ConnectedWallet>;\n /**\n * Ids still backed by a shadow adapter from `initialState`. Empty\n * without `initialState`; shrinks on `HYDRATED` / `CONNECT_SUCCEEDED`\n * and on `DISCONNECTED` / `RESET`.\n */\n reconnectingIds: ReadonlySet<string>;\n selection: Map<ChainPlatform, string>;\n};\n\n/**\n * Lifecycle events: hydration, full reset, and the explicit\n * user-disconnected flag the runtime sets to suppress eager reconnect.\n */\ntype LifecycleEvent =\n | {\n activeConnectorId: string | null;\n /** Connector ids that were seeded from `initialState` but whose silent\n * reconnect failed. Their pool entries are still shadow-backed, so they\n * are evicted rather than left permanently unusable. */\n dropped: ReadonlyArray<string>;\n isUserDisconnected: boolean;\n pool: Map<string, ConnectedWallet>;\n selection: Map<ChainPlatform, string>;\n type: \"HYDRATED\";\n }\n | { type: \"RESET\" }\n | { type: \"USER_DISCONNECTED_SET\"; value: boolean };\n\n/**\n * None of these mutate the pool; `CONNECT_SUCCEEDED` is the only bridge\n * across to `PoolMutationEvent`.\n */\ntype ConnectionStatusEvent =\n | { connectorId: string; type: \"CONNECT_STARTED\" }\n | { connectorId: string; entry: ConnectedWallet; type: \"CONNECT_SUCCEEDED\" }\n | { connectorId: string; error: ConnectionError; type: \"CONNECT_FAILED\" }\n | { error: ConnectionError | null; type: \"ERROR_SET\" }\n | { type: \"STATUS_RESET\" };\n\n/**\n * Pool-mutation events: changes to the set of connected wallets and\n * their per-wallet account lists. `DISCONNECTED` removes an entry;\n * the refresh events update an existing one in-place.\n */\ntype PoolMutationEvent =\n | {\n /**\n * Deliberately not `CONNECT_SUCCEEDED`: discovery fires this at an\n * arbitrary time, so it must not overwrite the connect-attempt\n * status that the user's own action owns.\n */\n connectorId: string;\n entry: ConnectedWallet;\n type: \"ENTRY_RESTORED\";\n }\n | {\n /** When set, becomes the new active account. Used by paths that\n * know which account should be active (wallet event, manual\n * update). When unset, the reducer preserves the current active\n * if it's still in `accounts`, else picks `accounts[0]`. */\n accounts: Array<Account>;\n active?: Account;\n connectorId: string;\n type: \"ACCOUNTS_REFRESHED\";\n }\n | { connectorId: string; type: \"DISCONNECTED\" }\n | { connectorId: string; type: \"WALLET_REFRESHED\" };\n\n/**\n * Selection events: which connector is active, and which connector\n * serves each chain platform. Pure pointer updates; no pool mutation.\n */\ntype SelectionEvent =\n | { chainPlatform: ChainPlatform; connectorId: string | null; type: \"SELECTION_CHANGED\" }\n | { connectorId: string | null; type: \"ACTIVE_CHANGED\" };\n\n/**\n * The single event type the reducer dispatches on. Grouped above by\n * concern so a reader sees the map before the cases; adding an event\n * means picking the group it belongs to.\n */\ntype Event = ConnectionStatusEvent | LifecycleEvent | PoolMutationEvent | SelectionEvent;\n\nconst initialState: State = {\n activeConnectorId: null,\n connectingConnectorId: null,\n connectionError: null,\n connectionStatus: \"idle\",\n isHydrated: false,\n isUserDisconnected: false,\n pool: new Map(),\n reconnectingIds: new Set(),\n selection: new Map(),\n};\n\n/** Find any connector in the pool serving a given platform. */\nconst findConnectorForPlatform = (\n pool: Map<string, ConnectedWallet>,\n chainPlatform: ChainPlatform,\n): string | undefined => {\n for (const [id, wallet] of pool) {\n if (wallet.connector.chainPlatform === chainPlatform) {\n return id;\n }\n }\n return undefined;\n};\n\n/** Pure reducer: every state transition is expressed as `(state, event) => state`.\n * No I/O, no async, no side effects. Side effects live in the runtime. */\nconst reducer = (state: State, event: Event): State => {\n switch (event.type) {\n case \"HYDRATED\": {\n const pool = new Map<string, ConnectedWallet>(state.pool);\n for (const [id, entry] of event.pool) {\n pool.set(id, entry);\n }\n // A seeded entry whose reconnect failed is still backed by a shadow\n // adapter whose every method rejects. Leaving it in the pool would strand\n // it: nothing else ever clears it, so consumers would read a permanently\n // erroring wallet that reports itself as reconnecting forever.\n for (const id of event.dropped) {\n pool.delete(id);\n }\n const selection = new Map<ChainPlatform, string>(state.selection);\n for (const [platform, id] of event.selection) {\n selection.set(platform, id);\n }\n let activeConnectorId: string | null = null;\n if (event.activeConnectorId !== null && pool.has(event.activeConnectorId)) {\n activeConnectorId = event.activeConnectorId;\n } else if (state.activeConnectorId !== null && pool.has(state.activeConnectorId)) {\n activeConnectorId = state.activeConnectorId;\n } else if (pool.size > 0) {\n activeConnectorId = pool.keys().next().value ?? null;\n }\n let nextReconnecting: ReadonlySet<string> = state.reconnectingIds;\n if (state.reconnectingIds.size > 0) {\n const next = new Set(state.reconnectingIds);\n for (const id of event.pool.keys()) {\n next.delete(id);\n }\n for (const id of event.dropped) {\n next.delete(id);\n }\n if (next.size !== state.reconnectingIds.size) {\n nextReconnecting = next;\n }\n }\n const selectionAfterDrop = new Map(selection);\n for (const [platform, id] of selectionAfterDrop) {\n if (!pool.has(id)) {\n selectionAfterDrop.delete(platform);\n const fallback = findConnectorForPlatform(pool, platform);\n if (fallback !== undefined) {\n selectionAfterDrop.set(platform, fallback);\n }\n }\n }\n return {\n ...state,\n activeConnectorId,\n isHydrated: true,\n isUserDisconnected: event.isUserDisconnected,\n pool,\n reconnectingIds: nextReconnecting,\n selection: selectionAfterDrop,\n };\n }\n\n case \"USER_DISCONNECTED_SET\": {\n return { ...state, isUserDisconnected: event.value };\n }\n\n case \"CONNECT_STARTED\": {\n return {\n ...state,\n connectingConnectorId: event.connectorId,\n connectionError: null,\n connectionStatus: \"connecting\",\n };\n }\n\n case \"CONNECT_SUCCEEDED\": {\n const { connectorId, entry } = event;\n const existing = state.pool.get(connectorId);\n\n const nextReconnecting: ReadonlySet<string> = state.reconnectingIds.has(connectorId)\n ? new Set([...state.reconnectingIds].filter((id) => id !== connectorId))\n : state.reconnectingIds;\n\n if (\n existing &&\n existing.account.walletAddress.toLowerCase() === entry.account.walletAddress.toLowerCase()\n ) {\n return {\n ...state,\n activeConnectorId: connectorId,\n connectingConnectorId: null,\n connectionError: null,\n connectionStatus: \"success\",\n pool:\n existing.connector === entry.connector\n ? state.pool\n : new Map([...state.pool, [connectorId, entry] as const]),\n reconnectingIds: nextReconnecting,\n };\n }\n\n const newPool = new Map([...state.pool, [connectorId, entry] as const]);\n const newSelection = new Map([\n ...state.selection,\n [entry.connector.chainPlatform, connectorId] as const,\n ]);\n\n return {\n ...state,\n activeConnectorId: connectorId,\n connectingConnectorId: null,\n connectionError: null,\n connectionStatus: \"success\",\n pool: newPool,\n reconnectingIds: nextReconnecting,\n selection: newSelection,\n };\n }\n\n case \"ENTRY_RESTORED\": {\n const { connectorId, entry } = event;\n const nextReconnecting: ReadonlySet<string> = state.reconnectingIds.has(connectorId)\n ? new Set([...state.reconnectingIds].filter((id) => id !== connectorId))\n : state.reconnectingIds;\n\n const platform = entry.connector.chainPlatform;\n const selection = state.selection.has(platform)\n ? state.selection\n : new Map([...state.selection, [platform, connectorId] as const]);\n\n return {\n ...state,\n activeConnectorId: state.activeConnectorId ?? connectorId,\n pool: new Map([...state.pool, [connectorId, entry] as const]),\n reconnectingIds: nextReconnecting,\n selection,\n };\n }\n\n case \"CONNECT_FAILED\": {\n if (state.connectingConnectorId !== event.connectorId) {\n return state;\n }\n return {\n ...state,\n connectingConnectorId: null,\n connectionError: event.error,\n connectionStatus: \"error\",\n };\n }\n\n case \"DISCONNECTED\": {\n const wallet = state.pool.get(event.connectorId);\n if (!wallet) {\n return state;\n }\n\n const newPool = new Map(state.pool);\n newPool.delete(event.connectorId);\n\n const newSelection = new Map(state.selection);\n const platform = wallet.connector.chainPlatform;\n if (newSelection.get(platform) === event.connectorId) {\n newSelection.delete(platform);\n const fallback = findConnectorForPlatform(newPool, platform);\n if (fallback !== undefined) {\n newSelection.set(platform, fallback);\n }\n }\n\n const firstId = newPool.keys().next();\n const activeConnectorId =\n state.activeConnectorId === event.connectorId\n ? (firstId.value ?? null)\n : state.activeConnectorId;\n\n const nextReconnecting: ReadonlySet<string> = state.reconnectingIds.has(event.connectorId)\n ? new Set([...state.reconnectingIds].filter((id) => id !== event.connectorId))\n : state.reconnectingIds;\n\n return {\n ...state,\n activeConnectorId,\n pool: newPool,\n reconnectingIds: nextReconnecting,\n selection: newSelection,\n };\n }\n\n case \"ACCOUNTS_REFRESHED\": {\n const wallet = state.pool.get(event.connectorId);\n if (!wallet) {\n return state;\n }\n let nextAccount: Account;\n if (event.active) {\n nextAccount = event.active;\n } else {\n const stillHasCurrent = event.accounts.some(\n (a) =>\n a.walletAddress === wallet.account.walletAddress &&\n a.chain.id === wallet.account.chain.id,\n );\n nextAccount = stillHasCurrent ? wallet.account : (event.accounts[0] ?? wallet.account);\n }\n const sameAccount =\n nextAccount.walletAddress === wallet.account.walletAddress &&\n nextAccount.chain.id === wallet.account.chain.id;\n const hasSameAccounts =\n event.accounts.length === wallet.accounts.length &&\n event.accounts.every((a, i) => a.walletAddress === wallet.accounts[i]?.walletAddress);\n if (sameAccount && hasSameAccounts) {\n return state;\n }\n const updated: ConnectedWallet = {\n ...wallet,\n account: nextAccount,\n accounts: [...event.accounts],\n };\n const newPool = new Map([...state.pool, [event.connectorId, updated] as const]);\n return { ...state, pool: newPool };\n }\n\n case \"WALLET_REFRESHED\": {\n const wallet = state.pool.get(event.connectorId);\n if (!wallet) {\n return state;\n }\n const newPool = new Map([...state.pool, [event.connectorId, { ...wallet }] as const]);\n return { ...state, pool: newPool };\n }\n\n case \"ACTIVE_CHANGED\": {\n return { ...state, activeConnectorId: event.connectorId };\n }\n\n case \"SELECTION_CHANGED\": {\n const newSelection = new Map(state.selection);\n if (event.connectorId === null) {\n newSelection.delete(event.chainPlatform);\n } else {\n newSelection.set(event.chainPlatform, event.connectorId);\n }\n return { ...state, selection: newSelection };\n }\n\n case \"STATUS_RESET\": {\n return {\n ...state,\n connectingConnectorId: null,\n connectionError: null,\n connectionStatus: \"idle\",\n };\n }\n\n case \"ERROR_SET\": {\n return {\n ...state,\n connectionError: event.error,\n connectionStatus: event.error ? \"error\" : \"idle\",\n };\n }\n\n case \"RESET\": {\n return {\n ...initialState,\n isHydrated: state.isHydrated,\n isUserDisconnected: true,\n reconnectingIds: new Set(),\n };\n }\n\n default: {\n const exhaustiveCheck: never = event;\n void exhaustiveCheck;\n return state;\n }\n }\n};\n\nexport type {\n ConnectionStatus,\n ConnectionStatusEvent,\n Event,\n LifecycleEvent,\n PoolMutationEvent,\n SelectionEvent,\n State,\n};\nexport { initialState, reducer };\n","import type { ErrorCause } from \"../types/errors\";\nimport { toErrorCause } from \"../types/errors\";\n\n/** Run an async operation fire-and-forget, calling onError if it throws. */\nconst run = async (\n fn: () => Promise<void>,\n onError: (error: ErrorCause) => void,\n): Promise<void> => {\n try {\n await fn();\n } catch (error) {\n onError(toErrorCause(error instanceof Error ? error : String(error)));\n }\n};\n\nexport { run };\n","import { createStore } from \"zustand/vanilla\";\n\nimport { logError, logWarn } from \"../logger\";\nimport type { WalletPersistence, WalletSnapshot } from \"../storage\";\nimport { WalletStorage } from \"../storage/wallet-storage\";\nimport type {\n Account,\n ChainPlatform,\n ConnectedWallet,\n WalletAdapter,\n WalletManagerConfig,\n} from \"../types\";\nimport type { ConnectionError, ErrorCause } from \"../types/errors\";\nimport { mapConnectionError } from \"../types/errors\";\nimport { CHAIN_PLATFORMS } from \"../types/platform\";\n\nimport { createConnectorLifecycle } from \"./connector-lifecycle\";\nimport { createHydrationCoordinator } from \"./hydration\";\nimport { type Event, type State, initialState, reducer } from \"./reducer\";\nimport { createShadowAdapter } from \"./shadow-adapter\";\nimport { run } from \"./wallet-store-helpers\";\n\nconst VALID_CHAIN_PLATFORMS: ReadonlySet<string> = new Set(CHAIN_PLATFORMS);\n\nconst isChainPlatform = (value: string): value is ChainPlatform => VALID_CHAIN_PLATFORMS.has(value);\n\n/**\n * `isHydrated` is true from the first render on this path, so\n * `reconnectingIds` (not `isHydrated`) is the \"is this connection\n * verified\" signal until silent reconnect lands.\n */\nconst seedStateFromSnapshot = (snapshot: WalletSnapshot): State => {\n const pool = new Map<string, ConnectedWallet>();\n const reconnectingIds = new Set<string>();\n for (const [connectorId, entry] of Object.entries(snapshot.pool)) {\n if (!entry) {\n continue;\n }\n const connector: WalletAdapter = createShadowAdapter(entry);\n pool.set(connectorId, {\n account: entry.account,\n accounts: [...entry.accounts],\n connector,\n });\n reconnectingIds.add(connectorId);\n }\n const selection = new Map<ChainPlatform, string>();\n for (const [platform, connectorId] of Object.entries(snapshot.selection)) {\n if (isChainPlatform(platform) && connectorId !== undefined && pool.has(connectorId)) {\n selection.set(platform, connectorId);\n }\n }\n const activeConnectorId =\n snapshot.activeConnectorId !== null && pool.has(snapshot.activeConnectorId)\n ? snapshot.activeConnectorId\n : (pool.keys().next().value ?? null);\n return {\n ...initialState,\n activeConnectorId,\n isHydrated: true,\n pool,\n reconnectingIds,\n selection,\n };\n};\n\nconst CONNECT_TIMEOUT_MS = 90_000;\nconst DEFAULT_SLOW_CONNECT_THRESHOLD_MS = 5000;\n\nconst normaliseAddress = (addr: string): string => addr.toLowerCase();\n\ntype ExtractState<S> = S extends { getState: () => infer T } ? T : never;\n\ntype RuntimeMembers = {\n _config: WalletManagerConfig;\n _storage: WalletPersistence;\n connectWallet: (\n connectorId: string,\n onSuccess?: (wallet: ConnectedWallet) => void,\n onError?: (error: Error) => void,\n ) => Promise<void>;\n disconnectWallet: (connectorId: string) => void;\n getConnectorInstance: (id: string) => ReturnType<WalletManagerConfig[\"createConnector\"]>;\n hydrateWallets: () => Promise<void>;\n refreshWallet: (connectorId: string) => void;\n requestAccounts: (connectorId: string) => Promise<void>;\n reset: () => void;\n resetConnectionStatus: () => void;\n setActiveConnector: (connectorId: string | null) => void;\n setConnectionError: (error: ConnectionError | null) => void;\n setSelection: (chainPlatform: ChainPlatform, connectorId: string | null) => void;\n setUserDisconnected: (value: boolean) => void;\n tryRestoreFromPending: (connectorId: string) => Promise<void>;\n updateWalletAccount: (connectorId: string, account: Account) => void;\n};\n\ntype WalletStore = ReturnType<typeof createWalletStore>;\ntype WalletStoreState = ExtractState<WalletStore>;\n\nconst createWalletStore = (config: WalletManagerConfig) => {\n const storage = config.storage ?? new WalletStorage({ keyPrefix: config.storageKeyPrefix });\n\n const reportStorageError = (context: string) => (error: ErrorCause) => {\n if (config.onStorageError) {\n try {\n config.onStorageError(error, context);\n } catch (cbError) {\n logWarn(\"[butr] onStorageError threw:\", cbError);\n }\n return;\n }\n logWarn(`[butr] ${context}:`, error);\n };\n\n const hydration = createHydrationCoordinator(storage, config.createConnector);\n\n return createStore<State & RuntimeMembers>()((set, get) => {\n const dispatch = (event: Event) => {\n set((prev) => reducer(prev, event), false);\n };\n\n const persistPool = (): Promise<void> =>\n run(() => storage.setPool(get().pool), reportStorageError(\"failed to persist pool\"));\n\n const persistSelection = (): Promise<void> =>\n run(\n () => storage.setSelection(get().selection),\n reportStorageError(\"failed to persist selection\"),\n );\n\n const persistActive = (): Promise<void> =>\n run(\n () => storage.setActiveConnectorId(get().activeConnectorId),\n reportStorageError(\"failed to persist active connector\"),\n );\n\n const refreshPoolEntry = (connectorId: string, accounts: Array<Account>, active?: Account) => {\n dispatch({ accounts, active, connectorId, type: \"ACCOUNTS_REFRESHED\" });\n void persistPool();\n };\n\n const lifecycle = createConnectorLifecycle({\n onAccountChanged: (connectorId, accounts, active) => {\n refreshPoolEntry(connectorId, [...accounts], active);\n },\n onDisconnected: (connectorId, chainPlatform) => {\n // Tear the connector down as well as dropping it from the pool. The\n // adapter instance is cached by discovery and handed back on the next\n // connect, so an adapter that reported itself disconnected while\n // holding a live session would be reused in that state.\n const wallet = get().pool.get(connectorId);\n if (wallet) {\n void run(() => wallet.connector.disconnect?.() ?? Promise.resolve(), logError);\n }\n dispatch({ connectorId, type: \"DISCONNECTED\" });\n config.onDisconnect?.(chainPlatform);\n },\n });\n\n const seeded: State = config.initialState\n ? seedStateFromSnapshot(config.initialState)\n : initialState;\n\n return {\n ...seeded,\n _config: config,\n _storage: storage,\n connectWallet: async (connectorId, onSuccess, onError) => {\n get().setUserDisconnected(false);\n\n const connector = config.createConnector(connectorId);\n if (!connector) {\n throw new Error(`Failed to create connector for ${connectorId}`);\n }\n\n dispatch({ connectorId, type: \"CONNECT_STARTED\" });\n\n const slowThreshold = config.slowConnectThresholdMs ?? DEFAULT_SLOW_CONNECT_THRESHOLD_MS;\n const slowTimer = config.onSlowConnect\n ? setTimeout(() => {\n try {\n config.onSlowConnect?.(connectorId);\n } catch (cbError) {\n logWarn(\"[butr] onSlowConnect threw:\", cbError);\n }\n }, slowThreshold)\n : null;\n\n let connectTimeoutId: ReturnType<typeof setTimeout> | undefined;\n\n try {\n const connectPromise = connector.connect();\n // oxlint-disable-next-line promise/prefer-await-to-then -- suppress unhandled rejection; we await via Promise.race below\n void connectPromise.catch(() => {});\n await Promise.race([\n connectPromise,\n new Promise((_, reject) => {\n connectTimeoutId = setTimeout(() => {\n reject(new Error(\"Connection timeout\"));\n }, CONNECT_TIMEOUT_MS);\n }),\n ]);\n\n const account = await connector.getAccount();\n if (!account) {\n throw new Error(\"Failed to get account\");\n }\n\n const fetchedAccounts = connector.getAccounts\n ? await connector.getAccounts().catch(() => null)\n : null;\n const accounts =\n fetchedAccounts && fetchedAccounts.length > 0 ? fetchedAccounts : [account];\n\n const entry: ConnectedWallet = { account, accounts, connector };\n dispatch({ connectorId, entry, type: \"CONNECT_SUCCEEDED\" });\n\n lifecycle.attach(connectorId, connector);\n\n await Promise.all([persistPool(), persistSelection(), persistActive()]);\n\n config.onConnect?.(entry);\n onSuccess?.(entry);\n } catch (error) {\n const normalised = mapConnectionError(error instanceof Error ? error : String(error));\n dispatch({ connectorId, error: normalised, type: \"CONNECT_FAILED\" });\n try {\n await connector.disconnect?.();\n } catch (disconnectError) {\n logWarn(\"[butr] disconnect during error recovery failed:\", disconnectError);\n }\n try {\n config.onConnectError?.(normalised, connectorId);\n } catch (cbError) {\n logWarn(\"[butr] onConnectError threw:\", cbError);\n }\n onError?.(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n clearTimeout(connectTimeoutId);\n if (slowTimer) {\n clearTimeout(slowTimer);\n }\n }\n },\n\n disconnectWallet: (connectorId) => {\n get().setUserDisconnected(true);\n\n const state = get();\n if (!state.isHydrated) {\n return;\n }\n const wallet = state.pool.get(connectorId);\n if (!wallet) {\n return;\n }\n\n lifecycle.detach(connectorId);\n\n void run(() => wallet.connector.disconnect?.() ?? Promise.resolve(), logError);\n\n const platform = wallet.connector.chainPlatform;\n dispatch({ connectorId, type: \"DISCONNECTED\" });\n\n if (get().pool.size === 0) {\n void run(() => storage.clearAll(), reportStorageError(\"failed to clear storage\"));\n } else {\n void run(\n () => storage.removePoolEntry(connectorId),\n reportStorageError(\"failed to remove pool entry\"),\n );\n void persistSelection();\n void persistActive();\n }\n\n config.onDisconnect?.(platform);\n },\n\n getConnectorInstance: (id) => config.createConnector(id),\n\n hydrateWallets: async () => {\n const result = await hydration.hydrate();\n dispatch({\n activeConnectorId: result.activeConnectorId,\n dropped: result.dropped.map((d) => d.connectorId),\n isUserDisconnected: result.isUserDisconnected,\n pool: result.pool,\n selection: result.selection,\n type: \"HYDRATED\",\n });\n for (const [connectorId, wallet] of result.pool) {\n lifecycle.attach(connectorId, wallet.connector);\n }\n await Promise.all([persistSelection(), persistActive()]);\n for (const id of hydration.pendingIds()) {\n void run(\n () => get().tryRestoreFromPending(id),\n (e) => {\n logWarn(`[butr] late restore rejected for ${id}:`, e);\n },\n );\n }\n if (config.onHydrated) {\n try {\n config.onHydrated({\n dropped: result.dropped,\n pendingIds: [...result.pendingIds],\n restoredIds: [...result.pool.keys()],\n });\n } catch (cbError) {\n logWarn(\"[butr] onHydrated threw:\", cbError);\n }\n } else if (result.dropped.length > 0) {\n for (const { connectorId, reason } of result.dropped) {\n logWarn(`[butr] failed to restore connector ${connectorId}:`, reason);\n }\n }\n },\n refreshWallet: (connectorId) => {\n dispatch({ connectorId, type: \"WALLET_REFRESHED\" });\n },\n\n requestAccounts: async (connectorId) => {\n const entry = get().pool.get(connectorId);\n if (!entry) {\n return;\n }\n await entry.connector.requestAccounts?.();\n const fresh = entry.connector.getAccounts\n ? await entry.connector.getAccounts().catch(() => null)\n : null;\n if (!fresh || fresh.length === 0) {\n return;\n }\n refreshPoolEntry(connectorId, fresh);\n },\n\n reset: () => {\n get().setUserDisconnected(true);\n\n const state = get();\n if (!state.isHydrated) {\n return;\n }\n\n lifecycle.detachAll();\n\n for (const wallet of state.pool.values()) {\n void run(() => wallet.connector.disconnect?.() ?? Promise.resolve(), logError);\n }\n\n void run(() => storage.clearAll(), reportStorageError(\"failed to clear storage\"));\n\n if (config.onReset) {\n const onReset = config.onReset;\n void run(() => Promise.resolve(onReset()), logError);\n }\n\n dispatch({ type: \"RESET\" });\n },\n\n resetConnectionStatus: () => {\n dispatch({ type: \"STATUS_RESET\" });\n },\n\n setActiveConnector: (connectorId) => {\n dispatch({ connectorId, type: \"ACTIVE_CHANGED\" });\n void persistActive();\n },\n\n setConnectionError: (error) => {\n dispatch({ error, type: \"ERROR_SET\" });\n },\n\n setSelection: (chainPlatform, connectorId) => {\n dispatch({ chainPlatform, connectorId, type: \"SELECTION_CHANGED\" });\n void persistSelection();\n },\n\n setUserDisconnected: (value: boolean) => {\n dispatch({ type: \"USER_DISCONNECTED_SET\", value });\n void run(\n () => storage.markUserDisconnected(value),\n reportStorageError(\"failed to persist disconnect intent\"),\n );\n },\n\n tryRestoreFromPending: async (connectorId) => {\n const outcome = await hydration.drainPending(connectorId);\n if (!outcome) {\n return;\n }\n if (outcome.kind === \"fail\") {\n logWarn(`[butr] late restore failed for ${connectorId}:`, outcome.error);\n return;\n }\n dispatch({ connectorId, entry: outcome.entry, type: \"ENTRY_RESTORED\" });\n lifecycle.attach(connectorId, outcome.entry.connector);\n await Promise.all([persistPool(), persistSelection(), persistActive()]);\n config.onConnect?.(outcome.entry);\n },\n\n updateWalletAccount: (connectorId, account) => {\n const entry = get().pool.get(connectorId);\n if (!entry) {\n return;\n }\n const newChain = account.chain;\n const remapped = entry.accounts.map((a) =>\n a.chain.id === newChain.id\n ? a\n : {\n chain: newChain,\n id: `${newChain.id}:${normaliseAddress(a.walletAddress)}`,\n walletAddress: a.walletAddress,\n },\n );\n const seen = remapped.some(\n (a) => normaliseAddress(a.walletAddress) === normaliseAddress(account.walletAddress),\n );\n const accounts = seen ? remapped : [...remapped, account];\n refreshPoolEntry(connectorId, accounts, account);\n },\n };\n });\n};\n\nexport type { WalletStore, WalletStoreState };\nexport { createWalletStore };\n","import type { StorageDriver } from \"./persistence\";\n\ntype InitialCookies = Iterable<[string, string]> | Readonly<Record<string, string>>;\n\ntype CookieDriverOptions = {\n /**\n * Cookie `domain` attribute. Omit to scope to the current host.\n * Set to a parent domain (e.g. `.example.com`) to share state\n * across subdomains.\n */\n domain?: string;\n /**\n * Server-side cookie snapshot (Next.js' `cookies()`, a parsed\n * `req.headers.cookie`, …) read only when `document` is unavailable,\n * so the SSR pass sees the state the client will hydrate with.\n */\n initialCookies?: InitialCookies;\n /**\n * Lifetime in seconds. Defaults to 30 days.\n */\n maxAgeSeconds?: number;\n /**\n * URL path the cookie applies to. Defaults to `/` (whole origin).\n */\n path?: string;\n /**\n * `SameSite` attribute. Defaults to `\"lax\"`; restrictive enough\n * to avoid CSRF on cross-origin POSTs, permissive enough for\n * top-level navigations.\n */\n sameSite?: \"lax\" | \"strict\" | \"none\";\n /**\n * `Secure` attribute. Defaults to `true` (cookies only sent over\n * HTTPS). Force `false` for local development on plain `http://`.\n */\n secure?: boolean;\n};\n\nconst DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;\n\nconst encode = (value: string): string => encodeURIComponent(value);\nconst decode = (value: string): string => decodeURIComponent(value);\n\nconst readCookies = (): Map<string, string> => {\n const out = new Map<string, string>();\n if (typeof document === \"undefined\") {\n return out;\n }\n const cookieString = document.cookie;\n if (!cookieString) {\n return out;\n }\n for (const segment of cookieString.split(\";\")) {\n const trimmed = segment.trim();\n if (!trimmed) {\n continue;\n }\n const eq = trimmed.indexOf(\"=\");\n if (eq === -1) {\n continue;\n }\n const name = trimmed.slice(0, eq);\n const raw = trimmed.slice(eq + 1);\n try {\n out.set(name, decode(raw));\n } catch {\n void 0;\n }\n }\n return out;\n};\n\nconst buildCookieString = (\n name: string,\n value: string,\n options: CookieDriverOptions,\n expired = false,\n): string => {\n const parts: Array<string> = [`${name}=${encode(value)}`, `Path=${options.path ?? \"/\"}`];\n if (options.domain !== undefined && options.domain !== \"\") {\n parts.push(`Domain=${options.domain}`);\n }\n if (expired) {\n parts.push(\"Max-Age=0\");\n } else {\n const maxAge = options.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS;\n parts.push(`Max-Age=${maxAge}`);\n }\n parts.push(`SameSite=${options.sameSite ?? \"lax\"}`);\n if (options.secure ?? true) {\n parts.push(\"Secure\");\n }\n return parts.join(\"; \");\n};\n\nconst toCookieMap = (input: InitialCookies | undefined): Map<string, string> | null => {\n if (!input) {\n return null;\n }\n if (Symbol.iterator in input) {\n return new Map(input);\n }\n return new Map(Object.entries(input));\n};\n\n/**\n * Server-side writes are no-ops: `Set-Cookie` needs the framework's\n * response object. Cookies ride every request, so use this driver for\n * the `persistent` slot only and leave `session` on `sessionStorage`.\n */\nconst createCookieStorageDriver = (options: CookieDriverOptions = {}): StorageDriver => {\n const seeded = toCookieMap(options.initialCookies);\n\n if (typeof document === \"undefined\") {\n if (!seeded) {\n return {\n getItem() {\n return null;\n },\n removeItem() {},\n setItem() {},\n };\n }\n return {\n getItem(key) {\n return seeded.get(key) ?? null;\n },\n removeItem() {},\n setItem() {},\n };\n }\n return {\n getItem(key) {\n return readCookies().get(key) ?? null;\n },\n removeItem(key) {\n // eslint-disable-next-line unicorn/no-document-cookie -- cookie storage driver is the document.cookie abstraction by design\n document.cookie = buildCookieString(key, \"\", options, true);\n },\n setItem(key, value) {\n // eslint-disable-next-line unicorn/no-document-cookie -- cookie storage driver is the document.cookie abstraction by design\n document.cookie = buildCookieString(key, value, options);\n },\n };\n};\n\nexport type { CookieDriverOptions, InitialCookies };\nexport { createCookieStorageDriver };\n","import type { StoredPoolRecord, StoredSelectionRecord } from \"./persistence\";\nimport { decodePool, decodeSelection, storageKeys } from \"./validation\";\n\n/**\n * Carries no `Connector` by design: a wallet extension exists only in\n * the browser, so a server render can name the wallet and its address\n * but can never dispatch on it.\n */\ntype WalletSnapshot = {\n activeConnectorId: string | null;\n pool: StoredPoolRecord;\n selection: StoredSelectionRecord;\n};\n\ntype CookieSource =\n | Iterable<{ name: string; value: string }>\n | Iterable<[string, string]>\n | Readonly<Record<string, string>>;\n\ntype SnapshotOptions = {\n /**\n * Same prefix passed to `WalletManagerProvider` / `WalletStorage`.\n * Defaults to `\"butr\"` to match the library default.\n */\n keyPrefix?: string;\n};\n\nconst EMPTY_POOL: StoredPoolRecord = Object.freeze({});\nconst EMPTY_SELECTION: StoredSelectionRecord = Object.freeze({});\n\nconst EMPTY_SNAPSHOT: WalletSnapshot = Object.freeze({\n activeConnectorId: null,\n pool: EMPTY_POOL,\n selection: EMPTY_SELECTION,\n});\n\nconst toCookieMap = (input: CookieSource): Map<string, string> => {\n if (!(Symbol.iterator in input)) {\n return new Map(Object.entries(input));\n }\n const out = new Map<string, string>();\n for (const entry of input) {\n if (Array.isArray(entry)) {\n const [name, value] = entry;\n if (typeof name === \"string\" && typeof value === \"string\") {\n out.set(name, value);\n }\n continue;\n }\n if (typeof entry.name === \"string\" && typeof entry.value === \"string\") {\n out.set(entry.name, entry.value);\n }\n }\n return out;\n};\n\nconst SNAPSHOT_LABEL = \"[butr] readWalletSnapshot:\";\n\n/**\n * Optimistic: only what the browser last persisted, so an uninstall or\n * other-tab disconnect makes it stale. Authoritative once the entry\n * leaves `reconnectingIds`; `isHydrated` is true from render one.\n */\nconst readWalletSnapshot = (\n source: CookieSource,\n options: SnapshotOptions = {},\n): WalletSnapshot => {\n const keys = storageKeys(options.keyPrefix);\n const cookies = toCookieMap(source);\n\n const pool = decodePool(cookies.get(keys.pool), SNAPSHOT_LABEL);\n const selection = decodeSelection(cookies.get(keys.selection), SNAPSHOT_LABEL);\n\n const rawActive = cookies.get(keys.active);\n let activeConnectorId: string | null = null;\n if (rawActive !== undefined && rawActive.length > 0 && pool[rawActive] !== undefined) {\n activeConnectorId = rawActive;\n } else {\n const firstKey = Object.keys(pool)[0];\n if (firstKey) {\n activeConnectorId = firstKey;\n }\n }\n\n return { activeConnectorId, pool, selection };\n};\n\nexport type { CookieSource, SnapshotOptions, WalletSnapshot };\nexport { EMPTY_SNAPSHOT, readWalletSnapshot };\n","import type { ChainPlatform } from \"./types/platform\";\nimport { CHAIN_PLATFORMS } from \"./types/platform\";\n\n/**\n * A multi-chain wallet announces one adapter per platform, so brands\n * repeat in the flat list. Keys follow `CHAIN_PLATFORMS` order and empty\n * platforms are omitted, so `[...groups]` needs no emptiness filter.\n */\nconst groupByPlatform = <T>(\n items: ReadonlyArray<T>,\n getPlatform: (item: T) => ChainPlatform,\n): Map<ChainPlatform, Array<T>> => {\n const buckets = new Map<ChainPlatform, Array<T>>();\n for (const item of items) {\n const platform = getPlatform(item);\n const bucket = buckets.get(platform);\n if (bucket === undefined) {\n buckets.set(platform, [item]);\n } else {\n bucket.push(item);\n }\n }\n\n const ordered = new Map<ChainPlatform, Array<T>>();\n for (const platform of CHAIN_PLATFORMS) {\n const bucket = buckets.get(platform);\n if (bucket !== undefined) {\n ordered.set(platform, bucket);\n }\n }\n return ordered;\n};\n\nexport { groupByPlatform };\n","/**\n * Hex prefixing diverges by chain (bare for Bitcoin and Ledger, `0x` for\n * EVM and Polkadot), so the variants stay explicit: these sit on the\n * signing path, where a silent mismatch corrupts one chain's signatures.\n */\n\n/** Bitcoin/Solana alphabet; omits the visually ambiguous `0`, `O`, `I`, `l`. */\nconst BASE58_ALPHABET = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n\nconst BASE58_INDEX = new Map<string, number>();\nfor (let i = 0; i < BASE58_ALPHABET.length; i += 1) {\n BASE58_INDEX.set(BASE58_ALPHABET[i] ?? \"\", i);\n}\n\n/** Bare lowercase hex, no `0x` prefix (Bitcoin, Ledger). */\nconst bytesToHex = (bytes: Uint8Array): string => {\n let hex = \"\";\n for (const byte of bytes) {\n hex += byte.toString(16).padStart(2, \"0\");\n }\n return hex;\n};\n\n/** `0x`-prefixed lowercase hex (EVM, Polkadot). */\nconst bytesToHexPrefixed = (bytes: Uint8Array): string => `0x${bytesToHex(bytes)}`;\n\n/**\n * Decode hex (with or without a leading `0x`) into raw bytes. Throws on\n * odd-length input or non-hex characters rather than silently producing\n * `NaN`-filled bytes.\n */\nconst hexToBytes = (hex: string): Uint8Array => {\n const clean = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n if (clean.length % 2 !== 0) {\n throw new TypeError(\"Invalid hex: odd length\");\n }\n const out = new Uint8Array(clean.length / 2);\n for (let i = 0; i < out.length; i += 1) {\n const byte = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n if (Number.isNaN(byte)) {\n throw new TypeError(`Invalid hex character at offset ${i * 2}`);\n }\n out[i] = byte;\n }\n return out;\n};\n\n/**\n * Cross-platform base64 → `Uint8Array`. `atob` is available everywhere\n * butr runs (browsers, RN since Hermes, Node 16+, Bun, Deno).\n */\nconst base64ToBytes = (b64: string): Uint8Array => {\n const binary = atob(b64);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) {\n out[i] = binary.codePointAt(i) ?? 0;\n }\n return out;\n};\n\n/** Cross-platform `Uint8Array` → base64. */\nconst bytesToBase64 = (bytes: Uint8Array): string => {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCodePoint(byte);\n }\n return btoa(binary);\n};\n\n/**\n * `Uint8Array` → base58 (Solana addresses and signatures). Leading zero\n * bytes are significant in base58 and survive the BigInt round-trip only\n * because they're re-prefixed as `1`s afterwards.\n */\nconst bytesToBase58 = (bytes: Uint8Array): string => {\n let intVal = 0n;\n for (const byte of bytes) {\n intVal = (intVal << 8n) | BigInt(byte);\n }\n let out = \"\";\n while (intVal > 0n) {\n const remainder = intVal % 58n;\n intVal /= 58n;\n out = BASE58_ALPHABET[Number(remainder)] + out;\n }\n for (const byte of bytes) {\n if (byte !== 0) {\n break;\n }\n out = `1${out}`;\n }\n return out;\n};\n\n/** Decode base58 into raw bytes. Throws on characters outside the alphabet\n * rather than silently dropping them. */\nconst base58ToBytes = (input: string): Uint8Array => {\n let intVal = 0n;\n let leadingZeros = 0;\n let stillLeading = true;\n for (const char of input) {\n if (stillLeading && char === \"1\") {\n leadingZeros += 1;\n } else {\n stillLeading = false;\n }\n const digit = BASE58_INDEX.get(char);\n if (digit === undefined) {\n throw new Error(`Invalid base58 character \"${char}\"`);\n }\n intVal = intVal * 58n + BigInt(digit);\n }\n const bytes: Array<number> = [];\n const byteMask = 255n;\n while (intVal > 0n) {\n bytes.unshift(Number(intVal & byteMask));\n intVal >>= 8n;\n }\n for (let i = 0; i < leadingZeros; i += 1) {\n bytes.unshift(0);\n }\n return Uint8Array.from(bytes);\n};\n\nexport {\n base58ToBytes,\n base64ToBytes,\n bytesToBase58,\n bytesToBase64,\n bytesToHex,\n bytesToHexPrefixed,\n hexToBytes,\n};\n","import { bytesToBase64 } from \"../encoding/bytes\";\nimport type { Account, ConnectedWallet } from \"../types\";\n\n/**\n * Verify against `signedMessage`, not `message`: Solana Wallet Standard\n * wallets may prefix or re-encode what they sign. Base64 mirrors exist\n * because `Uint8Array` does not survive `JSON.stringify`.\n */\ntype SignInResult = {\n account: Account;\n /** The message handed to the wallet. Absent on the SIWS path, where the\n * wallet composes the message itself. */\n message?: string;\n nonce: string;\n signature: Uint8Array;\n /** Base64 of `signature`. */\n signatureBase64: string;\n signedMessage: Uint8Array;\n /** Base64 of `signedMessage`; verify against this. */\n signedMessageBase64: string;\n wallet: ConnectedWallet;\n};\n\ntype SignInMessageContext = {\n account: Account;\n nonce: string;\n wallet: ConnectedWallet;\n};\n\ntype SignInFlowOptions = {\n /**\n * butr ships no wire format: a server-parsed message is an auth spec,\n * and SIWE / SIWS already fill that role. Pass what your backend\n * expects. Unused on the SIWS path, where the wallet composes it.\n */\n buildMessage?: (ctx: SignInMessageContext) => string;\n /** Fetch a single-use nonce from your backend. */\n getNonce: (ctx: { account: Account; wallet: ConnectedWallet }) => Promise<string>;\n /**\n * Skip the Sign In With Solana path even on wallets that advertise it,\n * forcing every platform down the same `signMessage` route. Useful when\n * one backend verifier has to handle every chain identically.\n */\n preferSignMessage?: boolean;\n /** Hand the signed result to your backend. Throw to fail the flow. */\n verify: (result: SignInResult) => Promise<void>;\n};\n\ntype SignInFlow = {\n signIn: (wallet: ConnectedWallet, account?: Account) => Promise<SignInResult>;\n};\n\n/** Thrown before any wallet interaction when the wallet can't sign at\n * all. Distinct from a rejection: nothing was asked of the user, so UI\n * should say \"this wallet can't sign in\" rather than \"you declined\". */\nclass SignInUnsupportedError extends Error {\n readonly connectorId: string;\n\n constructor(connectorId: string) {\n super(\n `Wallet \"${connectorId}\" reports capabilities.signMessage === false, so it cannot sign in.`,\n );\n this.connectorId = connectorId;\n this.name = \"SignInUnsupportedError\";\n }\n}\n\nconst defaultBuildMessage = ({ account, nonce }: SignInMessageContext): string =>\n `${account.walletAddress} signs in.\\nNonce: ${nonce}`;\n\n/**\n * Solana wallets advertising `solana:signIn` take the SIWS path, so\n * `result.signedMessage` holds the wallet-composed statement and\n * `result.message` is absent. `preferSignMessage` opts out.\n */\nconst createSignInFlow = (options: SignInFlowOptions): SignInFlow => {\n const buildMessage = options.buildMessage ?? defaultBuildMessage;\n\n const sign = async (wallet: ConnectedWallet, account?: Account): Promise<SignInResult> => {\n const { connector } = wallet;\n const signingAccount = account ?? wallet.account;\n\n if (!connector.capabilities.signMessage) {\n throw new SignInUnsupportedError(connector.id);\n }\n\n const nonce = await options.getNonce({ account: signingAccount, wallet });\n\n if (\n options.preferSignMessage !== true &&\n connector.chainPlatform === \"svm\" &&\n connector.capabilities.signIn &&\n connector.signIn !== undefined\n ) {\n const output = await connector.signIn({ nonce });\n return {\n account: output.account,\n nonce,\n signature: output.signature,\n signatureBase64: bytesToBase64(output.signature),\n signedMessage: output.signedMessage,\n signedMessageBase64: bytesToBase64(output.signedMessage),\n wallet,\n };\n }\n\n const message = buildMessage({ account: signingAccount, nonce, wallet });\n const { signature, signedMessage } = await connector.signMessage(\n new TextEncoder().encode(message),\n signingAccount,\n );\n\n return {\n account: signingAccount,\n message,\n nonce,\n signature,\n signatureBase64: bytesToBase64(signature),\n signedMessage,\n signedMessageBase64: bytesToBase64(signedMessage),\n wallet,\n };\n };\n\n return {\n signIn: async (wallet, account) => {\n const result = await sign(wallet, account);\n await options.verify(result);\n return result;\n },\n };\n};\n\nexport type { SignInFlow, SignInFlowOptions, SignInMessageContext, SignInResult };\nexport { SignInUnsupportedError, createSignInFlow };\n","import type { ConnectedWallet } from \"./types\";\n\n/**\n * The adapter is compared by reference, not `connector.id`: hydration\n * swaps a shadow adapter for the live one under an unchanged id, and an\n * id check would strand consumers on the throwing placeholder.\n */\nconst walletEqual = (a: ConnectedWallet | undefined, b: ConnectedWallet | undefined): boolean => {\n if (a === b) {\n return true;\n }\n if (!a || !b) {\n return false;\n }\n return (\n a.connector === b.connector &&\n a.account.walletAddress === b.account.walletAddress &&\n a.account.chain.id === b.account.chain.id\n );\n};\n\nexport { walletEqual };\n","/**\n * Some wallets announce data-URI icons wrapped in whitespace, which\n * makes Next.js `<Image>` throw on a leading control character.\n * Discovery already applies this; only hand-built metadata needs it.\n */\nconst sanitizeIcon = (icon: string | undefined): string | undefined => {\n if (icon === undefined) {\n return undefined;\n }\n const trimmed = icon.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n};\n\nexport { sanitizeIcon };\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usebutr/core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Core types, store, storage, and discovery seam for butr. No React, no protocols.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"butr",
|
|
7
|
+
"dapp",
|
|
8
|
+
"discovery",
|
|
9
|
+
"react",
|
|
10
|
+
"state-management",
|
|
11
|
+
"typescript",
|
|
12
|
+
"wallet",
|
|
13
|
+
"web3",
|
|
14
|
+
"zustand"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://docs.usebutr.com/api/core",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/pedroapfilho/usebutr/issues"
|
|
19
|
+
},
|
|
5
20
|
"license": "MIT",
|
|
6
21
|
"author": "Pedro Filho <pedro@filho.me>",
|
|
7
22
|
"repository": {
|
|
@@ -10,7 +25,8 @@
|
|
|
10
25
|
"directory": "packages/core"
|
|
11
26
|
},
|
|
12
27
|
"files": [
|
|
13
|
-
"dist"
|
|
28
|
+
"dist",
|
|
29
|
+
"CHANGELOG.md"
|
|
14
30
|
],
|
|
15
31
|
"type": "module",
|
|
16
32
|
"sideEffects": false,
|
|
@@ -29,7 +45,7 @@
|
|
|
29
45
|
},
|
|
30
46
|
"devDependencies": {
|
|
31
47
|
"@types/node": "^26.2.0",
|
|
32
|
-
"typescript": "^
|
|
48
|
+
"typescript": "^7.0.2",
|
|
33
49
|
"vitest": "^4.1.10",
|
|
34
50
|
"zustand": "^5.0.14",
|
|
35
51
|
"@repo/config-vitest": "0.0.0",
|