@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 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>) => 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<unknown>;
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: unknown, account?: Account) => Promise<string>;
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: unknown, targetChainId: string, account?: Account, cb?: () => void) => Promise<string>;
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?: Record<string, unknown>) => Promise<{
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: unknown, account?: Account) => Promise<Uint8Array>;
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: unknown, account?: Account) => Promise<{
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: unknown, account?: Account) => Promise<Uint8Array>;
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?: unknown;
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: unknown) => ConnectionError;
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: unknown;
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: unknown, context: string) => void;
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
@@ -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":"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"}
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 = "code" in raw ? raw.code : void 0;
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 typeof globalThis !== "undefined" && globalThis[kind] !== void 0;
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 entry = parseStoredPoolEntry(key, entryValue);
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 sameAccountsShape = event.accounts.length === wallet.accounts.length && event.accounts.every((a, i) => a.walletAddress === wallet.accounts[i]?.walletAddress);
826
- if (sameAccount && sameAccountsShape) return state;
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: Object.freeze({}),
1270
- selection: Object.freeze({})
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.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": "^6.0.3",
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",