@kheopskit/core 4.0.0 → 5.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.
Files changed (54) hide show
  1. package/dist/{chunk-SIUWQBT4.js → chunk-4ENHC7G4.js} +11 -2
  2. package/dist/chunk-4ENHC7G4.js.map +1 -0
  3. package/dist/{chunk-KWFQDD7E.mjs → chunk-6XAZANB5.mjs} +58 -186
  4. package/dist/chunk-6XAZANB5.mjs.map +1 -0
  5. package/dist/{chunk-PNPPI5CH.mjs → chunk-7QSGAJ4A.mjs} +11 -2
  6. package/dist/chunk-7QSGAJ4A.mjs.map +1 -0
  7. package/dist/{chunk-TMAPQWW2.js → chunk-B4L6GAYD.js} +24 -9
  8. package/dist/chunk-B4L6GAYD.js.map +1 -0
  9. package/dist/chunk-XQWJM3KC.js +450 -0
  10. package/dist/chunk-XQWJM3KC.js.map +1 -0
  11. package/dist/{chunk-4RBYRNY3.mjs → chunk-YDLCHYHH.mjs} +22 -7
  12. package/dist/chunk-YDLCHYHH.mjs.map +1 -0
  13. package/dist/ethereum.d.mts +4 -3
  14. package/dist/ethereum.d.ts +4 -3
  15. package/dist/ethereum.js +61 -42
  16. package/dist/ethereum.js.map +1 -1
  17. package/dist/ethereum.mjs +53 -34
  18. package/dist/ethereum.mjs.map +1 -1
  19. package/dist/index.d.mts +20 -6
  20. package/dist/index.d.ts +20 -6
  21. package/dist/index.js +253 -47
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +271 -65
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/internal.d.mts +4 -4
  26. package/dist/internal.d.ts +4 -4
  27. package/dist/internal.js +3 -3
  28. package/dist/internal.mjs +2 -2
  29. package/dist/polkadot.d.mts +4 -3
  30. package/dist/polkadot.d.ts +4 -3
  31. package/dist/polkadot.js +26 -37
  32. package/dist/polkadot.js.map +1 -1
  33. package/dist/polkadot.mjs +13 -24
  34. package/dist/polkadot.mjs.map +1 -1
  35. package/dist/solana.d.mts +5 -4
  36. package/dist/solana.d.ts +5 -4
  37. package/dist/solana.js +37 -42
  38. package/dist/solana.js.map +1 -1
  39. package/dist/solana.mjs +26 -31
  40. package/dist/solana.mjs.map +1 -1
  41. package/dist/{types-BNzRUNw-.d.mts → types-C7V7DGlg.d.mts} +47 -17
  42. package/dist/{types-BNzRUNw-.d.ts → types-C7V7DGlg.d.ts} +47 -17
  43. package/package.json +42 -16
  44. package/dist/chunk-4RBYRNY3.mjs.map +0 -1
  45. package/dist/chunk-FIAL4HTE.js +0 -1
  46. package/dist/chunk-FIAL4HTE.js.map +0 -1
  47. package/dist/chunk-KWFQDD7E.mjs.map +0 -1
  48. package/dist/chunk-NU46D4MZ.js +0 -578
  49. package/dist/chunk-NU46D4MZ.js.map +0 -1
  50. package/dist/chunk-PNPPI5CH.mjs.map +0 -1
  51. package/dist/chunk-SIUWQBT4.js.map +0 -1
  52. package/dist/chunk-TMAPQWW2.js.map +0 -1
  53. package/dist/chunk-YFD3IKK5.mjs +0 -1
  54. package/dist/chunk-YFD3IKK5.mjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  setCachedIcons,
9
9
  sortAccounts,
10
10
  sortWallets
11
- } from "./chunk-4RBYRNY3.mjs";
11
+ } from "./chunk-YDLCHYHH.mjs";
12
12
  import "./chunk-BWUUHUDK.mjs";
