@kheopskit/core 4.0.0 → 5.0.0

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
@@ -2,9 +2,10 @@ import {
2
2
  POLKADOT_EXTENSIONS
3
3
  } from "./chunk-BWUUHUDK.mjs";
4
4
  import {
5
+ isWalletConnectWallet,
5
6
  parseWalletId,
6
7
  safeLocalStorage
7
- } from "./chunk-PNPPI5CH.mjs";
8
+ } from "./chunk-7QSGAJ4A.mjs";
8
9
 
9
10
  // src/utils/hydrateState.ts
10
11
  var lookupWalletIcon = (platform, identifier) => {
@@ -22,10 +23,22 @@ var PendingWalletError = class extends Error {
22
23
  }
23
24
  };
24
25
  var hydrateWallet = (cached) => {
25
- const { platform, identifier } = parseWalletId(cached.id);
26
26
  const throwPending = () => {
27
27
  throw new PendingWalletError(cached.id);
28
28
  };
29
+ if (cached.type === "walletconnect") {
30
+ return {
31
+ id: cached.id,
32
+ type: "walletconnect",
33
+ platforms: [],
34
+ name: cached.name,
35
+ icon: "",
36
+ isConnected: cached.isConnected,
37
+ connect: throwPending,
38
+ disconnect: throwPending
39
+ };
40
+ }
41
+ const { platform, identifier } = parseWalletId(cached.id);
29
42
  return {
30
43
  id: cached.id,
31
44
  platform: cached.platform,
@@ -54,7 +67,8 @@ var hydrateAccount = (cached) => ({
54
67
  });
55
68
  var serializeWallet = (wallet) => ({
56
69
  id: wallet.id,
57
- platform: wallet.platform,
70
+ // The WalletConnect connector has no platform.
71
+ platform: isWalletConnectWallet(wallet) ? void 0 : wallet.platform,
58
72
  type: wallet.type,
59
73
  name: wallet.name,
60
74
  // Note: icon is NOT stored to save cookie space
@@ -135,10 +149,11 @@ var PLATFORM_ORDER2 = {
135
149
  ethereum: 1,
136
150
  solana: 2
137
151
  };
152
+ var orderOf = (wallet) => isWalletConnectWallet(wallet) ? 3 : PLATFORM_ORDER2[wallet.platform];
138
153
  var sortWallets = (w1, w2) => {
139
- if (w1.platform !== w2.platform) {
140
- return PLATFORM_ORDER2[w1.platform] - PLATFORM_ORDER2[w2.platform];
141
- }
154
+ const o1 = orderOf(w1);
155
+ const o2 = orderOf(w2);
156
+ if (o1 !== o2) return o1 - o2;
142
157
  if (w1.name.toLowerCase() === "talisman") return -1;
143
158
  if (w2.name.toLowerCase() === "talisman") return 1;
144
159
  return w1.name.localeCompare(w2.name);
@@ -161,4 +176,4 @@ export {
161
176
  sortWallets,
162
177
  acceptsCachedAccount
163
178
  };
164
- //# sourceMappingURL=chunk-4RBYRNY3.mjs.map
179
+ //# sourceMappingURL=chunk-YDLCHYHH.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/hydrateState.ts","../src/utils/iconCache.ts","../src/utils/sortAccounts.ts","../src/utils/sortWallets.ts","../src/api/platform.ts"],"sourcesContent":["import {\n\ttype BaseWallet,\n\ttype BaseWalletAccount,\n\ttype CachedAccount,\n\ttype CachedWallet,\n\tisWalletConnectWallet,\n\ttype PolkadotAccountType,\n\ttype WalletConnectWallet,\n} from \"../api/types\";\nimport { POLKADOT_EXTENSIONS } from \"./polkadotExtensions\";\nimport type { WalletAccountId } from \"./WalletAccountId\";\nimport { parseWalletId, type WalletId } from \"./WalletId\";\n\n/**\n * Looks up the icon for a wallet from known Polkadot extensions only.\n * Ethereum icons will be populated from the localStorage icon cache via the merge function.\n *\n * Note: We DON'T use localStorage icon cache here because hydrateWallet is called\n * during SSR (server) and client hydration. localStorage isn't available on server,\n * so using it would cause a hydration mismatch. Icons for Ethereum wallets will be\n * populated when the hydration buffer merges cached wallets with live wallets.\n */\nconst lookupWalletIcon = (platform: string, identifier: string): string => {\n\t// Only Polkadot extensions have hardcoded icons that are safe for SSR\n\tif (platform === \"polkadot\") {\n\t\treturn POLKADOT_EXTENSIONS[identifier]?.icon ?? \"\";\n\t}\n\t// Ethereum icons come from localStorage or live wallets - not here\n\treturn \"\";\n};\n\n/**\n * Error thrown when trying to use a placeholder wallet that hasn't fully loaded yet.\n */\nclass PendingWalletError extends Error {\n\tconstructor(walletId: string) {\n\t\tsuper(\n\t\t\t`Wallet ${walletId} is still loading. Wait for isHydrating to be false before calling connect/disconnect.`,\n\t\t);\n\t\tthis.name = \"PendingWalletError\";\n\t}\n}\n\n/**\n * Converts a CachedWallet to a placeholder wallet for SSR hydration display.\n *\n * The placeholder carries only the SDK-free {@link BaseWallet} fields; the real\n * wallet (with its injected provider/extension/standard-wallet handle) replaces\n * it once it loads. connect/disconnect throw until then.\n */\nexport const hydrateWallet = (\n\tcached: CachedWallet,\n): BaseWallet | WalletConnectWallet => {\n\tconst throwPending = () => {\n\t\tthrow new PendingWalletError(cached.id);\n\t};\n\n\t// The platform-less WalletConnect connector. `appKit`/`platforms` are SDK\n\t// state absent until the live connector loads (cast like other placeholder\n\t// SDK handles); icon is filled from the localStorage cache by the caller.\n\tif (cached.type === \"walletconnect\") {\n\t\treturn {\n\t\t\tid: cached.id,\n\t\t\ttype: \"walletconnect\",\n\t\t\tplatforms: [],\n\t\t\tname: cached.name,\n\t\t\ticon: \"\",\n\t\t\tisConnected: cached.isConnected,\n\t\t\tconnect: throwPending,\n\t\t\tdisconnect: throwPending,\n\t\t} as unknown as WalletConnectWallet;\n\t}\n\n\tconst { platform, identifier } = parseWalletId(cached.id);\n\n\treturn {\n\t\tid: cached.id,\n\t\tplatform: cached.platform as BaseWallet[\"platform\"],\n\t\ttype: cached.type,\n\t\tname: cached.name,\n\t\ticon: lookupWalletIcon(platform, identifier),\n\t\tisConnected: cached.isConnected,\n\t\tconnect: throwPending,\n\t\tdisconnect: throwPending,\n\t};\n};\n\n/**\n * Converts a CachedAccount to a placeholder account for SSR hydration display.\n *\n * The placeholder carries the SDK-free {@link BaseWalletAccount} fields plus the\n * plain, serializable platform data that lives in the cache — Ethereum `chainId`\n * and the Polkadot key `type`. Those render immediately on reload (no blank →\n * value flicker) and match what the live account will report. Only the SDK\n * handles (`client`/`signer`/`polkadotSigner`) are absent until the real account\n * replaces this placeholder; signing stays gated on `isHydrating` until then.\n */\nexport const hydrateAccount = (cached: CachedAccount): BaseWalletAccount => ({\n\tid: cached.id as WalletAccountId,\n\tplatform: cached.platform,\n\taddress: cached.address,\n\tname: cached.name,\n\twalletId: cached.walletId,\n\twalletName: cached.walletName,\n\t// Spread (not direct keys) so the extra platform fields don't trip the\n\t// excess-property check against BaseWalletAccount; they're read back via the\n\t// platform-specific account types once narrowed by `platform`.\n\t...(cached.platform === \"ethereum\" && { chainId: cached.chainId }),\n\t...(cached.platform === \"polkadot\" && {\n\t\ttype: cached.polkadotAccountType,\n\t}),\n});\n\n/**\n * Converts a wallet to a CachedWallet for storage.\n * Only extracts the serializable properties needed for hydration.\n */\nexport const serializeWallet = (\n\twallet: BaseWallet | WalletConnectWallet,\n): CachedWallet => ({\n\tid: wallet.id,\n\t// The WalletConnect connector has no platform.\n\tplatform: isWalletConnectWallet(wallet) ? undefined : wallet.platform,\n\ttype: wallet.type,\n\tname: wallet.name,\n\t// Note: icon is NOT stored to save cookie space\n\tisConnected: wallet.isConnected,\n});\n\n/**\n * Converts an account to a CachedAccount for storage.\n * Only extracts the serializable properties needed for hydration. Platform-only\n * fields (Ethereum chainId, Polkadot key type) are read defensively so this\n * stays SDK-free.\n */\nexport const serializeAccount = (\n\taccount: BaseWalletAccount,\n): CachedAccount => ({\n\tid: account.id,\n\tplatform: account.platform,\n\taddress: account.address,\n\tname: account.name,\n\tchainId:\n\t\taccount.platform === \"ethereum\"\n\t\t\t? (account as { chainId?: number }).chainId\n\t\t\t: undefined,\n\tpolkadotAccountType:\n\t\taccount.platform === \"polkadot\"\n\t\t\t? (account as { type?: PolkadotAccountType }).type\n\t\t\t: undefined,\n\twalletId: account.walletId as WalletId,\n\twalletName: account.walletName,\n});\n","import { safeLocalStorage } from \"./storage\";\n\n/**\n * Storage key for the icon cache in localStorage.\n */\nconst ICON_CACHE_KEY = \"kheopskit-icons\";\n\n/**\n * Icon cache type: a map of wallet ID to icon data URI or URL.\n */\ntype IconCache = Record<string, string>;\n\n/**\n * In-memory cache to avoid repeated localStorage reads.\n */\nlet memoryCache: IconCache | null = null;\n\n/**\n * Loads the icon cache from localStorage.\n */\nconst loadCache = (): IconCache => {\n\tif (memoryCache !== null) return memoryCache;\n\n\ttry {\n\t\tconst stored = safeLocalStorage.getItem(ICON_CACHE_KEY);\n\t\tmemoryCache = stored ? (JSON.parse(stored) as IconCache) : {};\n\t} catch {\n\t\tmemoryCache = {};\n\t}\n\treturn memoryCache;\n};\n\n/**\n * Saves the icon cache to localStorage.\n */\nconst saveCache = (cache: IconCache): void => {\n\ttry {\n\t\tsafeLocalStorage.setItem(ICON_CACHE_KEY, JSON.stringify(cache));\n\t\tmemoryCache = cache;\n\t} catch {\n\t\t// localStorage may be full or unavailable\n\t}\n};\n\n/**\n * Gets a cached icon for a wallet.\n * @param walletId - The wallet ID (e.g., \"ethereum:io.talisman\")\n * @returns The cached icon data URI, or undefined if not cached\n */\nexport const getCachedIcon = (walletId: string): string | undefined => {\n\tconst cache = loadCache();\n\treturn cache[walletId] || undefined;\n};\n\n/**\n * Sets multiple cached icons at once.\n * More efficient than calling setCachedIcon multiple times.\n * @param icons - Map of wallet ID to icon\n */\nexport const setCachedIcons = (icons: Record<string, string>): void => {\n\tconst cache = loadCache();\n\tlet changed = false;\n\n\tfor (const [walletId, icon] of Object.entries(icons)) {\n\t\tif (icon && cache[walletId] !== icon) {\n\t\t\tcache[walletId] = icon;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\tif (changed) {\n\t\tsaveCache(cache);\n\t}\n};\n","import type { BaseWalletAccount, WalletPlatform } from \"../api/types\";\n\nconst PLATFORM_ORDER: Record<WalletPlatform, number> = {\n\tpolkadot: 0,\n\tethereum: 1,\n\tsolana: 2,\n};\n\n// Group accounts by wallet, surfacing Talisman first (case-insensitive).\nconst byWalletName = (a1: BaseWalletAccount, a2: BaseWalletAccount) => {\n\tif (a1.walletName.toLowerCase() === \"talisman\") return -1;\n\tif (a2.walletName.toLowerCase() === \"talisman\") return 1;\n\treturn a1.walletName.localeCompare(a2.walletName);\n};\n\nexport const sortAccounts = (a1: BaseWalletAccount, a2: BaseWalletAccount) => {\n\t// Sort by platform first: polkadot, then ethereum, then solana\n\tif (a1.platform !== a2.platform)\n\t\treturn PLATFORM_ORDER[a1.platform] - PLATFORM_ORDER[a2.platform];\n\n\t// Then group by wallet name\n\tif (a1.walletName !== a2.walletName) return byWalletName(a1, a2);\n\n\t// Polkadot accounts expose a friendly name; fall back to address\n\tif (a1.platform === \"polkadot\" && a2.platform === \"polkadot\")\n\t\treturn a1.name !== a2.name\n\t\t\t? (a1.name ?? \"\").localeCompare(a2.name ?? \"\")\n\t\t\t: a1.address.localeCompare(a2.address);\n\n\t// Ethereum and Solana accounts disambiguate by id\n\treturn a1.id.localeCompare(a2.id);\n};\n","import {\n\ttype BaseWallet,\n\tisWalletConnectWallet,\n\ttype WalletConnectWallet,\n\ttype WalletPlatform,\n} from \"../api/types\";\n\nconst PLATFORM_ORDER: Record<WalletPlatform, number> = {\n\tpolkadot: 0,\n\tethereum: 1,\n\tsolana: 2,\n};\n\n// The platform-less WalletConnect connector sorts after all platform wallets.\nconst orderOf = (wallet: BaseWallet | WalletConnectWallet) =>\n\tisWalletConnectWallet(wallet) ? 3 : PLATFORM_ORDER[wallet.platform];\n\nexport const sortWallets = (\n\tw1: BaseWallet | WalletConnectWallet,\n\tw2: BaseWallet | WalletConnectWallet,\n) => {\n\t// Sort by platform first: polkadot, then ethereum, then solana, then WC\n\tconst o1 = orderOf(w1);\n\tconst o2 = orderOf(w2);\n\tif (o1 !== o2) return o1 - o2;\n\n\t// Sort by name, but Talisman first\n\tif (w1.name.toLowerCase() === \"talisman\") return -1;\n\tif (w2.name.toLowerCase() === \"talisman\") return 1;\n\n\treturn w1.name.localeCompare(w2.name);\n};\n","import type { CachedAccount, KheopskitPlatform } from \"./types\";\n\n/**\n * Whether a cached account should survive SSR hydration, per its platform\n * plugin's `acceptsCachedAccount` hook. Plugins without the hook (and platforms\n * with no enabled plugin) accept all — matching the pre-plugin behavior where\n * only Polkadot accounts were filtered (by key type).\n */\nexport const acceptsCachedAccount = (\n\tcached: CachedAccount,\n\tplatforms: readonly KheopskitPlatform[],\n): boolean => {\n\tconst plugin = platforms.find((p) => p.platform === cached.platform);\n\treturn plugin?.acceptsCachedAccount?.(cached) ?? true;\n};\n"],"mappings":"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","names":["PLATFORM_ORDER"]}
@@ -1,4 +1,5 @@
1
- import { W as WalletAccountId, a as WalletId, E as EthereumAppKitWallet, K as KheopskitPlatform } from './types-BNzRUNw-.mjs';
1
+ import { W as WalletAccountId, a as WalletId, K as KheopskitPlatform } from './types-C7V7DGlg.mjs';
2
+ export { b as WalletConnectWallet, i as isInjectedWallet, c as isWalletConnectWallet } from './types-C7V7DGlg.mjs';
2
3
  import { WalletClient, CustomTransport, Account, EIP1193Provider } from 'viem';
3
4
  import 'rxjs';
4
5
 
@@ -28,7 +29,7 @@ type EthereumInjectedWallet = {
28
29
  connect: () => Promise<void>;
29
30
  disconnect: () => Promise<void>;
30
31
  };
31
- type EthereumWallet = EthereumInjectedWallet | EthereumAppKitWallet;
32
+ type EthereumWallet = EthereumInjectedWallet;
32
33
  type EthereumAccount = {
33
34
  id: WalletAccountId;
34
35
  platform: "ethereum";
@@ -57,4 +58,4 @@ type EthereumAccount = {
57
58
  */
58
59
  declare const ethereum: () => KheopskitPlatform<"ethereum", EthereumWallet, EthereumAccount>;
59
60
 
60
- export { type EthereumAccount, EthereumAppKitWallet, type EthereumInjectedWallet, type EthereumWallet, ethereum, isEthereumAddress };
61
+ export { type EthereumAccount, type EthereumInjectedWallet, type EthereumWallet, ethereum, isEthereumAddress };
@@ -1,4 +1,5 @@
1
- import { W as WalletAccountId, a as WalletId, E as EthereumAppKitWallet, K as KheopskitPlatform } from './types-BNzRUNw-.js';
1
+ import { W as WalletAccountId, a as WalletId, K as KheopskitPlatform } from './types-C7V7DGlg.js';
2
+ export { b as WalletConnectWallet, i as isInjectedWallet, c as isWalletConnectWallet } from './types-C7V7DGlg.js';
2
3
  import { WalletClient, CustomTransport, Account, EIP1193Provider } from 'viem';
3
4
  import 'rxjs';
4
5
 
@@ -28,7 +29,7 @@ type EthereumInjectedWallet = {
28
29
  connect: () => Promise<void>;
29
30
  disconnect: () => Promise<void>;
30
31
  };
31
- type EthereumWallet = EthereumInjectedWallet | EthereumAppKitWallet;
32
+ type EthereumWallet = EthereumInjectedWallet;
32
33
  type EthereumAccount = {
33
34
  id: WalletAccountId;
34
35
  platform: "ethereum";
@@ -57,4 +58,4 @@ type EthereumAccount = {
57
58
  */
58
59
  declare const ethereum: () => KheopskitPlatform<"ethereum", EthereumWallet, EthereumAccount>;
59
60
 
60
- export { type EthereumAccount, EthereumAppKitWallet, type EthereumInjectedWallet, type EthereumWallet, ethereum, isEthereumAddress };
61
+ export { type EthereumAccount, type EthereumInjectedWallet, type EthereumWallet, ethereum, isEthereumAddress };
package/dist/ethereum.js CHANGED
@@ -1,16 +1,16 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }require('./chunk-FIAL4HTE.js');
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
3
 
4
4
 
5
5
 
6
+ var _chunkXQWJM3KCjs = require('./chunk-XQWJM3KC.js');
6
7
 
7
8
 
8
- var _chunkNU46D4MZjs = require('./chunk-NU46D4MZ.js');
9
9
 
10
10
 
11
11
 
12
12
 
13
- var _chunkSIUWQBT4js = require('./chunk-SIUWQBT4.js');
13
+ var _chunk4ENHC7G4js = require('./chunk-4ENHC7G4.js');
14
14
 
15
15
  // src/api/ethereum/accounts.ts
16
16
 
@@ -53,7 +53,7 @@ var toCaipNetworkId = (value) => {
53
53
  };
54
54
  var getInjectedWalletAccounts$ = (wallet) => {
55
55
  if (!wallet.isConnected) return _rxjs.of.call(void 0, []);
56
- return _chunkSIUWQBT4js.getCachedObservable$.call(void 0,
56
+ return _chunk4ENHC7G4js.getCachedObservable$.call(void 0,
57
57
  `accounts:${wallet.id}`,
58
58
  () => new (0, _rxjs.Observable)((subscriber) => {
59
59
  const addresses$ = new (0, _rxjs.ReplaySubject)(1);
@@ -64,7 +64,7 @@ var getInjectedWalletAccounts$ = (wallet) => {
64
64
  transport: _viem.custom.call(void 0, wallet.provider)
65
65
  });
66
66
  return {
67
- id: _chunkNU46D4MZjs.getWalletAccountId.call(void 0, wallet.id, address),
67
+ id: _chunkXQWJM3KCjs.getWalletAccountId.call(void 0, wallet.id, address),
68
68
  platform: "ethereum",
69
69
  client,
70
70
  address: _viem.getAddress.call(void 0, address),
@@ -112,26 +112,56 @@ var wrapWalletConnectProvider = (provider, sessionTopic, caipNetworkId) => {
112
112
  get(target, prop, receiver) {
113
113
  if (prop !== "request") return Reflect.get(target, prop, receiver);
114
114
  return (args) => {
115
- if (args && typeof args === "object" && args.method) {
116
- if (!args.topic) args.topic = sessionTopic;
117
- if (!args.chainId) args.chainId = caipNetworkId;
118
- }
119
- return target.request(args);
115
+ if (!args || typeof args !== "object" || !args.method)
116
+ return target.request(args);
117
+ const next = { ...args };
118
+ if (next.topic === void 0) next.topic = sessionTopic;
119
+ if (next.chainId === void 0 && caipNetworkId !== void 0)
120
+ next.chainId = caipNetworkId;
121
+ return target.request(next);
120
122
  };
121
123
  }
122
124
  });
123
125
  };
124
126
  var sameAddresses = (a, b) => a.length === b.length && a.every((addr, i) => addr === b[i]);
125
- var getAppKitAccounts$ = (wallet) => {
127
+ var getWalletConnectAccounts$ = (wallet) => {
126
128
  const provider = wallet.appKit.getProvider("eip155");
127
- if (!wallet.isConnected || !_optionalChain([wallet, 'access', _ => _.appKit, 'optionalAccess', _2 => _2.getAccount, 'call', _3 => _3("eip155"), 'optionalAccess', _4 => _4.allAccounts, 'access', _5 => _5.length]) || !_optionalChain([provider, 'optionalAccess', _6 => _6.session]))
129
+ if (!wallet.platforms.includes("ethereum") || !_optionalChain([provider, 'optionalAccess', _ => _.session]))
128
130
  return _rxjs.of.call(void 0, []);
129
- return _chunkSIUWQBT4js.getCachedObservable$.call(void 0,
130
- `accounts:${wallet.id}:`,
131
+ return _chunk4ENHC7G4js.getCachedObservable$.call(void 0,
132
+ `accounts:${wallet.id}:ethereum:`,
131
133
  () => new (0, _rxjs.Observable)((subscriber) => {
132
134
  const caipNetworkId$ = new (0, _rxjs.ReplaySubject)(1);
133
135
  const addresses$ = new (0, _rxjs.ReplaySubject)(1);
134
- const readAddresses = () => _nullishCoalesce(_optionalChain([wallet, 'access', _7 => _7.appKit, 'access', _8 => _8.getAccount, 'call', _9 => _9("eip155"), 'optionalAccess', _10 => _10.allAccounts, 'access', _11 => _11.map, 'call', _12 => _12((acc) => acc.address)]), () => ( []));
136
+ const readAddresses = () => {
137
+ const session = provider.session;
138
+ if (!session) return [];
139
+ const addresses = /* @__PURE__ */ new Set();
140
+ for (const namespace of Object.values(session.namespaces)) {
141
+ for (const account of _nullishCoalesce(namespace.accounts, () => ( []))) {
142
+ if (!account.startsWith("eip155:")) continue;
143
+ const raw = account.split(":")[2];
144
+ if (!raw) continue;
145
+ try {
146
+ addresses.add(_viem.getAddress.call(void 0, raw));
147
+ } catch (e) {
148
+ }
149
+ }
150
+ }
151
+ return [...addresses];
152
+ };
153
+ const readCaipNetworkId = () => {
154
+ const session = provider.session;
155
+ if (!session) return void 0;
156
+ for (const namespace of Object.values(session.namespaces)) {
157
+ for (const account of _nullishCoalesce(namespace.accounts, () => ( []))) {
158
+ if (!account.startsWith("eip155:")) continue;
159
+ const ref = account.split(":")[1];
160
+ if (ref) return `eip155:${ref}`;
161
+ }
162
+ }
163
+ return void 0;
164
+ };
135
165
  const handleChainChanged = (chainId) => {
136
166
  const caipNetworkId = toCaipNetworkId(chainId);
137
167
  if (caipNetworkId) {
@@ -142,7 +172,9 @@ var getAppKitAccounts$ = (wallet) => {
142
172
  provider.on("chainChanged", handleChainChanged);
143
173
  provider.on("accountsChanged", handleAccountsChanged);
144
174
  provider.on("session_update", handleAccountsChanged);
145
- provider.request({ method: "eth_chainId" }).then(handleChainChanged);
175
+ caipNetworkId$.next(readCaipNetworkId());
176
+ provider.request({ method: "eth_chainId" }).then(handleChainChanged).catch(() => {
177
+ });
146
178
  addresses$.next(readAddresses());
147
179
  const sub = _rxjs.combineLatest.call(void 0, [
148
180
  caipNetworkId$.pipe(_rxjs.distinctUntilChanged.call(void 0, )),
@@ -164,7 +196,7 @@ var getAppKitAccounts$ = (wallet) => {
164
196
  transport
165
197
  });
166
198
  return {
167
- id: _chunkNU46D4MZjs.getWalletAccountId.call(void 0, wallet.id, addr),
199
+ id: _chunkXQWJM3KCjs.getWalletAccountId.call(void 0, wallet.id, addr),
168
200
  platform: "ethereum",
169
201
  walletName: wallet.name,
170
202
  walletId: wallet.id,
@@ -190,8 +222,7 @@ var getEthereumAccounts$ = (ethereumWallets) => new (0, _rxjs.Observable)((subsc
190
222
  _rxjs.switchMap.call(void 0, (wallets) => {
191
223
  return wallets.length ? _rxjs.combineLatest.call(void 0, [
192
224
  ...wallets.filter((w) => w.type === "injected").map(getInjectedWalletAccounts$),
193
- ...wallets.filter((w) => w.type === "appKit").map(getAppKitAccounts$)
194
- // todo appkit
225
+ ...wallets.filter(_chunk4ENHC7G4js.isWalletConnectWallet).map(getWalletConnectAccounts$)
195
226
  ]) : _rxjs.of.call(void 0, []);
196
227
  }),
197
228
  _rxjs.map.call(void 0, (accounts) => accounts.flat()),
@@ -207,7 +238,7 @@ var getEthereumAccounts$ = (ethereumWallets) => new (0, _rxjs.Observable)((subsc
207
238
  var isSameAccountsList = (a, b) => {
208
239
  if (a.length !== b.length) return false;
209
240
  return a.every(
210
- (account, i) => account.id === _optionalChain([b, 'access', _13 => _13[i], 'optionalAccess', _14 => _14.id]) && account.chainId === _optionalChain([b, 'access', _15 => _15[i], 'optionalAccess', _16 => _16.chainId])
241
+ (account, i) => account.id === _optionalChain([b, 'access', _2 => _2[i], 'optionalAccess', _3 => _3.id]) && account.chainId === _optionalChain([b, 'access', _4 => _4[i], 'optionalAccess', _5 => _5.chainId])
211
242
  );
212
243
  };
213
244
 
@@ -246,7 +277,7 @@ var createEthereumInjectedWallets$ = (store2) => new (0, _rxjs.Observable)((subs
246
277
  const enabledWalletIds$ = new (0, _rxjs.BehaviorSubject)(/* @__PURE__ */ new Set());
247
278
  const connectWallet = async (walletId, provider) => {
248
279
  if (enabledWalletIds$.value.has(walletId))
249
- throw new (0, _chunkNU46D4MZjs.KheopskitError)(
280
+ throw new (0, _chunkXQWJM3KCjs.KheopskitError)(
250
281
  "WALLET_ALREADY_CONNECTED",
251
282
  `wallet ${walletId} is already connected`,
252
283
  { walletId }
@@ -261,7 +292,7 @@ var createEthereumInjectedWallets$ = (store2) => new (0, _rxjs.Observable)((subs
261
292
  };
262
293
  const disconnectWallet = async (walletId) => {
263
294
  if (!enabledWalletIds$.value.has(walletId))
264
- throw new (0, _chunkNU46D4MZjs.KheopskitError)(
295
+ throw new (0, _chunkXQWJM3KCjs.KheopskitError)(
265
296
  "WALLET_NOT_CONNECTED",
266
297
  `wallet ${walletId} is not connected`,
267
298
  { walletId }
@@ -270,12 +301,12 @@ var createEthereumInjectedWallets$ = (store2) => new (0, _rxjs.Observable)((subs
270
301
  newSet.delete(walletId);
271
302
  enabledWalletIds$.next(newSet);
272
303
  store2.removeEnabledWalletId(walletId);
273
- _chunkSIUWQBT4js.clearCachedObservable.call(void 0, `accounts:${walletId}`);
304
+ _chunk4ENHC7G4js.clearCachedObservable.call(void 0, `accounts:${walletId}`);
274
305
  };
275
306
  const sub = _rxjs.combineLatest.call(void 0, [providersDetails$, enabledWalletIds$]).pipe(
276
307
  _rxjs.map.call(void 0, ([providerDetails, enabledWalletIds]) => {
277
308
  return providerDetails.map((pd) => {
278
- const walletId = _chunkSIUWQBT4js.getWalletId.call(void 0, "ethereum", pd.info.rdns);
309
+ const walletId = _chunk4ENHC7G4js.getWalletId.call(void 0, "ethereum", pd.info.rdns);
279
310
  const provider = pd.provider;
280
311
  return {
281
312
  platform: "ethereum",
@@ -297,36 +328,24 @@ var createEthereumInjectedWallets$ = (store2) => new (0, _rxjs.Observable)((subs
297
328
  sub.unsubscribe();
298
329
  };
299
330
  }).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }));
300
- var getEthereumWallets$ = (config, store2 = _chunkNU46D4MZjs.store) => {
301
- return new (0, _rxjs.Observable)((subscriber) => {
302
- const subscription = _rxjs.combineLatest.call(void 0, [
303
- createEthereumInjectedWallets$(store2),
304
- _chunkNU46D4MZjs.getAppKitWallets$.call(void 0, config).pipe(_rxjs.map.call(void 0, (w) => w.ethereum))
305
- ]).pipe(
306
- _rxjs.map.call(void 0,
307
- ([injectedWallets, appKitWallet]) => appKitWallet ? [...injectedWallets, appKitWallet] : injectedWallets
308
- )
309
- ).subscribe(subscriber);
310
- return () => {
311
- subscription.unsubscribe();
312
- };
313
- }).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }));
314
- };
331
+ var getEthereumWallets$ = (store2 = _chunkXQWJM3KCjs.store) => createEthereumInjectedWallets$(store2);
315
332
  var walletsEqual = (a, b) => {
316
333
  if (a.length !== b.length) return false;
317
334
  return a.every(
318
- (w, i) => w.id === _optionalChain([b, 'access', _17 => _17[i], 'optionalAccess', _18 => _18.id]) && w.isConnected === _optionalChain([b, 'access', _19 => _19[i], 'optionalAccess', _20 => _20.isConnected]) && w.name === _optionalChain([b, 'access', _21 => _21[i], 'optionalAccess', _22 => _22.name])
335
+ (w, i) => w.id === _optionalChain([b, 'access', _6 => _6[i], 'optionalAccess', _7 => _7.id]) && w.isConnected === _optionalChain([b, 'access', _8 => _8[i], 'optionalAccess', _9 => _9.isConnected]) && w.name === _optionalChain([b, 'access', _10 => _10[i], 'optionalAccess', _11 => _11.name])
319
336
  );
320
337
  };
321
338
 
322
339
  // src/api/ethereum/plugin.ts
323
340
  var ethereum = () => ({
324
341
  platform: "ethereum",
325
- getWallets$: (ctx) => getEthereumWallets$(ctx.config, ctx.store),
342
+ getWallets$: (ctx) => getEthereumWallets$(ctx.store),
326
343
  getAccounts$: (wallets$) => getEthereumAccounts$(wallets$)
327
344
  });
328
345
 
329
346
 
330
347
 
331
- exports.ethereum = ethereum; exports.isEthereumAddress = _chunkNU46D4MZjs.isEthereumAddress;
348
+
349
+
350
+ exports.ethereum = ethereum; exports.isEthereumAddress = _chunkXQWJM3KCjs.isEthereumAddress; exports.isInjectedWallet = _chunk4ENHC7G4js.isInjectedWallet; exports.isWalletConnectWallet = _chunk4ENHC7G4js.isWalletConnectWallet;
332
351
  //# sourceMappingURL=ethereum.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/kheopskit/kheopskit/packages/core/dist/ethereum.js","../src/api/ethereum/accounts.ts","../src/api/ethereum/wallets.ts","../src/api/ethereum/plugin.ts"],"names":["combineLatest","distinctUntilChanged","map","Observable","shareReplay","providerDetails"],"mappings":"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","file":"/home/runner/work/kheopskit/kheopskit/packages/core/dist/ethereum.js","sourcesContent":[null,"import {\n\tcombineLatest,\n\tdistinctUntilChanged,\n\tmap,\n\tObservable,\n\tof,\n\tReplaySubject,\n\tshareReplay,\n\tswitchMap,\n} from \"rxjs\";\nimport {\n\tcreateWalletClient,\n\tcustom,\n\ttype EIP1193Provider,\n\tgetAddress,\n} from \"viem\";\nimport { getWalletAccountId } from \"../../utils\";\nimport { getCachedObservable$ } from \"../../utils/getCachedObservable\";\nimport type { EthereumAppKitWallet } from \"../types\";\nimport type {\n\tEthereumAccount,\n\tEthereumInjectedWallet,\n\tEthereumWallet,\n} from \"./types\";\n\nconst normalizeEvmChainId = (value: unknown): number | undefined => {\n\tlet raw = value;\n\n\tif (typeof raw === \"string\" && raw.startsWith(\"eip155:\")) {\n\t\traw = raw.slice(\"eip155:\".length);\n\t}\n\n\tif (typeof raw === \"bigint\") {\n\t\treturn raw >= 0n ? Number(raw) : undefined;\n\t}\n\n\tif (typeof raw === \"number\") {\n\t\treturn Number.isInteger(raw) && raw >= 0 ? raw : undefined;\n\t}\n\n\tif (typeof raw === \"string\") {\n\t\tconst normalized = raw.trim().toLowerCase();\n\t\tif (!normalized) return undefined;\n\t\tconst parsed = normalized.startsWith(\"0x\")\n\t\t\t? Number.parseInt(normalized, 16)\n\t\t\t: Number.parseInt(normalized, 10);\n\t\treturn Number.isNaN(parsed) ? undefined : parsed;\n\t}\n\n\treturn undefined;\n};\n\nconst toCaipNetworkId = (value: unknown): string | undefined => {\n\tconst chainId = normalizeEvmChainId(value);\n\treturn chainId === undefined ? undefined : `eip155:${chainId}`;\n};\n\nconst getInjectedWalletAccounts$ = (\n\twallet: EthereumInjectedWallet,\n): Observable<EthereumAccount[]> => {\n\tif (!wallet.isConnected) return of([]);\n\n\treturn getCachedObservable$(`accounts:${wallet.id}`, () =>\n\t\tnew Observable<EthereumAccount[]>((subscriber) => {\n\t\t\tconst addresses$ = new ReplaySubject<string[]>(1);\n\t\t\tconst chainId$ = new ReplaySubject<number | undefined>(1);\n\n\t\t\tconst getAccount = (\n\t\t\t\taddress: string,\n\t\t\t\tchainId: number | undefined,\n\t\t\t): EthereumAccount => {\n\t\t\t\tconst client = createWalletClient({\n\t\t\t\t\taccount: address as `0x${string}`,\n\t\t\t\t\ttransport: custom(wallet.provider as EIP1193Provider),\n\t\t\t\t});\n\n\t\t\t\treturn {\n\t\t\t\t\tid: getWalletAccountId(wallet.id, address),\n\t\t\t\t\tplatform: \"ethereum\",\n\t\t\t\t\tclient,\n\t\t\t\t\taddress: getAddress(address),\n\t\t\t\t\tchainId,\n\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t};\n\t\t\t};\n\n\t\t\tconst handleAccountsChanged = (addrs: string[]) => {\n\t\t\t\taddresses$.next(addrs);\n\t\t\t};\n\n\t\t\tconst handleChainChanged = (chainIdHex: unknown) => {\n\t\t\t\tchainId$.next(normalizeEvmChainId(chainIdHex));\n\t\t\t};\n\n\t\t\tconst handleDisconnect = () => {\n\t\t\t\tchainId$.next(undefined);\n\t\t\t};\n\n\t\t\t// Subscribe to provider events\n\t\t\twallet.provider.on(\"accountsChanged\", handleAccountsChanged);\n\t\t\twallet.provider.on(\"chainChanged\", handleChainChanged);\n\t\t\twallet.provider.on(\"disconnect\", handleDisconnect);\n\n\t\t\t// Fetch initial values\n\t\t\twallet.provider\n\t\t\t\t.request({ method: \"eth_accounts\" })\n\t\t\t\t.then((addrs: string[]) => addresses$.next(addrs))\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tconsole.error(\"Failed to get accounts\", err);\n\t\t\t\t\taddresses$.next([]);\n\t\t\t\t});\n\n\t\t\twallet.provider\n\t\t\t\t.request({ method: \"eth_chainId\" })\n\t\t\t\t.then(handleChainChanged)\n\t\t\t\t.catch(() => chainId$.next(undefined));\n\n\t\t\t// Combine addresses + chainId into account list\n\t\t\tconst sub = combineLatest([addresses$, chainId$])\n\t\t\t\t.pipe(\n\t\t\t\t\tmap(([addresses, chainId]) =>\n\t\t\t\t\t\taddresses.map((addr) => getAccount(addr, chainId)),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.subscribe(subscriber);\n\n\t\t\treturn () => {\n\t\t\t\twallet.provider.removeListener(\n\t\t\t\t\t\"accountsChanged\",\n\t\t\t\t\thandleAccountsChanged,\n\t\t\t\t);\n\t\t\t\twallet.provider.removeListener(\"chainChanged\", handleChainChanged);\n\t\t\t\twallet.provider.removeListener(\"disconnect\", handleDisconnect);\n\t\t\t\tsub.unsubscribe();\n\t\t\t};\n\t\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 })),\n\t);\n};\n\nconst wrapWalletConnectProvider = (\n\tprovider: EIP1193Provider,\n\tsessionTopic: string,\n\tcaipNetworkId: string,\n): EIP1193Provider => {\n\treturn new Proxy(provider, {\n\t\tget(target, prop, receiver) {\n\t\t\tif (prop !== \"request\") return Reflect.get(target, prop, receiver);\n\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: legacy\n\t\t\treturn (args: any) => {\n\t\t\t\tif (args && typeof args === \"object\" && args.method) {\n\t\t\t\t\tif (!args.topic) args.topic = sessionTopic;\n\t\t\t\t\tif (!args.chainId) args.chainId = caipNetworkId;\n\t\t\t\t}\n\t\t\t\treturn target.request(args);\n\t\t\t};\n\t\t},\n\t});\n};\n\nconst sameAddresses = (a: string[], b: string[]) =>\n\ta.length === b.length && a.every((addr, i) => addr === b[i]);\n\nconst getAppKitAccounts$ = (\n\twallet: EthereumAppKitWallet,\n): Observable<EthereumAccount[]> => {\n\tconst provider = wallet.appKit.getProvider(\"eip155\");\n\n\tif (\n\t\t!wallet.isConnected ||\n\t\t!wallet.appKit?.getAccount(\"eip155\")?.allAccounts.length ||\n\t\t!provider?.session\n\t)\n\t\treturn of([]);\n\n\treturn getCachedObservable$(`accounts:${wallet.id}:`, () =>\n\t\tnew Observable<EthereumAccount[]>((subscriber) => {\n\t\t\tconst caipNetworkId$ = new ReplaySubject<string>(1);\n\t\t\tconst addresses$ = new ReplaySubject<string[]>(1);\n\n\t\t\t// Read live from AppKit on each change rather than capturing a snapshot,\n\t\t\t// so switching/adding the active account is reflected (mirrors the\n\t\t\t// polkadot/solana AppKit paths).\n\t\t\tconst readAddresses = (): string[] =>\n\t\t\t\twallet.appKit\n\t\t\t\t\t.getAccount(\"eip155\")\n\t\t\t\t\t?.allAccounts.map((acc) => acc.address) ?? [];\n\n\t\t\tconst handleChainChanged = (chainId: unknown) => {\n\t\t\t\tconst caipNetworkId = toCaipNetworkId(chainId);\n\t\t\t\tif (caipNetworkId) {\n\t\t\t\t\tcaipNetworkId$.next(caipNetworkId);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst handleAccountsChanged = () => addresses$.next(readAddresses());\n\n\t\t\tprovider.on(\"chainChanged\", handleChainChanged);\n\t\t\tprovider.on(\"accountsChanged\", handleAccountsChanged);\n\t\t\tprovider.on(\"session_update\", handleAccountsChanged);\n\t\t\tprovider.request({ method: \"eth_chainId\" }).then(handleChainChanged);\n\t\t\taddresses$.next(readAddresses());\n\n\t\t\tconst sub = combineLatest([\n\t\t\t\tcaipNetworkId$.pipe(distinctUntilChanged()),\n\t\t\t\taddresses$.pipe(distinctUntilChanged(sameAddresses)),\n\t\t\t])\n\t\t\t\t.pipe(\n\t\t\t\t\tmap(([caipNetworkId, addresses]) => {\n\t\t\t\t\t\tconst chainId = normalizeEvmChainId(caipNetworkId);\n\t\t\t\t\t\tconst transport = custom(\n\t\t\t\t\t\t\twrapWalletConnectProvider(\n\t\t\t\t\t\t\t\tprovider as unknown as EIP1193Provider,\n\t\t\t\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: legacy\n\t\t\t\t\t\t\t\tprovider.session!.topic,\n\t\t\t\t\t\t\t\tcaipNetworkId,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn addresses.map((addr): EthereumAccount => {\n\t\t\t\t\t\t\tconst client = createWalletClient({\n\t\t\t\t\t\t\t\taccount: addr as `0x${string}`,\n\t\t\t\t\t\t\t\ttransport,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tid: getWalletAccountId(wallet.id, addr),\n\t\t\t\t\t\t\t\tplatform: \"ethereum\",\n\t\t\t\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t\t\t\t\taddress: addr as `0x${string}`,\n\t\t\t\t\t\t\t\tclient,\n\t\t\t\t\t\t\t\tchainId,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t});\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.subscribe(subscriber);\n\n\t\t\treturn () => {\n\t\t\t\tprovider.off(\"chainChanged\", handleChainChanged);\n\t\t\t\tprovider.off(\"accountsChanged\", handleAccountsChanged);\n\t\t\t\tprovider.off(\"session_update\", handleAccountsChanged);\n\t\t\t\tsub.unsubscribe();\n\t\t\t};\n\t\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 })),\n\t);\n};\n\nexport const getEthereumAccounts$ = (\n\tethereumWallets: Observable<EthereumWallet[]>,\n) =>\n\tnew Observable<EthereumAccount[]>((subscriber) => {\n\t\tconst sub = ethereumWallets\n\t\t\t.pipe(\n\t\t\t\tmap((wallets) => wallets.filter((w) => w.isConnected)),\n\t\t\t\tswitchMap((wallets) => {\n\t\t\t\t\treturn wallets.length\n\t\t\t\t\t\t? combineLatest([\n\t\t\t\t\t\t\t\t...wallets\n\t\t\t\t\t\t\t\t\t.filter((w) => w.type === \"injected\")\n\t\t\t\t\t\t\t\t\t.map(getInjectedWalletAccounts$),\n\t\t\t\t\t\t\t\t...wallets\n\t\t\t\t\t\t\t\t\t.filter((w) => w.type === \"appKit\")\n\t\t\t\t\t\t\t\t\t.map(getAppKitAccounts$),\n\t\t\t\t\t\t\t\t// todo appkit\n\t\t\t\t\t\t\t])\n\t\t\t\t\t\t: of([]);\n\t\t\t\t}),\n\t\t\t\tmap((accounts) => accounts.flat()),\n\t\t\t\tdistinctUntilChanged(isSameAccountsList),\n\t\t\t)\n\t\t\t.subscribe(subscriber);\n\n\t\treturn () => {\n\t\t\tsub.unsubscribe();\n\t\t};\n\t}).pipe(\n\t\t// logObservable(\"ethereumAccounts$\", true),\n\t\tshareReplay({ refCount: true, bufferSize: 1 }),\n\t);\n\nconst isSameAccountsList = (a: EthereumAccount[], b: EthereumAccount[]) => {\n\tif (a.length !== b.length) return false;\n\treturn a.every(\n\t\t(account, i) =>\n\t\t\taccount.id === b[i]?.id && account.chainId === b[i]?.chainId,\n\t);\n};\n","import {\n\tcreateStore as createMipdStore,\n\ttype EIP6963ProviderDetail,\n} from \"mipd\";\nimport {\n\tBehaviorSubject,\n\tcombineLatest,\n\tdistinctUntilChanged,\n\tmap,\n\tObservable,\n\tshareReplay,\n} from \"rxjs\";\nimport type { EIP1193Provider } from \"viem\";\nimport { clearCachedObservable } from \"../../utils/getCachedObservable\";\nimport { getWalletId, type WalletId } from \"../../utils/WalletId\";\nimport { getAppKitWallets$ } from \"../appKit\";\nimport { KheopskitError } from \"../errors\";\nimport { store as defaultStore, type KheopskitStore } from \"../store\";\nimport type { KheopskitConfig } from \"../types\";\nimport type { EthereumInjectedWallet, EthereumWallet } from \"./types\";\n\n/**\n * Observable that emits EIP-6963 provider details from injected wallets.\n * Returns empty array during SSR since browser wallet APIs are not available.\n */\nconst providersDetails$ = new Observable<EIP6963ProviderDetail[]>(\n\t(subscriber) => {\n\t\t// Guard against SSR - mipd requires browser APIs\n\t\tif (typeof window === \"undefined\") {\n\t\t\tsubscriber.next([]);\n\t\t\treturn () => {};\n\t\t}\n\n\t\tconst mipdStore = createMipdStore();\n\n\t\tconst unsubscribe = mipdStore.subscribe((providerDetails) => {\n\t\t\tsubscriber.next(providerDetails as EIP6963ProviderDetail[]);\n\t\t});\n\n\t\tconst providerDetails = mipdStore.getProviders();\n\n\t\tsubscriber.next(providerDetails as EIP6963ProviderDetail[]);\n\n\t\treturn () => {\n\t\t\tunsubscribe();\n\t\t\tmipdStore.destroy();\n\t\t};\n\t},\n).pipe(shareReplay({ refCount: true, bufferSize: 1 }));\n\nconst createEthereumInjectedWallets$ = (store: KheopskitStore) =>\n\tnew Observable<EthereumInjectedWallet[]>((subscriber) => {\n\t\tconst enabledWalletIds$ = new BehaviorSubject<Set<WalletId>>(new Set());\n\n\t\tconst connectWallet = async (\n\t\t\twalletId: WalletId,\n\t\t\tprovider: EIP1193Provider,\n\t\t) => {\n\t\t\tif (enabledWalletIds$.value.has(walletId))\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"WALLET_ALREADY_CONNECTED\",\n\t\t\t\t\t`wallet ${walletId} is already connected`,\n\t\t\t\t\t{ walletId },\n\t\t\t\t);\n\n\t\t\tawait provider.request({\n\t\t\t\tmethod: \"eth_requestAccounts\",\n\t\t\t});\n\n\t\t\tconst newSet = new Set(enabledWalletIds$.value);\n\t\t\tnewSet.add(walletId);\n\t\t\tenabledWalletIds$.next(newSet);\n\n\t\t\tstore.addEnabledWalletId(walletId);\n\t\t};\n\n\t\tconst disconnectWallet = async (walletId: WalletId) => {\n\t\t\tif (!enabledWalletIds$.value.has(walletId))\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"WALLET_NOT_CONNECTED\",\n\t\t\t\t\t`wallet ${walletId} is not connected`,\n\t\t\t\t\t{ walletId },\n\t\t\t\t);\n\t\t\tconst newSet = new Set(enabledWalletIds$.value);\n\t\t\tnewSet.delete(walletId);\n\t\t\tenabledWalletIds$.next(newSet);\n\n\t\t\tstore.removeEnabledWalletId(walletId);\n\n\t\t\t// Drop the cached account observable so a later reconnect rebuilds it\n\t\t\t// against the current provider, not a stale closure.\n\t\t\tclearCachedObservable(`accounts:${walletId}`);\n\t\t};\n\n\t\tconst sub = combineLatest([providersDetails$, enabledWalletIds$])\n\t\t\t.pipe(\n\t\t\t\tmap(([providerDetails, enabledWalletIds]) => {\n\t\t\t\t\treturn providerDetails.map((pd): EthereumInjectedWallet => {\n\t\t\t\t\t\tconst walletId = getWalletId(\"ethereum\", pd.info.rdns);\n\t\t\t\t\t\tconst provider = pd.provider as EIP1193Provider;\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tplatform: \"ethereum\",\n\t\t\t\t\t\t\ttype: \"injected\",\n\t\t\t\t\t\t\tid: walletId,\n\t\t\t\t\t\t\tname: pd.info.name,\n\t\t\t\t\t\t\ticon: pd.info.icon,\n\t\t\t\t\t\t\tprovider,\n\t\t\t\t\t\t\tisConnected: enabledWalletIds.has(walletId),\n\t\t\t\t\t\t\tsourceId: pd.info.rdns,\n\t\t\t\t\t\t\tconnect: () => connectWallet(walletId, provider),\n\t\t\t\t\t\t\tdisconnect: () => disconnectWallet(walletId),\n\t\t\t\t\t\t};\n\t\t\t\t\t});\n\t\t\t\t}),\n\t\t\t\tdistinctUntilChanged(walletsEqual),\n\t\t\t)\n\t\t\t.subscribe(subscriber);\n\n\t\treturn () => {\n\t\t\tsub.unsubscribe();\n\t\t};\n\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 }));\n\nexport const getEthereumWallets$ = (\n\tconfig: KheopskitConfig,\n\tstore: KheopskitStore = defaultStore,\n) => {\n\treturn new Observable<EthereumWallet[]>((subscriber) => {\n\t\tconst subscription = combineLatest([\n\t\t\tcreateEthereumInjectedWallets$(store),\n\t\t\tgetAppKitWallets$(config).pipe(map((w) => w.ethereum)),\n\t\t])\n\t\t\t.pipe(\n\t\t\t\tmap(([injectedWallets, appKitWallet]) =>\n\t\t\t\t\tappKitWallet ? [...injectedWallets, appKitWallet] : injectedWallets,\n\t\t\t\t),\n\t\t\t)\n\t\t\t.subscribe(subscriber);\n\n\t\treturn () => {\n\t\t\tsubscription.unsubscribe();\n\t\t};\n\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 }));\n};\n\n/**\n * Compare two wallet arrays by their relevant properties (not functions).\n */\nconst walletsEqual = (\n\ta: EthereumInjectedWallet[],\n\tb: EthereumInjectedWallet[],\n): boolean => {\n\tif (a.length !== b.length) return false;\n\treturn a.every(\n\t\t(w, i) =>\n\t\t\tw.id === b[i]?.id &&\n\t\t\tw.isConnected === b[i]?.isConnected &&\n\t\t\tw.name === b[i]?.name,\n\t);\n};\n","import type { KheopskitPlatform, PlatformContext } from \"../types\";\nimport { getEthereumAccounts$ } from \"./accounts\";\nimport type { EthereumAccount, EthereumWallet } from \"./types\";\nimport { getEthereumWallets$ } from \"./wallets\";\n\n/**\n * Ethereum platform plugin. Pass to `getKheopskit$({ platforms: [ethereum()] })`.\n *\n * @example\n * ```ts\n * import { ethereum } from \"@kheopskit/core/ethereum\";\n * ethereum();\n * ```\n */\nexport const ethereum = (): KheopskitPlatform<\n\t\"ethereum\",\n\tEthereumWallet,\n\tEthereumAccount\n> => ({\n\tplatform: \"ethereum\",\n\tgetWallets$: (ctx: PlatformContext) =>\n\t\tgetEthereumWallets$(ctx.config, ctx.store),\n\tgetAccounts$: (wallets$) => getEthereumAccounts$(wallets$),\n});\n"]}
1
+ {"version":3,"sources":["/home/runner/work/kheopskit/kheopskit/packages/core/dist/ethereum.js","../src/api/ethereum/accounts.ts","../src/api/ethereum/wallets.ts","../src/api/ethereum/plugin.ts"],"names":["combineLatest","distinctUntilChanged","map","Observable","shareReplay","providerDetails"],"mappings":"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","file":"/home/runner/work/kheopskit/kheopskit/packages/core/dist/ethereum.js","sourcesContent":[null,"import {\n\tcombineLatest,\n\tdistinctUntilChanged,\n\tmap,\n\tObservable,\n\tof,\n\tReplaySubject,\n\tshareReplay,\n\tswitchMap,\n} from \"rxjs\";\nimport {\n\tcreateWalletClient,\n\tcustom,\n\ttype EIP1193Provider,\n\tgetAddress,\n} from \"viem\";\nimport { getWalletAccountId } from \"../../utils\";\nimport { getCachedObservable$ } from \"../../utils/getCachedObservable\";\nimport type { WalletConnectWallet } from \"../types\";\nimport { isWalletConnectWallet } from \"../types\";\nimport type {\n\tEthereumAccount,\n\tEthereumInjectedWallet,\n\tEthereumWallet,\n} from \"./types\";\n\nconst normalizeEvmChainId = (value: unknown): number | undefined => {\n\tlet raw = value;\n\n\tif (typeof raw === \"string\" && raw.startsWith(\"eip155:\")) {\n\t\traw = raw.slice(\"eip155:\".length);\n\t}\n\n\tif (typeof raw === \"bigint\") {\n\t\treturn raw >= 0n ? Number(raw) : undefined;\n\t}\n\n\tif (typeof raw === \"number\") {\n\t\treturn Number.isInteger(raw) && raw >= 0 ? raw : undefined;\n\t}\n\n\tif (typeof raw === \"string\") {\n\t\tconst normalized = raw.trim().toLowerCase();\n\t\tif (!normalized) return undefined;\n\t\tconst parsed = normalized.startsWith(\"0x\")\n\t\t\t? Number.parseInt(normalized, 16)\n\t\t\t: Number.parseInt(normalized, 10);\n\t\treturn Number.isNaN(parsed) ? undefined : parsed;\n\t}\n\n\treturn undefined;\n};\n\nconst toCaipNetworkId = (value: unknown): string | undefined => {\n\tconst chainId = normalizeEvmChainId(value);\n\treturn chainId === undefined ? undefined : `eip155:${chainId}`;\n};\n\nconst getInjectedWalletAccounts$ = (\n\twallet: EthereumInjectedWallet,\n): Observable<EthereumAccount[]> => {\n\tif (!wallet.isConnected) return of([]);\n\n\treturn getCachedObservable$(`accounts:${wallet.id}`, () =>\n\t\tnew Observable<EthereumAccount[]>((subscriber) => {\n\t\t\tconst addresses$ = new ReplaySubject<string[]>(1);\n\t\t\tconst chainId$ = new ReplaySubject<number | undefined>(1);\n\n\t\t\tconst getAccount = (\n\t\t\t\taddress: string,\n\t\t\t\tchainId: number | undefined,\n\t\t\t): EthereumAccount => {\n\t\t\t\tconst client = createWalletClient({\n\t\t\t\t\taccount: address as `0x${string}`,\n\t\t\t\t\ttransport: custom(wallet.provider as EIP1193Provider),\n\t\t\t\t});\n\n\t\t\t\treturn {\n\t\t\t\t\tid: getWalletAccountId(wallet.id, address),\n\t\t\t\t\tplatform: \"ethereum\",\n\t\t\t\t\tclient,\n\t\t\t\t\taddress: getAddress(address),\n\t\t\t\t\tchainId,\n\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t};\n\t\t\t};\n\n\t\t\tconst handleAccountsChanged = (addrs: string[]) => {\n\t\t\t\taddresses$.next(addrs);\n\t\t\t};\n\n\t\t\tconst handleChainChanged = (chainIdHex: unknown) => {\n\t\t\t\tchainId$.next(normalizeEvmChainId(chainIdHex));\n\t\t\t};\n\n\t\t\tconst handleDisconnect = () => {\n\t\t\t\tchainId$.next(undefined);\n\t\t\t};\n\n\t\t\t// Subscribe to provider events\n\t\t\twallet.provider.on(\"accountsChanged\", handleAccountsChanged);\n\t\t\twallet.provider.on(\"chainChanged\", handleChainChanged);\n\t\t\twallet.provider.on(\"disconnect\", handleDisconnect);\n\n\t\t\t// Fetch initial values\n\t\t\twallet.provider\n\t\t\t\t.request({ method: \"eth_accounts\" })\n\t\t\t\t.then((addrs: string[]) => addresses$.next(addrs))\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tconsole.error(\"Failed to get accounts\", err);\n\t\t\t\t\taddresses$.next([]);\n\t\t\t\t});\n\n\t\t\twallet.provider\n\t\t\t\t.request({ method: \"eth_chainId\" })\n\t\t\t\t.then(handleChainChanged)\n\t\t\t\t.catch(() => chainId$.next(undefined));\n\n\t\t\t// Combine addresses + chainId into account list\n\t\t\tconst sub = combineLatest([addresses$, chainId$])\n\t\t\t\t.pipe(\n\t\t\t\t\tmap(([addresses, chainId]) =>\n\t\t\t\t\t\taddresses.map((addr) => getAccount(addr, chainId)),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.subscribe(subscriber);\n\n\t\t\treturn () => {\n\t\t\t\twallet.provider.removeListener(\n\t\t\t\t\t\"accountsChanged\",\n\t\t\t\t\thandleAccountsChanged,\n\t\t\t\t);\n\t\t\t\twallet.provider.removeListener(\"chainChanged\", handleChainChanged);\n\t\t\t\twallet.provider.removeListener(\"disconnect\", handleDisconnect);\n\t\t\t\tsub.unsubscribe();\n\t\t\t};\n\t\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 })),\n\t);\n};\n\nconst wrapWalletConnectProvider = (\n\tprovider: EIP1193Provider,\n\tsessionTopic: string,\n\tcaipNetworkId: string | undefined,\n): EIP1193Provider => {\n\treturn new Proxy(provider, {\n\t\tget(target, prop, receiver) {\n\t\t\tif (prop !== \"request\") return Reflect.get(target, prop, receiver);\n\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: EIP-1193 request args\n\t\t\treturn (args: any) => {\n\t\t\t\tif (!args || typeof args !== \"object\" || !args.method)\n\t\t\t\t\treturn target.request(args);\n\t\t\t\t// Build a new object rather than mutating the caller's args: the\n\t\t\t\t// EIP-1193 request object is owned by viem and may be frozen or reused.\n\t\t\t\tconst next = { ...args };\n\t\t\t\tif (next.topic === undefined) next.topic = sessionTopic;\n\t\t\t\tif (next.chainId === undefined && caipNetworkId !== undefined)\n\t\t\t\t\tnext.chainId = caipNetworkId;\n\t\t\t\treturn target.request(next);\n\t\t\t};\n\t\t},\n\t});\n};\n\nconst sameAddresses = (a: string[], b: string[]) =>\n\ta.length === b.length && a.every((addr, i) => addr === b[i]);\n\nconst getWalletConnectAccounts$ = (\n\twallet: WalletConnectWallet,\n): Observable<EthereumAccount[]> => {\n\tconst provider = wallet.appKit.getProvider(\"eip155\");\n\n\tif (!wallet.platforms.includes(\"ethereum\") || !provider?.session)\n\t\treturn of([]);\n\n\treturn getCachedObservable$(`accounts:${wallet.id}:ethereum:`, () =>\n\t\tnew Observable<EthereumAccount[]>((subscriber) => {\n\t\t\tconst caipNetworkId$ = new ReplaySubject<string | undefined>(1);\n\t\t\tconst addresses$ = new ReplaySubject<string[]>(1);\n\n\t\t\t// AppKit's getAccount(\"eip155\").allAccounts is empty because this AppKit\n\t\t\t// instance has no native eip155 adapter — eip155 runs through the\n\t\t\t// WalletConnect UniversalProvider, so the session is the source of truth\n\t\t\t// (mirrors the polkadot/solana AppKit paths). Accounts are CAIP-10 strings\n\t\t\t// (\"eip155:<chainRef>:<address>\"), one entry per chain, so dedupe to unique\n\t\t\t// addresses. Read live on each change so switching/adding accounts is\n\t\t\t// reflected.\n\t\t\tconst readAddresses = (): string[] => {\n\t\t\t\tconst session = provider.session;\n\t\t\t\tif (!session) return [];\n\t\t\t\tconst addresses = new Set<string>();\n\t\t\t\tfor (const namespace of Object.values(session.namespaces)) {\n\t\t\t\t\tfor (const account of namespace.accounts ?? []) {\n\t\t\t\t\t\tif (!account.startsWith(\"eip155:\")) continue;\n\t\t\t\t\t\tconst raw = account.split(\":\")[2];\n\t\t\t\t\t\tif (!raw) continue;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\taddresses.add(getAddress(raw));\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// skip malformed CAIP-10 address\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn [...addresses];\n\t\t\t};\n\n\t\t\t// Derive the CAIP network id from the session's eip155 CAIP-10 accounts\n\t\t\t// (\"eip155:<ref>:<addr>\") as a synchronous fallback for eth_chainId.\n\t\t\tconst readCaipNetworkId = (): string | undefined => {\n\t\t\t\tconst session = provider.session;\n\t\t\t\tif (!session) return undefined;\n\t\t\t\tfor (const namespace of Object.values(session.namespaces)) {\n\t\t\t\t\tfor (const account of namespace.accounts ?? []) {\n\t\t\t\t\t\tif (!account.startsWith(\"eip155:\")) continue;\n\t\t\t\t\t\tconst ref = account.split(\":\")[1];\n\t\t\t\t\t\tif (ref) return `eip155:${ref}`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t};\n\n\t\t\tconst handleChainChanged = (chainId: unknown) => {\n\t\t\t\tconst caipNetworkId = toCaipNetworkId(chainId);\n\t\t\t\tif (caipNetworkId) {\n\t\t\t\t\tcaipNetworkId$.next(caipNetworkId);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst handleAccountsChanged = () => addresses$.next(readAddresses());\n\n\t\t\tprovider.on(\"chainChanged\", handleChainChanged);\n\t\t\tprovider.on(\"accountsChanged\", handleAccountsChanged);\n\t\t\tprovider.on(\"session_update\", handleAccountsChanged);\n\t\t\t// Seed the chain id from the session synchronously so the account list can\n\t\t\t// surface even if eth_chainId never resolves; eth_chainId then refines it.\n\t\t\t// Without this seed, combineLatest below never fires when eth_chainId\n\t\t\t// rejects or returns an unparseable value, and the accounts silently never\n\t\t\t// appear (the injected path seeds undefined on failure for the same reason).\n\t\t\tcaipNetworkId$.next(readCaipNetworkId());\n\t\t\tprovider\n\t\t\t\t.request({ method: \"eth_chainId\" })\n\t\t\t\t.then(handleChainChanged)\n\t\t\t\t.catch(() => {});\n\t\t\taddresses$.next(readAddresses());\n\n\t\t\tconst sub = combineLatest([\n\t\t\t\tcaipNetworkId$.pipe(distinctUntilChanged()),\n\t\t\t\taddresses$.pipe(distinctUntilChanged(sameAddresses)),\n\t\t\t])\n\t\t\t\t.pipe(\n\t\t\t\t\tmap(([caipNetworkId, addresses]) => {\n\t\t\t\t\t\tconst chainId = normalizeEvmChainId(caipNetworkId);\n\t\t\t\t\t\tconst transport = custom(\n\t\t\t\t\t\t\twrapWalletConnectProvider(\n\t\t\t\t\t\t\t\tprovider as unknown as EIP1193Provider,\n\t\t\t\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: legacy\n\t\t\t\t\t\t\t\tprovider.session!.topic,\n\t\t\t\t\t\t\t\tcaipNetworkId,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn addresses.map((addr): EthereumAccount => {\n\t\t\t\t\t\t\tconst client = createWalletClient({\n\t\t\t\t\t\t\t\taccount: addr as `0x${string}`,\n\t\t\t\t\t\t\t\ttransport,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tid: getWalletAccountId(wallet.id, addr),\n\t\t\t\t\t\t\t\tplatform: \"ethereum\",\n\t\t\t\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t\t\t\t\taddress: addr as `0x${string}`,\n\t\t\t\t\t\t\t\tclient,\n\t\t\t\t\t\t\t\tchainId,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t});\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.subscribe(subscriber);\n\n\t\t\treturn () => {\n\t\t\t\tprovider.off(\"chainChanged\", handleChainChanged);\n\t\t\t\tprovider.off(\"accountsChanged\", handleAccountsChanged);\n\t\t\t\tprovider.off(\"session_update\", handleAccountsChanged);\n\t\t\t\tsub.unsubscribe();\n\t\t\t};\n\t\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 })),\n\t);\n};\n\nexport const getEthereumAccounts$ = (\n\tethereumWallets: Observable<(EthereumWallet | WalletConnectWallet)[]>,\n) =>\n\tnew Observable<EthereumAccount[]>((subscriber) => {\n\t\tconst sub = ethereumWallets\n\t\t\t.pipe(\n\t\t\t\tmap((wallets) => wallets.filter((w) => w.isConnected)),\n\t\t\t\tswitchMap((wallets) => {\n\t\t\t\t\treturn wallets.length\n\t\t\t\t\t\t? combineLatest([\n\t\t\t\t\t\t\t\t...wallets\n\t\t\t\t\t\t\t\t\t.filter((w) => w.type === \"injected\")\n\t\t\t\t\t\t\t\t\t.map(getInjectedWalletAccounts$),\n\t\t\t\t\t\t\t\t...wallets\n\t\t\t\t\t\t\t\t\t.filter(isWalletConnectWallet)\n\t\t\t\t\t\t\t\t\t.map(getWalletConnectAccounts$),\n\t\t\t\t\t\t\t])\n\t\t\t\t\t\t: of([]);\n\t\t\t\t}),\n\t\t\t\tmap((accounts) => accounts.flat()),\n\t\t\t\tdistinctUntilChanged(isSameAccountsList),\n\t\t\t)\n\t\t\t.subscribe(subscriber);\n\n\t\treturn () => {\n\t\t\tsub.unsubscribe();\n\t\t};\n\t}).pipe(\n\t\t// logObservable(\"ethereumAccounts$\", true),\n\t\tshareReplay({ refCount: true, bufferSize: 1 }),\n\t);\n\nconst isSameAccountsList = (a: EthereumAccount[], b: EthereumAccount[]) => {\n\tif (a.length !== b.length) return false;\n\treturn a.every(\n\t\t(account, i) =>\n\t\t\taccount.id === b[i]?.id && account.chainId === b[i]?.chainId,\n\t);\n};\n","import {\n\tcreateStore as createMipdStore,\n\ttype EIP6963ProviderDetail,\n} from \"mipd\";\nimport {\n\tBehaviorSubject,\n\tcombineLatest,\n\tdistinctUntilChanged,\n\tmap,\n\tObservable,\n\tshareReplay,\n} from \"rxjs\";\nimport type { EIP1193Provider } from \"viem\";\nimport { clearCachedObservable } from \"../../utils/getCachedObservable\";\nimport { getWalletId, type WalletId } from \"../../utils/WalletId\";\nimport { KheopskitError } from \"../errors\";\nimport { store as defaultStore, type KheopskitStore } from \"../store\";\nimport type { EthereumInjectedWallet } from \"./types\";\n\n/**\n * Observable that emits EIP-6963 provider details from injected wallets.\n * Returns empty array during SSR since browser wallet APIs are not available.\n */\nconst providersDetails$ = new Observable<EIP6963ProviderDetail[]>(\n\t(subscriber) => {\n\t\t// Guard against SSR - mipd requires browser APIs\n\t\tif (typeof window === \"undefined\") {\n\t\t\tsubscriber.next([]);\n\t\t\treturn () => {};\n\t\t}\n\n\t\tconst mipdStore = createMipdStore();\n\n\t\tconst unsubscribe = mipdStore.subscribe((providerDetails) => {\n\t\t\tsubscriber.next(providerDetails as EIP6963ProviderDetail[]);\n\t\t});\n\n\t\tconst providerDetails = mipdStore.getProviders();\n\n\t\tsubscriber.next(providerDetails as EIP6963ProviderDetail[]);\n\n\t\treturn () => {\n\t\t\tunsubscribe();\n\t\t\tmipdStore.destroy();\n\t\t};\n\t},\n).pipe(shareReplay({ refCount: true, bufferSize: 1 }));\n\nconst createEthereumInjectedWallets$ = (store: KheopskitStore) =>\n\tnew Observable<EthereumInjectedWallet[]>((subscriber) => {\n\t\tconst enabledWalletIds$ = new BehaviorSubject<Set<WalletId>>(new Set());\n\n\t\tconst connectWallet = async (\n\t\t\twalletId: WalletId,\n\t\t\tprovider: EIP1193Provider,\n\t\t) => {\n\t\t\tif (enabledWalletIds$.value.has(walletId))\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"WALLET_ALREADY_CONNECTED\",\n\t\t\t\t\t`wallet ${walletId} is already connected`,\n\t\t\t\t\t{ walletId },\n\t\t\t\t);\n\n\t\t\tawait provider.request({\n\t\t\t\tmethod: \"eth_requestAccounts\",\n\t\t\t});\n\n\t\t\tconst newSet = new Set(enabledWalletIds$.value);\n\t\t\tnewSet.add(walletId);\n\t\t\tenabledWalletIds$.next(newSet);\n\n\t\t\tstore.addEnabledWalletId(walletId);\n\t\t};\n\n\t\tconst disconnectWallet = async (walletId: WalletId) => {\n\t\t\tif (!enabledWalletIds$.value.has(walletId))\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"WALLET_NOT_CONNECTED\",\n\t\t\t\t\t`wallet ${walletId} is not connected`,\n\t\t\t\t\t{ walletId },\n\t\t\t\t);\n\t\t\tconst newSet = new Set(enabledWalletIds$.value);\n\t\t\tnewSet.delete(walletId);\n\t\t\tenabledWalletIds$.next(newSet);\n\n\t\t\tstore.removeEnabledWalletId(walletId);\n\n\t\t\t// Drop the cached account observable so a later reconnect rebuilds it\n\t\t\t// against the current provider, not a stale closure.\n\t\t\tclearCachedObservable(`accounts:${walletId}`);\n\t\t};\n\n\t\tconst sub = combineLatest([providersDetails$, enabledWalletIds$])\n\t\t\t.pipe(\n\t\t\t\tmap(([providerDetails, enabledWalletIds]) => {\n\t\t\t\t\treturn providerDetails.map((pd): EthereumInjectedWallet => {\n\t\t\t\t\t\tconst walletId = getWalletId(\"ethereum\", pd.info.rdns);\n\t\t\t\t\t\tconst provider = pd.provider as EIP1193Provider;\n\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tplatform: \"ethereum\",\n\t\t\t\t\t\t\ttype: \"injected\",\n\t\t\t\t\t\t\tid: walletId,\n\t\t\t\t\t\t\tname: pd.info.name,\n\t\t\t\t\t\t\ticon: pd.info.icon,\n\t\t\t\t\t\t\tprovider,\n\t\t\t\t\t\t\tisConnected: enabledWalletIds.has(walletId),\n\t\t\t\t\t\t\tsourceId: pd.info.rdns,\n\t\t\t\t\t\t\tconnect: () => connectWallet(walletId, provider),\n\t\t\t\t\t\t\tdisconnect: () => disconnectWallet(walletId),\n\t\t\t\t\t\t};\n\t\t\t\t\t});\n\t\t\t\t}),\n\t\t\t\tdistinctUntilChanged(walletsEqual),\n\t\t\t)\n\t\t\t.subscribe(subscriber);\n\n\t\treturn () => {\n\t\t\tsub.unsubscribe();\n\t\t};\n\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 }));\n\n// The shared WalletConnect connector is emitted once by core (see\n// `getWallets$`), not per platform — so this returns only injected wallets.\nexport const getEthereumWallets$ = (store: KheopskitStore = defaultStore) =>\n\tcreateEthereumInjectedWallets$(store);\n\n/**\n * Compare two wallet arrays by their relevant properties (not functions).\n */\nconst walletsEqual = (\n\ta: EthereumInjectedWallet[],\n\tb: EthereumInjectedWallet[],\n): boolean => {\n\tif (a.length !== b.length) return false;\n\treturn a.every(\n\t\t(w, i) =>\n\t\t\tw.id === b[i]?.id &&\n\t\t\tw.isConnected === b[i]?.isConnected &&\n\t\t\tw.name === b[i]?.name,\n\t);\n};\n","import type { KheopskitPlatform, PlatformContext } from \"../types\";\nimport { getEthereumAccounts$ } from \"./accounts\";\nimport type { EthereumAccount, EthereumWallet } from \"./types\";\nimport { getEthereumWallets$ } from \"./wallets\";\n\n/**\n * Ethereum platform plugin. Pass to `getKheopskit$({ platforms: [ethereum()] })`.\n *\n * @example\n * ```ts\n * import { ethereum } from \"@kheopskit/core/ethereum\";\n * ethereum();\n * ```\n */\nexport const ethereum = (): KheopskitPlatform<\n\t\"ethereum\",\n\tEthereumWallet,\n\tEthereumAccount\n> => ({\n\tplatform: \"ethereum\",\n\tgetWallets$: (ctx: PlatformContext) => getEthereumWallets$(ctx.store),\n\tgetAccounts$: (wallets$) => getEthereumAccounts$(wallets$),\n});\n"]}
package/dist/ethereum.mjs CHANGED
@@ -1,16 +1,16 @@
1
- import "./chunk-YFD3IKK5.mjs";
2
1
  import {
3
2
  KheopskitError,
4
- getAppKitWallets$,
5
3
  getWalletAccountId,
6
4
  isEthereumAddress,
7
5
  store
8
- } from "./chunk-KWFQDD7E.mjs";
6
+ } from "./chunk-6XAZANB5.mjs";
9
7
  import {
10
8
  clearCachedObservable,
11
9
  getCachedObservable$,
12
- getWalletId
13
- } from "./chunk-PNPPI5CH.mjs";
10
+ getWalletId,
11
+ isInjectedWallet,
12
+ isWalletConnectWallet
13
+ } from "./chunk-7QSGAJ4A.mjs";
14
14
 
15
15
  // src/api/ethereum/accounts.ts
16
16
  import {
@@ -112,26 +112,56 @@ var wrapWalletConnectProvider = (provider, sessionTopic, caipNetworkId) => {
112
112
  get(target, prop, receiver) {
113
113
  if (prop !== "request") return Reflect.get(target, prop, receiver);
114
114
  return (args) => {
115
- if (args && typeof args === "object" && args.method) {
116
- if (!args.topic) args.topic = sessionTopic;
117
- if (!args.chainId) args.chainId = caipNetworkId;
118
- }
119
- return target.request(args);
115
+ if (!args || typeof args !== "object" || !args.method)
116
+ return target.request(args);
117
+ const next = { ...args };
118
+ if (next.topic === void 0) next.topic = sessionTopic;
119
+ if (next.chainId === void 0 && caipNetworkId !== void 0)
120
+ next.chainId = caipNetworkId;
121
+ return target.request(next);
120
122
  };
121
123
  }
122
124
  });
123
125
  };
124
126
  var sameAddresses = (a, b) => a.length === b.length && a.every((addr, i) => addr === b[i]);
125
- var getAppKitAccounts$ = (wallet) => {
127
+ var getWalletConnectAccounts$ = (wallet) => {
126
128
  const provider = wallet.appKit.getProvider("eip155");
127
- if (!wallet.isConnected || !wallet.appKit?.getAccount("eip155")?.allAccounts.length || !provider?.session)
129
+ if (!wallet.platforms.includes("ethereum") || !provider?.session)
128
130
  return of([]);
129
131
  return getCachedObservable$(
130
- `accounts:${wallet.id}:`,
132
+ `accounts:${wallet.id}:ethereum:`,
131
133
  () => new Observable((subscriber) => {
132
134
  const caipNetworkId$ = new ReplaySubject(1);
133
135
  const addresses$ = new ReplaySubject(1);
134
- const readAddresses = () => wallet.appKit.getAccount("eip155")?.allAccounts.map((acc) => acc.address) ?? [];
136
+ const readAddresses = () => {
137
+ const session = provider.session;
138
+ if (!session) return [];
139
+ const addresses = /* @__PURE__ */ new Set();
140
+ for (const namespace of Object.values(session.namespaces)) {
141
+ for (const account of namespace.accounts ?? []) {
142
+ if (!account.startsWith("eip155:")) continue;
143
+ const raw = account.split(":")[2];
144
+ if (!raw) continue;
145
+ try {
146
+ addresses.add(getAddress(raw));
147
+ } catch {
148
+ }
149
+ }
150
+ }
151
+ return [...addresses];
152
+ };
153
+ const readCaipNetworkId = () => {
154
+ const session = provider.session;
155
+ if (!session) return void 0;
156
+ for (const namespace of Object.values(session.namespaces)) {
157
+ for (const account of namespace.accounts ?? []) {
158
+ if (!account.startsWith("eip155:")) continue;
159
+ const ref = account.split(":")[1];
160
+ if (ref) return `eip155:${ref}`;
161
+ }
162
+ }
163
+ return void 0;
164
+ };
135
165
  const handleChainChanged = (chainId) => {
136
166
  const caipNetworkId = toCaipNetworkId(chainId);
137
167
  if (caipNetworkId) {
@@ -142,7 +172,9 @@ var getAppKitAccounts$ = (wallet) => {
142
172
  provider.on("chainChanged", handleChainChanged);
143
173
  provider.on("accountsChanged", handleAccountsChanged);
144
174
  provider.on("session_update", handleAccountsChanged);
145
- provider.request({ method: "eth_chainId" }).then(handleChainChanged);
175
+ caipNetworkId$.next(readCaipNetworkId());
176
+ provider.request({ method: "eth_chainId" }).then(handleChainChanged).catch(() => {
177
+ });
146
178
  addresses$.next(readAddresses());
147
179
  const sub = combineLatest([
148
180
  caipNetworkId$.pipe(distinctUntilChanged()),
@@ -190,8 +222,7 @@ var getEthereumAccounts$ = (ethereumWallets) => new Observable((subscriber) => {
190
222
  switchMap((wallets) => {
191
223
  return wallets.length ? combineLatest([
192
224
  ...wallets.filter((w) => w.type === "injected").map(getInjectedWalletAccounts$),
193
- ...wallets.filter((w) => w.type === "appKit").map(getAppKitAccounts$)
194
- // todo appkit
225
+ ...wallets.filter(isWalletConnectWallet).map(getWalletConnectAccounts$)
195
226
  ]) : of([]);
196
227
  }),
197
228
  map((accounts) => accounts.flat()),
@@ -297,21 +328,7 @@ var createEthereumInjectedWallets$ = (store2) => new Observable2((subscriber) =>
297
328
  sub.unsubscribe();
298
329
  };
299
330
  }).pipe(shareReplay2({ refCount: true, bufferSize: 1 }));
300
- var getEthereumWallets$ = (config, store2 = store) => {
301
- return new Observable2((subscriber) => {
302
- const subscription = combineLatest2([
303
- createEthereumInjectedWallets$(store2),
304
- getAppKitWallets$(config).pipe(map2((w) => w.ethereum))
305
- ]).pipe(
306
- map2(
307
- ([injectedWallets, appKitWallet]) => appKitWallet ? [...injectedWallets, appKitWallet] : injectedWallets
308
- )
309
- ).subscribe(subscriber);
310
- return () => {
311
- subscription.unsubscribe();
312
- };
313
- }).pipe(shareReplay2({ refCount: true, bufferSize: 1 }));
314
- };
331
+ var getEthereumWallets$ = (store2 = store) => createEthereumInjectedWallets$(store2);
315
332
  var walletsEqual = (a, b) => {
316
333
  if (a.length !== b.length) return false;
317
334
  return a.every(
@@ -322,11 +339,13 @@ var walletsEqual = (a, b) => {
322
339
  // src/api/ethereum/plugin.ts
323
340
  var ethereum = () => ({
324
341
  platform: "ethereum",
325
- getWallets$: (ctx) => getEthereumWallets$(ctx.config, ctx.store),
342
+ getWallets$: (ctx) => getEthereumWallets$(ctx.store),
326
343
  getAccounts$: (wallets$) => getEthereumAccounts$(wallets$)
327
344
  });
328
345
  export {
329
346
  ethereum,
330
- isEthereumAddress
347
+ isEthereumAddress,
348
+ isInjectedWallet,
349
+ isWalletConnectWallet
331
350
  };
332
351
  //# sourceMappingURL=ethereum.mjs.map