13
13
  import {
14
14
  DEFAULT_STORAGE_KEY,
@@ -17,54 +17,231 @@ import {
17
17
  getDefaultStore,
18
18
  getWalletAccountId,
19
19
  isValidAddress,
20
- resetAppKitCache,
20
+ parseWalletAccountId,
21
21
  resolveConfig,
22
22
  store
23
- } from "./chunk-KWFQDD7E.mjs";
23
+ } from "./chunk-6XAZANB5.mjs";
24
24
  import {
25
+ WALLET_CONNECT_WALLET_ID,
25
26
  clearAllCachedObservables,
27
+ clearCachedObservablesByPrefix,
26
28
  getWalletId,
29
+ isInjectedWallet,
30
+ isValidWalletId,
31
+ isWalletConnectWallet,
27
32
  parseWalletId
28
- } from "./chunk-PNPPI5CH.mjs";
33
+ } from "./chunk-7QSGAJ4A.mjs";
34
+
35
+ // src/api/appKit.ts
36
+ import {
37
+ BehaviorSubject,
38
+ distinctUntilChanged,
39
+ from,
40
+ map,
41
+ Observable,
42
+ of,
43
+ shareReplay,
44
+ switchMap,
45
+ tap
46
+ } from "rxjs";
47
+ var loadAppKit = async () => {
48
+ try {
49
+ const { createAppKit } = await import("@reown/appkit/core");
50
+ return createAppKit;
51
+ } catch (cause) {
52
+ console.error(
53
+ "[kheopskit] WalletConnect is configured but @reown/appkit could not be loaded. Install it with `pnpm add @reown/appkit` (or remove config.walletConnect). WalletConnect wallets are disabled; injected wallets still work.",
54
+ cause
55
+ );
56
+ return null;
57
+ }
58
+ };
59
+ var WALLET_CONNECT_ICON = "data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjQwMCIgdmlld0JveD0iMCAwIDQwMCA0MDAiIHdpZHRoPSI0MDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxjbGlwUGF0aCBpZD0iYSI+PHBhdGggZD0ibTAgMGg0MDB2NDAwaC00MDB6Ii8+PC9jbGlwUGF0aD48ZyBjbGlwLXBhdGg9InVybCgjYSkiPjxjaXJjbGUgY3g9IjIwMCIgY3k9IjIwMCIgZmlsbD0iIzMzOTZmZiIgcj0iMTk5LjUiIHN0cm9rZT0iIzY2YjFmZiIvPjxwYXRoIGQ9Im0xMjIuNTE5IDE0OC45NjVjNDIuNzkxLTQxLjcyOSAxMTIuMTcxLTQxLjcyOSAxNTQuOTYyIDBsNS4xNSA1LjAyMmMyLjE0IDIuMDg2IDIuMTQgNS40NjkgMCA3LjU1NWwtMTcuNjE3IDE3LjE4Yy0xLjA3IDEuMDQzLTIuODA0IDEuMDQzLTMuODc0IDBsLTcuMDg3LTYuOTExYy0yOS44NTMtMjkuMTExLTc4LjI1My0yOS4xMTEtMTA4LjEwNiAwbC03LjU5IDcuNDAxYy0xLjA3IDEuMDQzLTIuODA0IDEuMDQzLTMuODc0IDBsLTE3LjYxNy0xNy4xOGMtMi4xNC0yLjA4Ni0yLjE0LTUuNDY5IDAtNy41NTV6bTE5MS4zOTcgMzUuNTI5IDE1LjY3OSAxNS4yOWMyLjE0IDIuMDg2IDIuMTQgNS40NjkgMCA3LjU1NWwtNzAuNyA2OC45NDRjLTIuMTM5IDIuMDg3LTUuNjA4IDIuMDg3LTcuNzQ4IDBsLTUwLjE3OC00OC45MzFjLS41MzUtLjUyMi0xLjQwMi0uNTIyLTEuOTM3IDBsLTUwLjE3OCA0OC45MzFjLTIuMTM5IDIuMDg3LTUuNjA4IDIuMDg3LTcuNzQ4IDBsLTcwLjcwMTUtNjguOTQ1Yy0yLjEzOTYtMi4wODYtMi4xMzk2LTUuNDY5IDAtNy41NTVsMTUuNjc5NS0xNS4yOWMyLjEzOTYtMi4wODYgNS42MDg1LTIuMDg2IDcuNzQ4MSAwbDUwLjE3ODkgNDguOTMyYy41MzUuNTIyIDEuNDAyLjUyMiAxLjkzNyAwbDUwLjE3Ny00OC45MzJjMi4xMzktMi4wODcgNS42MDgtMi4wODcgNy43NDggMGw1MC4xNzkgNDguOTMyYy41MzUuNTIyIDEuNDAyLjUyMiAxLjkzNyAwbDUwLjE3OS00OC45MzFjMi4xMzktMi4wODcgNS42MDgtMi4wODcgNy43NDggMHoiIGZpbGw9IiNmZmYiLz48L2c+PC9zdmc+";
60
+ var APPKIT_SYMBOL = /* @__PURE__ */ Symbol.for("kheopskit.cachedAppKit");
61
+ var APPKIT_PROJECT_ID_SYMBOL = /* @__PURE__ */ Symbol.for("kheopskit.cachedAppKitProjectId");
62
+ var getCachedAppKit = () => globalThis[APPKIT_SYMBOL];
63
+ var getCachedAppKitProjectId = () => globalThis[APPKIT_PROJECT_ID_SYMBOL];
64
+ var setCachedAppKit = (value, projectId) => {
65
+ globalThis[APPKIT_SYMBOL] = value;
66
+ globalThis[APPKIT_PROJECT_ID_SYMBOL] = projectId;
67
+ };
68
+ var resetAppKitCache = () => {
69
+ setCachedAppKit(void 0);
70
+ };
71
+ var dropAccountsCache = (platform) => {
72
+ clearCachedObservablesByPrefix(
73
+ `accounts:${WALLET_CONNECT_WALLET_ID}:${platform}:`
74
+ );
75
+ };
76
+ var getWalletConnectWallet$ = (config) => {
77
+ if (!config.walletConnect) return of(null);
78
+ if (typeof window === "undefined") return of(null);
79
+ const walletConnect = config.walletConnect;
80
+ const cachedProjectId = getCachedAppKitProjectId();
81
+ if (cachedProjectId !== void 0 && cachedProjectId !== walletConnect.projectId) {
82
+ console.warn(
83
+ "[kheopskit] WalletConnect is already initialised with projectId %s; AppKit is a process-wide singleton, so the first configuration wins and projectId %s is ignored. Call resetAppKitCache() before re-initialising if the WalletConnect config must change.",
84
+ cachedProjectId,
85
+ walletConnect.projectId
86
+ );
87
+ }
88
+ let cachedAppKit = getCachedAppKit();
89
+ if (!cachedAppKit) {
90
+ cachedAppKit = from(loadAppKit()).pipe(
91
+ switchMap((createAppKit) => {
92
+ if (!createAppKit) return of(null);
93
+ return new Observable((subscriber) => {
94
+ const appKit = createAppKit({
95
+ projectId: walletConnect.projectId,
96
+ metadata: walletConnect.metadata,
97
+ // Loosely typed in WalletConnectConfig to keep @reown/appkit's
98
+ // types out of core; forwarded to AppKit verbatim.
99
+ networks: walletConnect.networks,
100
+ themeMode: walletConnect.themeMode,
101
+ themeVariables: walletConnect.themeVariables,
102
+ universalProviderConfigOverride: {
103
+ methods: {
104
+ polkadot: ["polkadot_signTransaction", "polkadot_signMessage"],
105
+ solana: [
106
+ "solana_signTransaction",
107
+ "solana_signMessage",
108
+ "solana_signAndSendTransaction"
109
+ ]
110
+ }
111
+ },
112
+ allWallets: "HIDE",
113
+ debug: config.debug,
114
+ allowUnsupportedChain: true
115
+ });
116
+ const appKitInstance = appKit;
117
+ const status$ = new BehaviorSubject({
118
+ isPolkadotConnected: false,
119
+ isEthereumConnected: false,
120
+ isSolanaConnected: false
121
+ });
122
+ const unsubProviders = appKit.subscribeProviders((providers) => {
123
+ status$.next({
124
+ isPolkadotConnected: !!providers.polkadot,
125
+ isEthereumConnected: !!providers.eip155,
126
+ isSolanaConnected: !!providers.solana
127
+ });
128
+ });
129
+ const namespaceOf = {
130
+ polkadot: "polkadot",
131
+ ethereum: "eip155",
132
+ solana: "solana"
133
+ };
134
+ const allPlatforms = [
135
+ "polkadot",
136
+ "ethereum",
137
+ "solana"
138
+ ];
139
+ const enabledPlatforms = allPlatforms.filter(
140
+ (p) => appKit.chainNamespaces.includes(namespaceOf[p])
141
+ );
142
+ let prevConnected = {
143
+ polkadot: false,
144
+ ethereum: false,
145
+ solana: false
146
+ };
147
+ const sub = status$.pipe(
148
+ map((s) => ({
149
+ polkadot: s.isPolkadotConnected,
150
+ ethereum: s.isEthereumConnected,
151
+ solana: s.isSolanaConnected
152
+ })),
153
+ distinctUntilChanged(
154
+ (a, b) => a.polkadot === b.polkadot && a.ethereum === b.ethereum && a.solana === b.solana
155
+ ),
156
+ tap((connected) => {
157
+ for (const platform of allPlatforms)
158
+ if (prevConnected[platform] && !connected[platform])
159
+ dropAccountsCache(platform);
160
+ prevConnected = connected;
161
+ }),
162
+ map((connected) => {
163
+ const platforms = enabledPlatforms.filter((p) => connected[p]);
164
+ const isConnected = platforms.length > 0;
165
+ const walletInfo = appKit.getWalletInfo();
166
+ return {
167
+ id: WALLET_CONNECT_WALLET_ID,
168
+ type: "walletconnect",
169
+ platforms,
170
+ appKit: appKitInstance,
171
+ name: walletInfo?.name ?? "WalletConnect",
172
+ icon: walletInfo?.icon ?? WALLET_CONNECT_ICON,
173
+ // One shared session: connecting opens the modal; the wallet
174
+ // approves namespaces in that single pairing. Disconnect is
175
+ // session-wide; re-pair to change the approved set.
176
+ connect: async () => {
177
+ if (!isConnected) await appKit.open();
178
+ },
179
+ disconnect: async () => {
180
+ if (isConnected) await appKit.disconnect();
181
+ },
182
+ isConnected
183
+ };
184
+ })
185
+ ).subscribe(subscriber);
186
+ return () => {
187
+ sub.unsubscribe();
188
+ unsubProviders();
189
+ };
190
+ });
191
+ }),
192
+ // refCount:false keeps the AppKit instance alive for the process lifetime
193
+ // once created: createAppKit runs at most once (Reown AppKit cannot be
194
+ // instantiated twice). With refCount:true the producer would re-run
195
+ // createAppKit whenever every subscriber drained and a new one
196
+ // re-subscribed — e.g. a React unmount/remount or StrictMode's
197
+ // mount→unmount→remount — throwing on the duplicate Lit web components and
198
+ // WalletConnect modal singleton. The replayed connector value also keeps
199
+ // the wallet list stable across such teardown/rebuild cycles.
200
+ shareReplay({ refCount: false, bufferSize: 1 })
201
+ );
202
+ setCachedAppKit(cachedAppKit, walletConnect.projectId);
203
+ }
204
+ return cachedAppKit;
205
+ };
29
206
 
30
207
  // src/api/kheopskit.ts
31
208
  import {
32
209
  combineLatest as combineLatest4,
33
210
  debounceTime,
34
- distinctUntilChanged,
211
+ distinctUntilChanged as distinctUntilChanged2,
35
212
  filter as filter3,
36
- map as map4,
37
- Observable as Observable4,
38
- shareReplay as shareReplay4,
213
+ map as map5,
214
+ Observable as Observable5,
215
+ shareReplay as shareReplay5,
39
216
  throttleTime
40
217
  } from "rxjs";
41
218
 
42
219
  // src/utils/createHydrationBuffer.ts
43
220
  import {
44
- BehaviorSubject,
221
+ BehaviorSubject as BehaviorSubject2,
45
222
  combineLatest,
46
223
  filter,
47
- map,
48
- Observable,
224
+ map as map2,
225
+ Observable as Observable2,
49
226
  Subscription,
50
- shareReplay,
227
+ shareReplay as shareReplay2,
51
228
  startWith,
52
229
  take,
53
230
  timer
54
231
  } from "rxjs";
55
232
  var createBufferCore = (cachedItems, liveItems$, gracePeriodMs, mergeFn, isConverged) => {
56
233
  if (gracePeriodMs <= 0 || cachedItems.length === 0) {
57
- return liveItems$.pipe(map((items) => ({ items, isHydrating: false })));
234
+ return liveItems$.pipe(map2((items) => ({ items, isHydrating: false })));
58
235
  }
59
- return new Observable((subscriber) => {
236
+ return new Observable2((subscriber) => {
60
237
  const subscriptions = new Subscription();
61
- const isHydrating$ = new BehaviorSubject(true);
238
+ const isHydrating$ = new BehaviorSubject2(true);
62
239
  const liveWithInitial$ = liveItems$.pipe(startWith([]));
63
240
  if (isConverged) {
64
241
  const timerFired$ = timer(gracePeriodMs).pipe(
65
- map(() => true),
242
+ map2(() => true),
66
243
  startWith(false),
67
- shareReplay({ bufferSize: 1, refCount: true })
244
+ shareReplay2({ bufferSize: 1, refCount: true })
68
245
  );
69
246
  subscriptions.add(
70
247
  combineLatest([liveWithInitial$, timerFired$]).pipe(
@@ -91,7 +268,7 @@ var createBufferCore = (cachedItems, liveItems$, gracePeriodMs, mergeFn, isConve
91
268
  }
92
269
  subscriptions.add(
93
270
  combineLatest([liveWithInitial$, isHydrating$]).pipe(
94
- map(([liveItems, isHydrating]) => {
271
+ map2(([liveItems, isHydrating]) => {
95
272
  if (!isHydrating) {
96
273
  return { items: liveItems, isHydrating: false };
97
274
  }
@@ -153,8 +330,8 @@ var createAccountHydrationBuffer = (cachedAccounts, liveAccounts$, gracePeriodMs
153
330
  };
154
331
 
155
332
  // src/utils/logObservable.ts
156
- import { tap } from "rxjs";
157
- var logObservable = (label, opts) => tap((value) => {
333
+ import { tap as tap2 } from "rxjs";
334
+ var logObservable = (label, opts) => tap2((value) => {
158
335
  const { printValue = false, enabled = true } = opts || {};
159
336
  if (!label || !enabled) return;
160
337
  const text = `[kheopskit] observable ${label} emit`;
@@ -163,68 +340,86 @@ var logObservable = (label, opts) => tap((value) => {
163
340
  });
164
341
 
165
342
  // src/api/accounts.ts
166
- import { combineLatest as combineLatest2, map as map2, Observable as Observable2, of, shareReplay as shareReplay2 } from "rxjs";
343
+ import { combineLatest as combineLatest2, map as map3, Observable as Observable3, of as of2, shareReplay as shareReplay3 } from "rxjs";
167
344
  var getAccounts$ = (config, wallets) => {
168
- return new Observable2((subscriber) => {
345
+ return new Observable3((subscriber) => {
169
346
  const sources = config.platforms.map(
170
347
  (plugin) => plugin.getAccounts$(
171
348
  wallets.pipe(
172
- map2((ws) => ws.filter((w) => w.platform === plugin.platform))
349
+ map3(
350
+ (ws) => ws.filter(
351
+ (w) => isWalletConnectWallet(w) || w.platform === plugin.platform
352
+ )
353
+ )
173
354
  )
174
355
  )
175
356
  );
176
357
  const accounts$ = sources.length ? combineLatest2(sources).pipe(
177
- map2((accounts) => accounts.flat().sort(sortAccounts))
178
- ) : of([]);
358
+ map3((accounts) => accounts.flat().sort(sortAccounts))
359
+ ) : of2([]);
179
360
  const sub = accounts$.subscribe(subscriber);
180
361
  return () => {
181
362
  sub.unsubscribe();
182
363
  };
183
- }).pipe(shareReplay2({ refCount: true, bufferSize: 1 }));
364
+ }).pipe(shareReplay3({ refCount: true, bufferSize: 1 }));
184
365
  };
185
366
 
186
367
  // src/api/wallets.ts
187
368
  import {
188
369
  combineLatest as combineLatest3,
189
370
  filter as filter2,
190
- map as map3,
371
+ map as map4,
191
372
  mergeMap,
192
- Observable as Observable3,
193
- of as of2,
194
- shareReplay as shareReplay3,
373
+ Observable as Observable4,
374
+ of as of3,
375
+ shareReplay as shareReplay4,
195
376
  take as take2
196
377
  } from "rxjs";
197
378
  var getWallets$ = (config, store2 = store) => {
198
379
  const autoReconnectWalletIds$ = store2.observable.pipe(
199
- map3((s) => s.autoReconnect ?? []),
380
+ map4((s) => s.autoReconnect ?? []),
200
381
  take2(1),
201
- shareReplay3({ bufferSize: 1, refCount: true })
382
+ shareReplay4({ bufferSize: 1, refCount: true })
202
383
  );
203
- return new Observable3((subscriber) => {
384
+ return new Observable4((subscriber) => {
204
385
  const ctx = { config, store: store2 };
205
386
  const observables = config.platforms.map(
206
387
  (plugin) => plugin.getWallets$(ctx)
207
388
  );
208
- const wallets$ = observables.length ? combineLatest3(observables).pipe(
209
- map3((wallets) => wallets.flat().sort(sortWallets))
389
+ const platformWallets$ = observables.length ? combineLatest3(observables).pipe(map4((wallets) => wallets.flat())) : of3([]);
390
+ const wallets$ = combineLatest3([
391
+ platformWallets$,
392
+ getWalletConnectWallet$(config)
393
+ ]).pipe(
394
+ map4(([platformWallets, walletConnect]) => {
395
+ const all = walletConnect ? [...platformWallets, walletConnect] : platformWallets;
396
+ return all.sort(sortWallets);
397
+ })
210
398
  // Note: No startWith([]) here - the hydration buffer handles initial state
211
- ) : of2([]);
399
+ );
212
400
  const reconnectingWallets = /* @__PURE__ */ new Set();
213
401
  const reconnectedWallets = /* @__PURE__ */ new Set();
402
+ const MAX_RECONNECT_ATTEMPTS = 3;
403
+ const failedAttempts = /* @__PURE__ */ new Map();
214
404
  const subAutoReconnect = combineLatest3([wallets$, autoReconnectWalletIds$]).pipe(
215
405
  filter2(([, walletIds]) => config.autoReconnect && !!walletIds?.length),
216
406
  mergeMap(
217
407
  ([wallets, walletIds]) => wallets.filter((wallet) => walletIds?.includes(wallet.id))
218
408
  )
219
409
  ).subscribe(async (wallet) => {
220
- if (wallet.isConnected || reconnectingWallets.has(wallet.id) || reconnectedWallets.has(wallet.id)) {
410
+ if (wallet.isConnected || reconnectingWallets.has(wallet.id) || reconnectedWallets.has(wallet.id) || (failedAttempts.get(wallet.id) ?? 0) >= MAX_RECONNECT_ATTEMPTS) {
221
411
  return;
222
412
  }
223
413
  reconnectingWallets.add(wallet.id);
224
414
  try {
225
415
  await wallet.connect();
226
416
  reconnectedWallets.add(wallet.id);
417
+ failedAttempts.delete(wallet.id);
227
418
  } catch (err) {
419
+ failedAttempts.set(
420
+ wallet.id,
421
+ (failedAttempts.get(wallet.id) ?? 0) + 1
422
+ );
228
423
  console.error("Failed to reconnect wallet %s", wallet.id, { err });
229
424
  } finally {
230
425
  reconnectingWallets.delete(wallet.id);
@@ -235,11 +430,12 @@ var getWallets$ = (config, store2 = store) => {
235
430
  subAutoReconnect.unsubscribe();
236
431
  subWallets.unsubscribe();
237
432
  };
238
- }).pipe(shareReplay3({ refCount: true, bufferSize: 1 }));
433
+ }).pipe(shareReplay4({ refCount: true, bufferSize: 1 }));
239
434
  };
240
435
 
241
436
  // src/api/kheopskit.ts
242
- var getKheopskit$ = (config, ssrCookies, existingStore) => {
437
+ var getKheopskit$ = (config, options = {}) => {
438
+ const { ssrCookies, store: existingStore } = options;
243
439
  const kc = resolveConfig(config);
244
440
  const store2 = existingStore ?? createKheopskitStore({ ssrCookies, storageKey: kc.storageKey });
245
441
  if (kc.debug) console.debug("[kheopskit] config", kc);
@@ -266,7 +462,7 @@ var getKheopskit$ = (config, ssrCookies, existingStore) => {
266
462
  accounts: cachedAccounts.length
267
463
  });
268
464
  }
269
- return new Observable4((subscriber) => {
465
+ return new Observable5((subscriber) => {
270
466
  const liveWallets$ = getWallets$(kc, store2);
271
467
  const liveAccounts$ = getAccounts$(kc, liveWallets$);
272
468
  const bufferedWallets$ = createHydrationBuffer(
@@ -313,16 +509,16 @@ var getKheopskit$ = (config, ssrCookies, existingStore) => {
313
509
  }
314
510
  );
315
511
  const sharedWallets$ = bufferedWallets$.pipe(
316
- shareReplay4({ bufferSize: 1, refCount: true })
512
+ shareReplay5({ bufferSize: 1, refCount: true })
317
513
  );
318
514
  const sharedAccounts$ = bufferedAccounts$.pipe(
319
- shareReplay4({ bufferSize: 1, refCount: true })
515
+ shareReplay5({ bufferSize: 1, refCount: true })
320
516
  );
321
517
  const subscription = combineLatest4({
322
518
  wallets: sharedWallets$,
323
519
  accounts: sharedAccounts$
324
520
  }).pipe(
325
- map4(({ wallets, accounts }) => {
521
+ map5(({ wallets, accounts }) => {
326
522
  if (kc.debug) {
327
523
  console.debug("[kheopskit] hydration state", {
328
524
  walletsHydrating: wallets.isHydrating,
@@ -349,13 +545,16 @@ var getKheopskit$ = (config, ssrCookies, existingStore) => {
349
545
  ),
350
546
  // Debounce to avoid excessive writes
351
547
  debounceTime(1e3),
352
- // Only persist if state actually changed
353
- distinctUntilChanged((prev, curr) => {
354
- const prevWalletIds = prev.wallets.items.map((w) => w.id);
355
- const currWalletIds = curr.wallets.items.map((w) => w.id);
356
- const prevAccountIds = prev.accounts.items.map((a) => a.id);
357
- const currAccountIds = curr.accounts.items.map((a) => a.id);
358
- return arraysEqual(prevWalletIds, currWalletIds) && arraysEqual(prevAccountIds, currAccountIds);
548
+ // Only persist if the serialized snapshot would actually change.
549
+ // Compare the persisted fields (not just ids): an Ethereum chain switch
550
+ // keeps the same account id but changes the cached chainId, so an
551
+ // id-only comparator would skip persisting it.
552
+ distinctUntilChanged2((prev, curr) => {
553
+ const prevWalletKeys = prev.wallets.items.map(walletPersistKey);
554
+ const currWalletKeys = curr.wallets.items.map(walletPersistKey);
555
+ const prevAccountKeys = prev.accounts.items.map(accountChangeKey);
556
+ const currAccountKeys = curr.accounts.items.map(accountChangeKey);
557
+ return arraysEqual(prevWalletKeys, currWalletKeys) && arraysEqual(prevAccountKeys, currAccountKeys);
359
558
  })
360
559
  ).subscribe(({ wallets, accounts }) => {
361
560
  const connectedWalletIds = new Set(
@@ -387,34 +586,37 @@ var getKheopskit$ = (config, ssrCookies, existingStore) => {
387
586
  persistSub.unsubscribe();
388
587
  };
389
588
  }).pipe(
390
- distinctUntilChanged(statesEqual),
589
+ distinctUntilChanged2(statesEqual),
391
590
  throttleTime(16, void 0, { leading: true, trailing: true }),
392
591
  // ~1 frame at 60fps
393
592
  logObservable("kheopskit$", { enabled: kc.debug, printValue: true }),
394
- shareReplay4({ bufferSize: 1, refCount: true })
593
+ shareReplay5({ bufferSize: 1, refCount: true })
395
594
  // The runtime objects are the concrete per-plugin wallet/account types;
396
595
  // recover the precise KheopskitState<P> the caller's plugins imply.
397
596
  );
398
597
  };
399
598
  var arraysEqual = (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
400
- var statesEqual = (a, b) => a.isHydrating === b.isHydrating && a.wallets.length === b.wallets.length && a.accounts.length === b.accounts.length && a.wallets.every(
401
- (w, i) => w.id === b.wallets[i]?.id && w.isConnected === b.wallets[i]?.isConnected
402
- ) && a.accounts.every((acc, i) => {
403
- const other = b.accounts[i];
404
- if (acc.id !== other?.id) return false;
405
- switch (acc.platform) {
599
+ var accountChangeKey = (account) => {
600
+ switch (account.platform) {
406
601
  case "ethereum":
407
- return acc.chainId === other.chainId;
602
+ return `${account.id}|${account.chainId ?? ""}`;
408
603
  case "polkadot":
409
- return acc.type === other.type;
604
+ return `${account.id}|${account.type ?? ""}`;
410
605
  case "solana":
411
- return arraysEqual(
412
- acc.chains ?? [],
413
- other.chains ?? []
414
- );
606
+ return `${account.id}|${(account.chains ?? []).join(",")}`;
415
607
  default:
416
- return true;
608
+ return account.id;
417
609
  }
610
+ };
611
+ var walletPlatforms = (wallet) => isWalletConnectWallet(wallet) ? wallet.platforms.join(",") : "";
612
+ var walletPersistKey = (wallet) => `${wallet.id}|${wallet.isConnected ? 1 : 0}|${wallet.name}`;
613
+ var walletUiKey = (wallet) => `${walletPersistKey(wallet)}|${wallet.icon}|${walletPlatforms(wallet)}`;
614
+ var statesEqual = (a, b) => a.isHydrating === b.isHydrating && a.wallets.length === b.wallets.length && a.accounts.length === b.accounts.length && a.wallets.every((w, i) => {
615
+ const other = b.wallets[i];
616
+ return !!other && walletUiKey(w) === walletUiKey(other);
617
+ }) && a.accounts.every((acc, i) => {
618
+ const other = b.accounts[i];
619
+ return !!other && accountChangeKey(acc) === accountChangeKey(other);
418
620
  });
419
621
  export {
420
622
  DEFAULT_STORAGE_KEY,
@@ -425,7 +627,11 @@ export {
425
627
  getKheopskit$,
426
628
  getWalletAccountId,
427
629
  getWalletId,
630
+ isInjectedWallet,
428
631
  isValidAddress,
632
+ isValidWalletId,
633
+ isWalletConnectWallet,
634
+ parseWalletAccountId,
429
635
  parseWalletId,
430
636
  resetAppKitCache,
431
637
  resolveConfig