@kheopskit/core 5.0.1 → 5.1.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.
- package/dist/{chunk-7QSGAJ4A.mjs → chunk-3Y5N4N3Q.mjs} +119 -62
- package/dist/chunk-3Y5N4N3Q.mjs.map +1 -0
- package/dist/chunk-DF7EKK4G.mjs +106 -0
- package/dist/chunk-DF7EKK4G.mjs.map +1 -0
- package/dist/chunk-EH73P476.js +106 -0
- package/dist/chunk-EH73P476.js.map +1 -0
- package/dist/chunk-JVSCMJY5.mjs +147 -0
- package/dist/chunk-JVSCMJY5.mjs.map +1 -0
- package/dist/chunk-P7BPHHVV.js +76 -0
- package/dist/chunk-P7BPHHVV.js.map +1 -0
- package/dist/{chunk-4ENHC7G4.js → chunk-SO64R7Z6.js} +114 -57
- package/dist/chunk-SO64R7Z6.js.map +1 -0
- package/dist/chunk-WOPCW2OX.mjs +76 -0
- package/dist/chunk-WOPCW2OX.mjs.map +1 -0
- package/dist/chunk-XOGQMEV2.js +147 -0
- package/dist/chunk-XOGQMEV2.js.map +1 -0
- package/dist/ethereum.d.mts +2 -2
- package/dist/ethereum.d.ts +2 -2
- package/dist/ethereum.js +55 -115
- package/dist/ethereum.js.map +1 -1
- package/dist/ethereum.mjs +55 -115
- package/dist/ethereum.mjs.map +1 -1
- package/dist/index.d.mts +59 -3
- package/dist/index.d.ts +59 -3
- package/dist/index.js +442 -61
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +429 -48
- package/dist/index.mjs.map +1 -1
- package/dist/internal.d.mts +2 -39
- package/dist/internal.d.ts +2 -39
- package/dist/internal.js +3 -15
- package/dist/internal.js.map +1 -1
- package/dist/internal.mjs +6 -18
- package/dist/polkadot.d.mts +2 -2
- package/dist/polkadot.d.ts +2 -2
- package/dist/polkadot.js +75 -148
- package/dist/polkadot.js.map +1 -1
- package/dist/polkadot.mjs +76 -149
- package/dist/polkadot.mjs.map +1 -1
- package/dist/solana.d.mts +2 -2
- package/dist/solana.d.ts +2 -2
- package/dist/solana.js +90 -158
- package/dist/solana.js.map +1 -1
- package/dist/solana.mjs +86 -154
- package/dist/solana.mjs.map +1 -1
- package/dist/{types-C7V7DGlg.d.ts → types-0iDBydsK.d.mts} +24 -46
- package/dist/{types-C7V7DGlg.d.mts → types-0iDBydsK.d.ts} +24 -46
- package/package.json +1 -1
- package/dist/chunk-4ENHC7G4.js.map +0 -1
- package/dist/chunk-6XAZANB5.mjs +0 -450
- package/dist/chunk-6XAZANB5.mjs.map +0 -1
- package/dist/chunk-7QSGAJ4A.mjs.map +0 -1
- package/dist/chunk-B4L6GAYD.js +0 -179
- package/dist/chunk-B4L6GAYD.js.map +0 -1
- package/dist/chunk-XQWJM3KC.js +0 -450
- package/dist/chunk-XQWJM3KC.js.map +0 -1
- package/dist/chunk-YDLCHYHH.mjs +0 -179
- package/dist/chunk-YDLCHYHH.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/isWalletPlatform.ts","../src/utils/WalletId.ts","../src/utils/getCachedObservable.ts","../src/api/types.ts"],"sourcesContent":["import type { WalletPlatform } from \"../api/types\";\n\nexport const isWalletPlatform = (\n\tplatform: unknown,\n): platform is WalletPlatform =>\n\ttypeof platform === \"string\" &&\n\t[\"polkadot\", \"ethereum\", \"solana\"].includes(platform as WalletPlatform);\n","import type { WalletPlatform } from \"../api/types\";\nimport { isWalletPlatform } from \"./isWalletPlatform\";\n\nexport type WalletId = string;\n\n/**\n * Stable id of the single WalletConnect connector. It is platform-less: one WC\n * session spans whichever namespaces the wallet approves, so it isn't tied to a\n * platform (unlike injected wallet ids, which are `<platform>:<identifier>`).\n */\nexport const WALLET_CONNECT_WALLET_ID: WalletId = \"walletconnect\";\n\nexport const getWalletId = (\n\tplatform: WalletPlatform,\n\tidentifier: string,\n): WalletId => {\n\tif (!isWalletPlatform(platform)) throw new Error(\"Invalid platform\");\n\tif (!identifier) throw new Error(\"Invalid name\");\n\treturn `${platform}:${identifier}`;\n};\n\nexport const parseWalletId = (walletId: string) => {\n\tif (!walletId) throw new Error(\"Invalid walletId\");\n\tconst [platform, identifier] = walletId.split(\":\");\n\tif (!isWalletPlatform(platform)) throw new Error(\"Invalid platform\");\n\tif (!identifier) throw new Error(\"Invalid address\");\n\treturn { platform, identifier };\n};\n\n/**\n * Non-throwing variant of {@link parseWalletId}. Use when validating untrusted\n * input (e.g. cached state persisted by an older version) before parsing.\n */\nexport const isValidWalletId = (walletId: unknown): walletId is WalletId => {\n\tif (typeof walletId !== \"string\" || !walletId) return false;\n\tif (walletId === WALLET_CONNECT_WALLET_ID) return true;\n\tconst [platform, identifier] = walletId.split(\":\");\n\treturn isWalletPlatform(platform) && !!identifier;\n};\n","import type { Observable } from \"rxjs\";\n\n// Anchored on globalThis so the cache stays a single instance even if the\n// module is duplicated across bundle chunks (e.g. CJS subpath entries).\nconst CACHE_SYMBOL = Symbol.for(\"kheopskit.observableCache\");\n\nconst getCache = (): Map<string, Observable<unknown>> => {\n\tconst g = globalThis as unknown as Record<\n\t\tsymbol,\n\t\tMap<string, Observable<unknown>> | undefined\n\t>;\n\tlet cache = g[CACHE_SYMBOL];\n\tif (!cache) {\n\t\tcache = new Map();\n\t\tg[CACHE_SYMBOL] = cache;\n\t}\n\treturn cache;\n};\n\nexport const getCachedObservable$ = <T, Obs = Observable<T>>(\n\tkey: string,\n\tcreate: () => Obs,\n): Obs => {\n\tconst cache = getCache();\n\tif (!cache.has(key)) cache.set(key, create() as Observable<unknown>);\n\n\treturn cache.get(key) as Obs;\n};\n\n/**\n * Clears an observable from the cache.\n * Use when a wallet disconnects or configuration changes.\n */\nexport const clearCachedObservable = (key: string): void => {\n\tgetCache().delete(key);\n};\n\n/**\n * Clears all cached observables whose key starts with `prefix`.\n *\n * Used to drop a wallet's account observables when it disconnects, so a later\n * reconnect rebuilds them against the current wallet handle instead of a stale\n * closure — and to keep the cache from growing unbounded across connect cycles.\n */\nexport const clearCachedObservablesByPrefix = (prefix: string): void => {\n\tconst cache = getCache();\n\tfor (const key of cache.keys()) {\n\t\tif (key.startsWith(prefix)) cache.delete(key);\n\t}\n};\n\n/**\n * Clears all cached observables.\n * Use when resetting the entire kheopskit state.\n */\nexport const clearAllCachedObservables = (): void => {\n\tgetCache().clear();\n};\n","import type { Observable } from \"rxjs\";\nimport type { WalletAccountId } from \"../utils\";\nimport type { WalletId } from \"../utils/WalletId\";\n\nexport type WalletPlatform = \"polkadot\" | \"ethereum\" | \"solana\";\n\n/**\n * Minimal structural view of a WalletConnect `UniversalProvider` — the subset\n * kheopskit reads. Declared locally so core never depends on\n * `@walletconnect/universal-provider`. The concrete instance comes from\n * `@reown/appkit` at runtime.\n */\nexport type WalletConnectProvider = {\n\tsession?: {\n\t\ttopic: string;\n\t\tnamespaces: Record<string, { accounts?: string[] }>;\n\t};\n\tclient: {\n\t\trequest<T = unknown>(args: {\n\t\t\ttopic: string;\n\t\t\tchainId: string;\n\t\t\trequest: { method: string; params: unknown };\n\t\t}): Promise<T>;\n\t};\n\trequest(args: { method: string; params?: unknown }): Promise<unknown>;\n\ton(event: string, listener: (...args: unknown[]) => void): void;\n\toff(event: string, listener: (...args: unknown[]) => void): void;\n};\n\n/**\n * Minimal structural view of the Reown AppKit instance — the subset kheopskit's\n * account factories use. Exposed as the `appKit` escape hatch on AppKit wallets;\n * cast it to `@reown/appkit`'s `AppKit` type for the full API. Declared locally\n * so core never depends on `@reown/appkit`'s types (it's an optional peer).\n */\nexport type AppKitInstance = {\n\tgetProvider<T = WalletConnectProvider>(namespace: string): T | undefined;\n\tgetAccount(\n\t\tnamespace: string,\n\t): { allAccounts: { address: string }[] } | undefined;\n\tgetCaipNetworks(namespace: string): { caipNetworkId?: string }[];\n};\n\nexport type WalletType = \"injected\" | \"walletconnect\";\n\nexport type PolkadotAccountType = \"sr25519\" | \"ed25519\" | \"ecdsa\" | \"ethereum\";\n\n/**\n * SDK-free fields common to every wallet, regardless of platform. Platform\n * packages (`@kheopskit/core/<platform>`) extend this with SDK-typed fields\n * (the injected provider/extension/standard-wallet handle).\n */\nexport type BaseWallet = {\n\tid: WalletId;\n\tplatform: WalletPlatform;\n\ttype: WalletType;\n\tname: string;\n\ticon: string;\n\tisConnected: boolean;\n\tconnect: () => Promise<void>;\n\t/**\n\t * Disconnect the wallet. Resolves once the underlying provider/extension\n\t * disconnect completes; rejects if it fails so callers can surface or retry.\n\t */\n\tdisconnect: () => Promise<void>;\n};\n\n/**\n * SDK-free fields common to every account, regardless of platform. Platform\n * packages extend this with their SDK-typed signer/client.\n */\nexport type BaseWalletAccount = {\n\tid: WalletAccountId;\n\tplatform: WalletPlatform;\n\t/** Base58 (Solana), SS58 (Polkadot) or 0x-hex (Ethereum) address. */\n\taddress: string;\n\t/** Friendly account name, when the wallet exposes one (e.g. Polkadot). */\n\tname?: string;\n\twalletName: string;\n\twalletId: WalletId;\n};\n\n/**\n * The single WalletConnect connector, shared across every platform.\n *\n * Unlike injected wallets, it is **not tied to a platform**: one WalletConnect\n * session spans whichever namespaces the remote wallet approves in a single\n * pairing (a namespace can't be added to a live session afterwards). So there is\n * exactly one of these in `wallets`, discriminated by `type: \"walletconnect\"`.\n * Its accounts appear in `accounts`, each carrying its own `platform`.\n */\nexport type WalletConnectWallet = {\n\tid: WalletId;\n\ttype: \"walletconnect\";\n\t/**\n\t * Platforms (namespaces) the live session currently carries. Empty until\n\t * connected; populated with whatever the wallet approved (e.g. just\n\t * `[\"ethereum\"]`, or `[\"polkadot\", \"ethereum\"]`).\n\t */\n\tplatforms: WalletPlatform[];\n\t/**\n\t * Raw Reown AppKit instance, exposed as an escape hatch for advanced use\n\t * (custom modal control, reading providers directly). Most consumers should\n\t * use `connect`/`disconnect` and the derived accounts instead.\n\t */\n\tappKit: AppKitInstance;\n\tname: string;\n\ticon: string;\n\tisConnected: boolean;\n\tconnect: () => Promise<void>;\n\tdisconnect: () => Promise<void>;\n};\n\n/** Narrows a wallet to the platform-less {@link WalletConnectWallet}. */\nexport const isWalletConnectWallet = (\n\twallet: BaseWallet | WalletConnectWallet,\n): wallet is WalletConnectWallet => wallet.type === \"walletconnect\";\n\n/**\n * Narrows a wallet to an injected (browser-extension / Wallet Standard) wallet —\n * the complement of {@link isWalletConnectWallet}. `state.wallets` is\n * `(InjectedWallet | WalletConnectWallet)[]`, so use this to recover the\n * injected-only fields when iterating: `platform`, `sourceId`, and the SDK\n * handle (`provider` on Ethereum, `extension` on Polkadot, `wallet` on Solana).\n *\n * @example\n * ```ts\n * for (const wallet of wallets.filter(isInjectedWallet)) {\n * console.log(wallet.platform, wallet.sourceId); // typed, no WC widening\n * }\n * ```\n */\nexport const isInjectedWallet = <W extends BaseWallet | WalletConnectWallet>(\n\twallet: W,\n): wallet is Exclude<W, WalletConnectWallet> => wallet.type === \"injected\";\n\n/**\n * Dapp metadata shown in the WalletConnect modal. Mirrors WalletConnect's\n * `Metadata`, declared locally so core doesn't depend on\n * `@walletconnect/universal-provider`.\n */\nexport type WalletConnectMetadata = {\n\tname: string;\n\tdescription: string;\n\turl: string;\n\ticons: string[];\n};\n\nexport type WalletConnectConfig = {\n\tprojectId: string;\n\tmetadata: WalletConnectMetadata;\n\t/** Defaults to wss://relay.walletconnect.com */\n\trelayUrl?: string;\n\t/**\n\t * Networks AppKit should enable. Pass `AppKitNetwork[]` from\n\t * `@reown/appkit/networks` (see\n\t * https://docs.reown.com/advanced/multichain/polkadot/dapp-integration-guide#walletconnect-code%2Fcomponent-setup).\n\t * Loosely typed (`unknown`) so core doesn't depend on `@reown/appkit`'s\n\t * types — the value is forwarded to AppKit as-is.\n\t */\n\tnetworks: [unknown, ...unknown[]];\n\tthemeMode?: \"light\" | \"dark\";\n\tthemeVariables?: Record<string, string | number>;\n};\n\n/**\n * Context passed to a platform plugin's `getWallets$`. Carries the shared store\n * and the resolved core config (for WalletConnect / debug).\n */\nexport type PlatformContext = {\n\tstore: KheopskitStore;\n\tconfig: KheopskitConfig;\n};\n\n/**\n * A platform plugin. Created by the per-platform factories exported from\n * `@kheopskit/core/polkadot`, `/ethereum`, `/solana`. Core iterates plugins\n * generically and never imports a platform SDK itself.\n *\n * @typeParam TPlatform - the platform discriminant\n * @typeParam TWallet - the platform's wallet type (extends {@link BaseWallet})\n * @typeParam TAccount - the platform's account type (extends {@link BaseWalletAccount})\n */\nexport type KheopskitPlatform<\n\tTPlatform extends WalletPlatform = WalletPlatform,\n\tTWallet extends BaseWallet = BaseWallet,\n\tTAccount extends BaseWalletAccount = BaseWalletAccount,\n> = {\n\treadonly platform: TPlatform;\n\t// Declared as methods (not arrow properties) so parameters are checked\n\t// bivariantly — this lets a specific `KheopskitPlatform<\"polkadot\", …>` be\n\t// assigned to the base `KheopskitPlatform` despite the contravariant\n\t// `wallets$` parameter.\n\tgetWallets$(ctx: PlatformContext): Observable<TWallet[]>;\n\t// Receives this platform's (injected) wallets plus the shared, platform-less\n\t// WalletConnect connector — the plugin derives its injected accounts and, if\n\t// the WC session carries its namespace, its WalletConnect accounts.\n\tgetAccounts$(\n\t\twallets$: Observable<(TWallet | WalletConnectWallet)[]>,\n\t): Observable<TAccount[]>;\n\t/**\n\t * Optional hydration filter. Cached accounts for which this returns false are\n\t * dropped during SSR hydration (Polkadot uses it to honour `accountTypes`).\n\t */\n\tacceptsCachedAccount?(cached: CachedAccount): boolean;\n};\n\ntype ElementOf<T> = T extends readonly (infer E)[] ? E : never;\n\n/** The account type produced by a plugin (inferred from its `getAccounts$`). */\nexport type AccountOf<T> = T extends {\n\tgetAccounts$: (wallets$: never) => Observable<infer R>;\n}\n\t? ElementOf<R>\n\t: never;\n\n/** The wallet type produced by a plugin (inferred from its `getWallets$`). */\nexport type WalletOf<T> = T extends {\n\tgetWallets$: (ctx: never) => Observable<infer R>;\n}\n\t? ElementOf<R>\n\t: never;\n\nexport type KheopskitConfig<\n\tP extends readonly KheopskitPlatform[] = readonly KheopskitPlatform[],\n> = {\n\tautoReconnect: boolean;\n\t/**\n\t * Platform plugins to enable, e.g. `[polkadot(), solana({ chain })]`.\n\t * Import factories from `@kheopskit/core/<platform>`.\n\t */\n\tplatforms: P;\n\twalletConnect?: WalletConnectConfig;\n\tdebug: boolean;\n\t/**\n\t * Custom storage key for persisting wallet connection state.\n\t * Useful when running multiple kheopskit instances on the same domain\n\t * to prevent state conflicts between different dapps.\n\t *\n\t * @default \"kheopskit\"\n\t */\n\tstorageKey: string;\n\t/**\n\t * Grace period in milliseconds to wait for wallets to inject before\n\t * syncing to actual state. During this period, cached wallet/account\n\t * state from storage is preserved to prevent UI flashing.\n\t *\n\t * Set to 0 to disable hydration buffering.\n\t *\n\t * @default 500\n\t */\n\thydrationGracePeriod: number;\n};\n\n/**\n * The current kheopskit state.\n *\n * @remarks\n * While {@link KheopskitState.isHydrating} is `true`, `wallets` and `accounts`\n * may contain cached placeholders restored from storage. The **SDK handles** the\n * platform types advertise (e.g. `account.signer` / `getSigner` on Solana,\n * `account.client` on Ethereum, `wallet.provider` / `extension`) are **absent at\n * runtime even though the types claim them**, and placeholder wallets throw if\n * `connect`/`disconnect` is called. Guard all access to those behind\n * `!isHydrating`.\n *\n * The plain, serializable platform data that is persisted in the cache IS\n * restored on the placeholders (Ethereum `chainId`, Polkadot key `type`), so it\n * renders immediately on reload without flashing. Solana `chains` is not cached,\n * so it remains absent until the live account loads.\n */\nexport type KheopskitState<\n\tP extends readonly KheopskitPlatform[] = readonly KheopskitPlatform[],\n> = {\n\twallets: (WalletOf<P[number]> | WalletConnectWallet)[];\n\taccounts: AccountOf<P[number]>[];\n\tconfig: KheopskitConfig<P>;\n\t/**\n\t * Whether the state is still being hydrated from cache.\n\t *\n\t * During hydration, cached wallets/accounts may be displayed before the\n\t * actual wallet extensions have injected. See the type-level remarks: while\n\t * this is `true`, SDK-typed fields (signer/client/provider/extension) are not\n\t * present at runtime — guard all access behind `!isHydrating`.\n\t */\n\tisHydrating: boolean;\n};\n\n/** Shape of the persisted store data (localStorage, or cookies in compact form). */\nexport type KheopskitStoreData = {\n\tautoReconnect?: WalletId[];\n\t/** Cached wallet state for SSR hydration to prevent UI flash */\n\tcachedWallets?: CachedWallet[];\n\t/** Cached account state for SSR hydration to prevent UI flash */\n\tcachedAccounts?: CachedAccount[];\n};\n\n/**\n * The persisted settings store shared between core and framework bindings.\n * Declared structurally here (implemented by `createKheopskitStore`) so modules\n * can depend on the interface without importing the implementation.\n */\nexport type KheopskitStore = {\n\tobservable: Observable<KheopskitStoreData>;\n\taddEnabledWalletId: (walletId: WalletId) => void;\n\tremoveEnabledWalletId: (walletId: WalletId) => void;\n\tgetCachedState: () => { wallets: CachedWallet[]; accounts: CachedAccount[] };\n\tsetCachedState: (wallets: CachedWallet[], accounts: CachedAccount[]) => void;\n};\n\n/**\n * Serializable wallet data for SSR hydration cache.\n * Contains only the data needed to render wallet UI without flash.\n * Note: icon is NOT stored to save cookie space - it's looked up at hydration time.\n */\nexport type CachedWallet = {\n\tid: WalletId;\n\t/** Absent for the platform-less WalletConnect connector. */\n\tplatform?: WalletPlatform;\n\ttype: WalletType;\n\tname: string;\n\tisConnected: boolean;\n};\n\n/**\n * Serializable account data for SSR hydration cache.\n * Contains only the data needed to render account UI without flash.\n */\nexport type CachedAccount = {\n\tid: string;\n\tplatform: WalletPlatform;\n\taddress: string;\n\tname?: string;\n\t/** Cached chain ID for Ethereum accounts. */\n\tchainId?: number;\n\t/** Cached key type for Polkadot accounts. */\n\tpolkadotAccountType?: PolkadotAccountType;\n\twalletId: WalletId;\n\twalletName: string;\n};\n"],"mappings":";;;;;AAEO,IAAM,mBAAmB,CAC/B,aAEA,OAAO,aAAa,YACpB,CAAC,YAAY,YAAY,QAAQ,EAAE,SAAS,QAA0B;;;ACIhE,IAAM,2BAAqC;AAE3C,IAAM,cAAc,CAC1B,UACA,eACc;AACd,MAAI,CAAC,iBAAiB,QAAQ,EAAG,OAAM,IAAI,MAAM,kBAAkB;AACnE,MAAI,CAAC,WAAY,OAAM,IAAI,MAAM,cAAc;AAC/C,SAAO,GAAG,QAAQ,IAAI,UAAU;AACjC;AAEO,IAAM,gBAAgB,CAAC,aAAqB;AAClD,MAAI,CAAC,SAAU,OAAM,IAAI,MAAM,kBAAkB;AACjD,QAAM,CAAC,UAAU,UAAU,IAAI,SAAS,MAAM,GAAG;AACjD,MAAI,CAAC,iBAAiB,QAAQ,EAAG,OAAM,IAAI,MAAM,kBAAkB;AACnE,MAAI,CAAC,WAAY,OAAM,IAAI,MAAM,iBAAiB;AAClD,SAAO,EAAE,UAAU,WAAW;AAC/B;AAMO,IAAM,kBAAkB,CAAC,aAA4C;AAC3E,MAAI,OAAO,aAAa,YAAY,CAAC,SAAU,QAAO;AACtD,MAAI,aAAa,yBAA0B,QAAO;AAClD,QAAM,CAAC,UAAU,UAAU,IAAI,SAAS,MAAM,GAAG;AACjD,SAAO,iBAAiB,QAAQ,KAAK,CAAC,CAAC;AACxC;;;AClCA,IAAM,eAAe,uBAAO,IAAI,2BAA2B;AAE3D,IAAM,WAAW,MAAwC;AACxD,QAAM,IAAI;AAIV,MAAI,QAAQ,EAAE,YAAY;AAC1B,MAAI,CAAC,OAAO;AACX,YAAQ,oBAAI,IAAI;AAChB,MAAE,YAAY,IAAI;AAAA,EACnB;AACA,SAAO;AACR;AAEO,IAAM,uBAAuB,CACnC,KACA,WACS;AACT,QAAM,QAAQ,SAAS;AACvB,MAAI,CAAC,MAAM,IAAI,GAAG,EAAG,OAAM,IAAI,KAAK,OAAO,CAAwB;AAEnE,SAAO,MAAM,IAAI,GAAG;AACrB;AAMO,IAAM,wBAAwB,CAAC,QAAsB;AAC3D,WAAS,EAAE,OAAO,GAAG;AACtB;AASO,IAAM,iCAAiC,CAAC,WAAyB;AACvE,QAAM,QAAQ,SAAS;AACvB,aAAW,OAAO,MAAM,KAAK,GAAG;AAC/B,QAAI,IAAI,WAAW,MAAM,EAAG,OAAM,OAAO,GAAG;AAAA,EAC7C;AACD;AAMO,IAAM,4BAA4B,MAAY;AACpD,WAAS,EAAE,MAAM;AAClB;;;ACyDO,IAAM,wBAAwB,CACpC,WACmC,OAAO,SAAS;AAgB7C,IAAM,mBAAmB,CAC/B,WAC+C,OAAO,SAAS;","names":[]}
|
|
@@ -0,0 +1,147 @@
|
|
|
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
|
+
|
|
3
|
+
var _chunkEH73P476js = require('./chunk-EH73P476.js');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
var _chunkP7BPHHVVjs = require('./chunk-P7BPHHVV.js');
|
|
8
|
+
|
|
9
|
+
// src/api/platformAccounts.ts
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
var _rxjs = require('rxjs');
|
|
19
|
+
var createPlatformAccounts$ = ({
|
|
20
|
+
wallets$,
|
|
21
|
+
getInjectedAccounts$,
|
|
22
|
+
getWalletConnectAccounts$,
|
|
23
|
+
mapAccounts,
|
|
24
|
+
accountChangeKey = (account) => account.id
|
|
25
|
+
}) => {
|
|
26
|
+
const accountsListEqual = (a, b) => a.length === b.length && a.every((account, i) => {
|
|
27
|
+
const other = b[i];
|
|
28
|
+
return !!other && accountChangeKey(account) === accountChangeKey(other);
|
|
29
|
+
});
|
|
30
|
+
return new (0, _rxjs.Observable)((subscriber) => {
|
|
31
|
+
const sub = wallets$.pipe(
|
|
32
|
+
_rxjs.map.call(void 0, (wallets) => wallets.filter((w) => w.isConnected)),
|
|
33
|
+
_rxjs.switchMap.call(void 0,
|
|
34
|
+
(wallets) => wallets.length ? _rxjs.combineLatest.call(void 0, [
|
|
35
|
+
...wallets.filter((w) => !_chunkP7BPHHVVjs.isWalletConnectWallet.call(void 0, w)).map(getInjectedAccounts$),
|
|
36
|
+
...wallets.filter(_chunkP7BPHHVVjs.isWalletConnectWallet).map(getWalletConnectAccounts$)
|
|
37
|
+
]) : _rxjs.of.call(void 0, [])
|
|
38
|
+
),
|
|
39
|
+
_rxjs.map.call(void 0, (accounts) => {
|
|
40
|
+
const flat = accounts.flat();
|
|
41
|
+
return mapAccounts ? mapAccounts(flat) : flat;
|
|
42
|
+
}),
|
|
43
|
+
_rxjs.distinctUntilChanged.call(void 0, accountsListEqual)
|
|
44
|
+
).subscribe(subscriber);
|
|
45
|
+
return () => {
|
|
46
|
+
sub.unsubscribe();
|
|
47
|
+
};
|
|
48
|
+
}).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }));
|
|
49
|
+
};
|
|
50
|
+
var getSessionCaip10s = (session, namespace) => Object.values(session.namespaces).flatMap((ns) => _nullishCoalesce(ns.accounts, () => ( []))).filter((account) => account.startsWith(`${namespace}:`));
|
|
51
|
+
var getCaip10Addresses = (caip10s) => [
|
|
52
|
+
...new Set(
|
|
53
|
+
caip10s.map((account) => account.split(":")[2]).filter((address) => !!address)
|
|
54
|
+
)
|
|
55
|
+
];
|
|
56
|
+
var getWalletConnectSessionAccounts$ = (options) => {
|
|
57
|
+
const { wallet, platform, namespace, cacheKey, buildAccounts } = options;
|
|
58
|
+
const provider = wallet.appKit.getProvider(namespace);
|
|
59
|
+
if (!wallet.platforms.includes(platform) || !_optionalChain([provider, 'optionalAccess', _ => _.session])) return _rxjs.of.call(void 0, []);
|
|
60
|
+
return _chunkP7BPHHVVjs.getCachedObservable$.call(void 0,
|
|
61
|
+
cacheKey,
|
|
62
|
+
() => new (0, _rxjs.Observable)((subscriber) => {
|
|
63
|
+
subscriber.next(buildAccounts(provider));
|
|
64
|
+
const reemit = () => subscriber.next(buildAccounts(provider));
|
|
65
|
+
provider.on("session_update", reemit);
|
|
66
|
+
provider.on("accountsChanged", reemit);
|
|
67
|
+
return () => {
|
|
68
|
+
provider.off("session_update", reemit);
|
|
69
|
+
provider.off("accountsChanged", reemit);
|
|
70
|
+
};
|
|
71
|
+
}).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }))
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// src/api/injectedWallets.ts
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
var walletsEqual = (a, b) => {
|
|
85
|
+
if (a.length !== b.length) return false;
|
|
86
|
+
return a.every(
|
|
87
|
+
(w, i) => w.id === _optionalChain([b, 'access', _2 => _2[i], 'optionalAccess', _3 => _3.id]) && w.isConnected === _optionalChain([b, 'access', _4 => _4[i], 'optionalAccess', _5 => _5.isConnected]) && w.name === _optionalChain([b, 'access', _6 => _6[i], 'optionalAccess', _7 => _7.name])
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
var createInjectedWallets$ = (store, adapter) => new (0, _rxjs.Observable)((subscriber) => {
|
|
91
|
+
const handles$ = new (0, _rxjs.BehaviorSubject)(/* @__PURE__ */ new Map());
|
|
92
|
+
const connect = async (source, walletId) => {
|
|
93
|
+
if (handles$.value.has(walletId))
|
|
94
|
+
throw new (0, _chunkEH73P476js.KheopskitError)(
|
|
95
|
+
"WALLET_ALREADY_CONNECTED",
|
|
96
|
+
`wallet ${walletId} is already connected`,
|
|
97
|
+
{ walletId }
|
|
98
|
+
);
|
|
99
|
+
const handle = await adapter.connect(source, walletId);
|
|
100
|
+
const next = new Map(handles$.value);
|
|
101
|
+
next.set(walletId, handle);
|
|
102
|
+
handles$.next(next);
|
|
103
|
+
store.addEnabledWalletId(walletId);
|
|
104
|
+
};
|
|
105
|
+
const disconnect = async (source, walletId) => {
|
|
106
|
+
if (!handles$.value.has(walletId))
|
|
107
|
+
throw new (0, _chunkEH73P476js.KheopskitError)(
|
|
108
|
+
"WALLET_NOT_CONNECTED",
|
|
109
|
+
`wallet ${walletId} is not connected`,
|
|
110
|
+
{ walletId }
|
|
111
|
+
);
|
|
112
|
+
await _optionalChain([adapter, 'access', _8 => _8.disconnect, 'optionalCall', _9 => _9(source, walletId)]);
|
|
113
|
+
const next = new Map(handles$.value);
|
|
114
|
+
next.delete(walletId);
|
|
115
|
+
handles$.next(next);
|
|
116
|
+
store.removeEnabledWalletId(walletId);
|
|
117
|
+
_optionalChain([adapter, 'access', _10 => _10.onDisconnected, 'optionalCall', _11 => _11(walletId)]);
|
|
118
|
+
};
|
|
119
|
+
const sub = _rxjs.combineLatest.call(void 0, [adapter.sources$, handles$]).pipe(
|
|
120
|
+
_rxjs.map.call(void 0,
|
|
121
|
+
([sources, handles]) => sources.map((source) => {
|
|
122
|
+
const walletId = adapter.getWalletId(source);
|
|
123
|
+
return adapter.buildWallet({
|
|
124
|
+
source,
|
|
125
|
+
walletId,
|
|
126
|
+
handle: handles.get(walletId),
|
|
127
|
+
isConnected: handles.has(walletId),
|
|
128
|
+
connect: () => connect(source, walletId),
|
|
129
|
+
disconnect: () => disconnect(source, walletId)
|
|
130
|
+
});
|
|
131
|
+
})
|
|
132
|
+
),
|
|
133
|
+
_rxjs.distinctUntilChanged.call(void 0, walletsEqual)
|
|
134
|
+
).subscribe(subscriber);
|
|
135
|
+
return () => {
|
|
136
|
+
sub.unsubscribe();
|
|
137
|
+
};
|
|
138
|
+
}).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }));
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
exports.createPlatformAccounts$ = createPlatformAccounts$; exports.getSessionCaip10s = getSessionCaip10s; exports.getCaip10Addresses = getCaip10Addresses; exports.getWalletConnectSessionAccounts$ = getWalletConnectSessionAccounts$; exports.createInjectedWallets$ = createInjectedWallets$;
|
|
147
|
+
//# sourceMappingURL=chunk-XOGQMEV2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/kheopskit/kheopskit/packages/core/dist/chunk-XOGQMEV2.js","../src/api/platformAccounts.ts","../src/api/injectedWallets.ts"],"names":["combineLatest","distinctUntilChanged","map","Observable","shareReplay"],"mappings":"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","file":"/home/runner/work/kheopskit/kheopskit/packages/core/dist/chunk-XOGQMEV2.js","sourcesContent":[null,"import {\n\tcombineLatest,\n\tdistinctUntilChanged,\n\tmap,\n\tObservable,\n\tof,\n\tshareReplay,\n\tswitchMap,\n} from \"rxjs\";\nimport { getCachedObservable$ } from \"../utils/getCachedObservable\";\nimport type {\n\tBaseWallet,\n\tBaseWalletAccount,\n\tWalletConnectProvider,\n\tWalletConnectWallet,\n\tWalletPlatform,\n} from \"./types\";\nimport { isWalletConnectWallet } from \"./types\";\n\n/**\n * The platform-specific surface of an accounts stream. The shared pipeline —\n * filter connected wallets, fan out per-wallet account streams, flatten,\n * change-detect, share — is owned by {@link createPlatformAccounts$}.\n */\nexport type PlatformAccountsOptions<\n\tTWallet extends BaseWallet,\n\tTAccount extends BaseWalletAccount,\n> = {\n\t/** This platform's wallets plus the shared WalletConnect connector. */\n\twallets$: Observable<(TWallet | WalletConnectWallet)[]>;\n\t/** Account stream for one connected injected wallet. */\n\tgetInjectedAccounts$: (wallet: TWallet) => Observable<TAccount[]>;\n\t/** Account stream for the WalletConnect connector. */\n\tgetWalletConnectAccounts$: (\n\t\twallet: WalletConnectWallet,\n\t) => Observable<TAccount[]>;\n\t/** Optional post-flatten transform (e.g. Polkadot's `accountTypes` filter). */\n\tmapAccounts?: (accounts: TAccount[]) => TAccount[];\n\t/**\n\t * Signature of the account fields that should trigger a re-emission.\n\t * Defaults to the account id; platforms add mutable fields (Ethereum\n\t * `chainId`, Solana `chains`).\n\t */\n\taccountChangeKey?: (account: TAccount) => string;\n};\n\n/** Shared engine behind every platform's `getAccounts$`. */\nexport const createPlatformAccounts$ = <\n\tTWallet extends BaseWallet,\n\tTAccount extends BaseWalletAccount,\n>({\n\twallets$,\n\tgetInjectedAccounts$,\n\tgetWalletConnectAccounts$,\n\tmapAccounts,\n\taccountChangeKey = (account) => account.id,\n}: PlatformAccountsOptions<TWallet, TAccount>): Observable<TAccount[]> => {\n\tconst accountsListEqual = (a: TAccount[], b: TAccount[]) =>\n\t\ta.length === b.length &&\n\t\ta.every((account, i) => {\n\t\t\tconst other = b[i];\n\t\t\treturn !!other && accountChangeKey(account) === accountChangeKey(other);\n\t\t});\n\n\treturn new Observable<TAccount[]>((subscriber) => {\n\t\tconst sub = wallets$\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\twallets.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 is TWallet => !isWalletConnectWallet(w))\n\t\t\t\t\t\t\t\t\t.map(getInjectedAccounts$),\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) => {\n\t\t\t\t\tconst flat = accounts.flat();\n\t\t\t\t\treturn mapAccounts ? mapAccounts(flat) : flat;\n\t\t\t\t}),\n\t\t\t\tdistinctUntilChanged(accountsListEqual),\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\n/**\n * CAIP-10 account strings (\"<namespace>:<chainRef>:<address>\") the live\n * WalletConnect session carries for a namespace.\n */\nexport const getSessionCaip10s = (\n\tsession: NonNullable<WalletConnectProvider[\"session\"]>,\n\tnamespace: string,\n): string[] =>\n\tObject.values(session.namespaces)\n\t\t.flatMap((ns) => ns.accounts ?? [])\n\t\t.filter((account) => account.startsWith(`${namespace}:`));\n\n/**\n * Unique addresses from CAIP-10 account strings (one entry per chain, so the\n * same address repeats — dedupe).\n */\nexport const getCaip10Addresses = (caip10s: string[]): string[] => [\n\t...new Set(\n\t\tcaip10s\n\t\t\t.map((account) => account.split(\":\")[2])\n\t\t\t.filter((address): address is string => !!address),\n\t),\n];\n\n/**\n * Shared shape of the Polkadot/Solana WalletConnect account streams: no-op\n * unless the session carries the platform's namespace, then a cached\n * observable that rebuilds the account list from the session on\n * `session_update` / `accountsChanged`.\n *\n * AppKit's `getAccount(namespace).allAccounts` is always empty for namespaces\n * without a native AppKit adapter — the WalletConnect session is the source of\n * truth, hence the session-driven rebuild.\n */\nexport const getWalletConnectSessionAccounts$ = <\n\tTAccount extends BaseWalletAccount,\n>(options: {\n\twallet: WalletConnectWallet;\n\tplatform: WalletPlatform;\n\t/** WalletConnect namespace, e.g. \"polkadot\" | \"solana\" | \"eip155\". */\n\tnamespace: string;\n\t/** Cache key for {@link getCachedObservable$} — must be reconnect-safe. */\n\tcacheKey: string;\n\t/** Build the account list from the live session. */\n\tbuildAccounts: (provider: WalletConnectProvider) => TAccount[];\n}): Observable<TAccount[]> => {\n\tconst { wallet, platform, namespace, cacheKey, buildAccounts } = options;\n\tconst provider = wallet.appKit.getProvider(namespace);\n\n\tif (!wallet.platforms.includes(platform) || !provider?.session) return of([]);\n\n\treturn getCachedObservable$(cacheKey, () =>\n\t\tnew Observable<TAccount[]>((subscriber) => {\n\t\t\tsubscriber.next(buildAccounts(provider));\n\n\t\t\t// Re-derive when the WalletConnect session's accounts change, mirroring\n\t\t\t// the injected paths' change subscriptions.\n\t\t\tconst reemit = () => subscriber.next(buildAccounts(provider));\n\t\t\tprovider.on(\"session_update\", reemit);\n\t\t\tprovider.on(\"accountsChanged\", reemit);\n\n\t\t\treturn () => {\n\t\t\t\tprovider.off(\"session_update\", reemit);\n\t\t\t\tprovider.off(\"accountsChanged\", reemit);\n\t\t\t};\n\t\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 })),\n\t);\n};\n","import {\n\tBehaviorSubject,\n\tcombineLatest,\n\tdistinctUntilChanged,\n\tmap,\n\tObservable,\n\tshareReplay,\n} from \"rxjs\";\nimport type { WalletId } from \"../utils/WalletId\";\nimport { KheopskitError } from \"./errors\";\nimport type { KheopskitStore } from \"./store\";\nimport type { BaseWallet } from \"./types\";\n\n/**\n * Compare two wallet arrays by their relevant properties (not functions).\n * Shared by every platform's injected-wallets stream.\n */\nconst walletsEqual = <\n\tW extends Pick<BaseWallet, \"id\" | \"isConnected\" | \"name\">,\n>(\n\ta: W[],\n\tb: W[],\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\n/**\n * The platform-specific surface of an injected-wallets stream. Everything else\n * — the connect/disconnect state machine, the connected-ids bookkeeping, the\n * store persistence, change detection and sharing — is owned by\n * {@link createInjectedWallets$}.\n *\n * @typeParam TSource - a wallet as the platform's registry reports it\n * @typeParam TWallet - the platform's wallet type\n * @typeParam THandle - live connection handle retained while connected\n * (Polkadot keeps the `InjectedExtension`; platforms with no handle use void)\n */\nexport type InjectedWalletsAdapter<\n\tTSource,\n\tTWallet extends BaseWallet,\n\tTHandle = void,\n> = {\n\t/** Live registry of the platform's injected wallets (emits `[]` during SSR). */\n\tsources$: Observable<readonly TSource[]>;\n\t/** Stable wallet id for a registry entry. */\n\tgetWalletId: (source: TSource) => WalletId;\n\t/**\n\t * Platform connect call (e.g. `connectInjectedExtension`,\n\t * `eth_requestAccounts`, `standard:connect`). The resolved value is retained\n\t * as the wallet's live handle until disconnect.\n\t */\n\tconnect: (source: TSource, walletId: WalletId) => Promise<THandle>;\n\t/**\n\t * Optional platform disconnect call, awaited before local state clears so a\n\t * failed disconnect rejects without desyncing the connected list.\n\t */\n\tdisconnect?: (source: TSource, walletId: WalletId) => Promise<void>;\n\t/**\n\t * Runs after a disconnect fully applied — the place to drop cached account\n\t * observables so a later reconnect rebuilds them against a fresh handle.\n\t */\n\tonDisconnected?: (walletId: WalletId) => void;\n\t/** Build the platform wallet object for one registry entry. */\n\tbuildWallet: (args: {\n\t\tsource: TSource;\n\t\twalletId: WalletId;\n\t\t/** Live connection handle; `undefined` while disconnected. */\n\t\thandle: THandle | undefined;\n\t\tisConnected: boolean;\n\t\tconnect: () => Promise<void>;\n\t\tdisconnect: () => Promise<void>;\n\t}) => TWallet;\n};\n\n/**\n * The shared engine behind every platform's injected-wallets stream: tracks\n * connected wallets (and their live handles), guards double\n * connect/disconnect, persists connected ids to the store for auto-reconnect,\n * and re-emits the wallet list whenever the registry or connection state\n * changes.\n */\nexport const createInjectedWallets$ = <\n\tTSource,\n\tTWallet extends BaseWallet,\n\tTHandle = void,\n>(\n\tstore: KheopskitStore,\n\tadapter: InjectedWalletsAdapter<TSource, TWallet, THandle>,\n): Observable<TWallet[]> =>\n\tnew Observable<TWallet[]>((subscriber) => {\n\t\tconst handles$ = new BehaviorSubject<Map<WalletId, THandle>>(new Map());\n\n\t\tconst connect = async (source: TSource, walletId: WalletId) => {\n\t\t\tif (handles$.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\tconst handle = await adapter.connect(source, walletId);\n\n\t\t\tconst next = new Map(handles$.value);\n\t\t\tnext.set(walletId, handle);\n\t\t\thandles$.next(next);\n\n\t\t\tstore.addEnabledWalletId(walletId);\n\t\t};\n\n\t\tconst disconnect = async (source: TSource, walletId: WalletId) => {\n\t\t\tif (!handles$.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\n\t\t\tawait adapter.disconnect?.(source, walletId);\n\n\t\t\tconst next = new Map(handles$.value);\n\t\t\tnext.delete(walletId);\n\t\t\thandles$.next(next);\n\n\t\t\tstore.removeEnabledWalletId(walletId);\n\n\t\t\tadapter.onDisconnected?.(walletId);\n\t\t};\n\n\t\tconst sub = combineLatest([adapter.sources$, handles$])\n\t\t\t.pipe(\n\t\t\t\tmap(([sources, handles]) =>\n\t\t\t\t\tsources.map((source): TWallet => {\n\t\t\t\t\t\tconst walletId = adapter.getWalletId(source);\n\t\t\t\t\t\treturn adapter.buildWallet({\n\t\t\t\t\t\t\tsource,\n\t\t\t\t\t\t\twalletId,\n\t\t\t\t\t\t\thandle: handles.get(walletId),\n\t\t\t\t\t\t\tisConnected: handles.has(walletId),\n\t\t\t\t\t\t\tconnect: () => connect(source, walletId),\n\t\t\t\t\t\t\tdisconnect: () => disconnect(source, 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"]}
|
package/dist/ethereum.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { W as WalletAccountId, a as WalletId, K as KheopskitPlatform } from './types-
|
|
2
|
-
export { b as WalletConnectWallet, i as isInjectedWallet, c as isWalletConnectWallet } from './types-
|
|
1
|
+
import { W as WalletAccountId, a as WalletId, K as KheopskitPlatform } from './types-0iDBydsK.mjs';
|
|
2
|
+
export { b as WalletConnectWallet, i as isInjectedWallet, c as isWalletConnectWallet } from './types-0iDBydsK.mjs';
|
|
3
3
|
import { WalletClient, CustomTransport, Account, EIP1193Provider } from 'viem';
|
|
4
4
|
import 'rxjs';
|
|
5
5
|
|
package/dist/ethereum.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { W as WalletAccountId, a as WalletId, K as KheopskitPlatform } from './types-
|
|
2
|
-
export { b as WalletConnectWallet, i as isInjectedWallet, c as isWalletConnectWallet } from './types-
|
|
1
|
+
import { W as WalletAccountId, a as WalletId, K as KheopskitPlatform } from './types-0iDBydsK.js';
|
|
2
|
+
export { b as WalletConnectWallet, i as isInjectedWallet, c as isWalletConnectWallet } from './types-0iDBydsK.js';
|
|
3
3
|
import { WalletClient, CustomTransport, Account, EIP1193Provider } from 'viem';
|
|
4
4
|
import 'rxjs';
|
|
5
5
|
|
package/dist/ethereum.js
CHANGED
|
@@ -3,18 +3,21 @@
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkXOGQMEV2js = require('./chunk-XOGQMEV2.js');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
var _chunkEH73P476js = require('./chunk-EH73P476.js');
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
|
|
13
|
-
var _chunk4ENHC7G4js = require('./chunk-4ENHC7G4.js');
|
|
14
14
|
|
|
15
|
-
// src/api/ethereum/accounts.ts
|
|
16
15
|
|
|
17
16
|
|
|
17
|
+
var _chunkP7BPHHVVjs = require('./chunk-P7BPHHVV.js');
|
|
18
|
+
|
|
19
|
+
// src/api/ethereum/accounts.ts
|
|
20
|
+
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
|
|
@@ -53,7 +56,7 @@ var toCaipNetworkId = (value) => {
|
|
|
53
56
|
};
|
|
54
57
|
var getInjectedWalletAccounts$ = (wallet) => {
|
|
55
58
|
if (!wallet.isConnected) return _rxjs.of.call(void 0, []);
|
|
56
|
-
return
|
|
59
|
+
return _chunkP7BPHHVVjs.getCachedObservable$.call(void 0,
|
|
57
60
|
`accounts:${wallet.id}`,
|
|
58
61
|
() => new (0, _rxjs.Observable)((subscriber) => {
|
|
59
62
|
const addresses$ = new (0, _rxjs.ReplaySubject)(1);
|
|
@@ -64,7 +67,7 @@ var getInjectedWalletAccounts$ = (wallet) => {
|
|
|
64
67
|
transport: _viem.custom.call(void 0, wallet.provider)
|
|
65
68
|
});
|
|
66
69
|
return {
|
|
67
|
-
id:
|
|
70
|
+
id: _chunkEH73P476js.getWalletAccountId.call(void 0, wallet.id, address),
|
|
68
71
|
platform: "ethereum",
|
|
69
72
|
client,
|
|
70
73
|
address: _viem.getAddress.call(void 0, address),
|
|
@@ -128,7 +131,7 @@ var getWalletConnectAccounts$ = (wallet) => {
|
|
|
128
131
|
const provider = wallet.appKit.getProvider("eip155");
|
|
129
132
|
if (!wallet.platforms.includes("ethereum") || !_optionalChain([provider, 'optionalAccess', _ => _.session]))
|
|
130
133
|
return _rxjs.of.call(void 0, []);
|
|
131
|
-
return
|
|
134
|
+
return _chunkP7BPHHVVjs.getCachedObservable$.call(void 0,
|
|
132
135
|
`accounts:${wallet.id}:ethereum:`,
|
|
133
136
|
() => new (0, _rxjs.Observable)((subscriber) => {
|
|
134
137
|
const caipNetworkId$ = new (0, _rxjs.ReplaySubject)(1);
|
|
@@ -137,15 +140,12 @@ var getWalletConnectAccounts$ = (wallet) => {
|
|
|
137
140
|
const session = provider.session;
|
|
138
141
|
if (!session) return [];
|
|
139
142
|
const addresses = /* @__PURE__ */ new Set();
|
|
140
|
-
for (const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
addresses.add(_viem.getAddress.call(void 0, raw));
|
|
147
|
-
} catch (e) {
|
|
148
|
-
}
|
|
143
|
+
for (const raw of _chunkXOGQMEV2js.getCaip10Addresses.call(void 0,
|
|
144
|
+
_chunkXOGQMEV2js.getSessionCaip10s.call(void 0, session, "eip155")
|
|
145
|
+
)) {
|
|
146
|
+
try {
|
|
147
|
+
addresses.add(_viem.getAddress.call(void 0, raw));
|
|
148
|
+
} catch (e) {
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
return [...addresses];
|
|
@@ -153,12 +153,9 @@ var getWalletConnectAccounts$ = (wallet) => {
|
|
|
153
153
|
const readCaipNetworkId = () => {
|
|
154
154
|
const session = provider.session;
|
|
155
155
|
if (!session) return void 0;
|
|
156
|
-
for (const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const ref = account.split(":")[1];
|
|
160
|
-
if (ref) return `eip155:${ref}`;
|
|
161
|
-
}
|
|
156
|
+
for (const account of _chunkXOGQMEV2js.getSessionCaip10s.call(void 0, session, "eip155")) {
|
|
157
|
+
const ref = account.split(":")[1];
|
|
158
|
+
if (ref) return `eip155:${ref}`;
|
|
162
159
|
}
|
|
163
160
|
return void 0;
|
|
164
161
|
};
|
|
@@ -196,7 +193,7 @@ var getWalletConnectAccounts$ = (wallet) => {
|
|
|
196
193
|
transport
|
|
197
194
|
});
|
|
198
195
|
return {
|
|
199
|
-
id:
|
|
196
|
+
id: _chunkEH73P476js.getWalletAccountId.call(void 0, wallet.id, addr),
|
|
200
197
|
platform: "ethereum",
|
|
201
198
|
walletName: wallet.name,
|
|
202
199
|
walletId: wallet.id,
|
|
@@ -216,44 +213,19 @@ var getWalletConnectAccounts$ = (wallet) => {
|
|
|
216
213
|
}).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }))
|
|
217
214
|
);
|
|
218
215
|
};
|
|
219
|
-
var getEthereumAccounts$ = (ethereumWallets) =>
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
]) : _rxjs.of.call(void 0, []);
|
|
227
|
-
}),
|
|
228
|
-
_rxjs.map.call(void 0, (accounts) => accounts.flat()),
|
|
229
|
-
_rxjs.distinctUntilChanged.call(void 0, isSameAccountsList)
|
|
230
|
-
).subscribe(subscriber);
|
|
231
|
-
return () => {
|
|
232
|
-
sub.unsubscribe();
|
|
233
|
-
};
|
|
234
|
-
}).pipe(
|
|
235
|
-
// logObservable("ethereumAccounts$", true),
|
|
236
|
-
_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 })
|
|
237
|
-
);
|
|
238
|
-
var isSameAccountsList = (a, b) => {
|
|
239
|
-
if (a.length !== b.length) return false;
|
|
240
|
-
return a.every(
|
|
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])
|
|
242
|
-
);
|
|
243
|
-
};
|
|
216
|
+
var getEthereumAccounts$ = (ethereumWallets) => _chunkXOGQMEV2js.createPlatformAccounts$.call(void 0, {
|
|
217
|
+
wallets$: ethereumWallets,
|
|
218
|
+
getInjectedAccounts$: getInjectedWalletAccounts$,
|
|
219
|
+
getWalletConnectAccounts$,
|
|
220
|
+
// Re-emit on chain switches, not just account id changes.
|
|
221
|
+
accountChangeKey: (account) => `${account.id}|${_nullishCoalesce(account.chainId, () => ( ""))}`
|
|
222
|
+
});
|
|
244
223
|
|
|
245
224
|
// src/api/ethereum/wallets.ts
|
|
246
225
|
|
|
247
226
|
|
|
248
227
|
var _mipd = require('mipd');
|
|
249
228
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
229
|
var providersDetails$ = new (0, _rxjs.Observable)(
|
|
258
230
|
(subscriber) => {
|
|
259
231
|
if (typeof window === "undefined") {
|
|
@@ -273,68 +245,36 @@ var providersDetails$ = new (0, _rxjs.Observable)(
|
|
|
273
245
|
};
|
|
274
246
|
}
|
|
275
247
|
).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }));
|
|
276
|
-
var
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
"WALLET_ALREADY_CONNECTED",
|
|
282
|
-
`wallet ${walletId} is already connected`,
|
|
283
|
-
{ walletId }
|
|
284
|
-
);
|
|
285
|
-
await provider.request({
|
|
248
|
+
var getEthereumWallets$ = (store) => _chunkXOGQMEV2js.createInjectedWallets$.call(void 0, store, {
|
|
249
|
+
sources$: providersDetails$,
|
|
250
|
+
getWalletId: (pd) => _chunkP7BPHHVVjs.getWalletId.call(void 0, "ethereum", pd.info.rdns),
|
|
251
|
+
connect: async (pd) => {
|
|
252
|
+
await pd.provider.request({
|
|
286
253
|
method: "eth_requestAccounts"
|
|
287
254
|
});
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
return {
|
|
312
|
-
platform: "ethereum",
|
|
313
|
-
type: "injected",
|
|
314
|
-
id: walletId,
|
|
315
|
-
name: pd.info.name,
|
|
316
|
-
icon: pd.info.icon,
|
|
317
|
-
provider,
|
|
318
|
-
isConnected: enabledWalletIds.has(walletId),
|
|
319
|
-
sourceId: pd.info.rdns,
|
|
320
|
-
connect: () => connectWallet(walletId, provider),
|
|
321
|
-
disconnect: () => disconnectWallet(walletId)
|
|
322
|
-
};
|
|
323
|
-
});
|
|
324
|
-
}),
|
|
325
|
-
_rxjs.distinctUntilChanged.call(void 0, walletsEqual)
|
|
326
|
-
).subscribe(subscriber);
|
|
327
|
-
return () => {
|
|
328
|
-
sub.unsubscribe();
|
|
329
|
-
};
|
|
330
|
-
}).pipe(_rxjs.shareReplay.call(void 0, { refCount: true, bufferSize: 1 }));
|
|
331
|
-
var getEthereumWallets$ = (store2 = _chunkXQWJM3KCjs.store) => createEthereumInjectedWallets$(store2);
|
|
332
|
-
var walletsEqual = (a, b) => {
|
|
333
|
-
if (a.length !== b.length) return false;
|
|
334
|
-
return a.every(
|
|
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])
|
|
336
|
-
);
|
|
337
|
-
};
|
|
255
|
+
},
|
|
256
|
+
// Drop the cached account observable so a later reconnect rebuilds it
|
|
257
|
+
// against the current provider, not a stale closure.
|
|
258
|
+
onDisconnected: (walletId) => _chunkP7BPHHVVjs.clearCachedObservable.call(void 0, `accounts:${walletId}`),
|
|
259
|
+
buildWallet: ({
|
|
260
|
+
source: pd,
|
|
261
|
+
walletId,
|
|
262
|
+
isConnected,
|
|
263
|
+
connect,
|
|
264
|
+
disconnect
|
|
265
|
+
}) => ({
|
|
266
|
+
platform: "ethereum",
|
|
267
|
+
type: "injected",
|
|
268
|
+
id: walletId,
|
|
269
|
+
name: pd.info.name,
|
|
270
|
+
icon: pd.info.icon,
|
|
271
|
+
provider: pd.provider,
|
|
272
|
+
isConnected,
|
|
273
|
+
sourceId: pd.info.rdns,
|
|
274
|
+
connect,
|
|
275
|
+
disconnect
|
|
276
|
+
})
|
|
277
|
+
});
|
|
338
278
|
|
|
339
279
|
// src/api/ethereum/plugin.ts
|
|
340
280
|
var ethereum = () => ({
|
|
@@ -347,5 +287,5 @@ var ethereum = () => ({
|
|
|
347
287
|
|
|
348
288
|
|
|
349
289
|
|
|
350
|
-
exports.ethereum = ethereum; exports.isEthereumAddress =
|
|
290
|
+
exports.ethereum = ethereum; exports.isEthereumAddress = _chunkEH73P476js.isEthereumAddress; exports.isInjectedWallet = _chunkP7BPHHVVjs.isInjectedWallet; exports.isWalletConnectWallet = _chunkP7BPHHVVjs.isWalletConnectWallet;
|
|
351
291
|
//# sourceMappingURL=ethereum.js.map
|
package/dist/ethereum.js.map
CHANGED
|
@@ -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 { 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\t// WalletConnect's UniversalProvider reads the target CAIP chain id from\n\t\t\t\t// the SECOND positional argument of `request(args, chainId)`, not from a\n\t\t\t\t// field on the args object. This AppKit instance has no native eip155\n\t\t\t\t// adapter, so the provider has no default chain — without the positional\n\t\t\t\t// chain id every call is rejected (\"Unsupported chains\" / \"Method not\n\t\t\t\t// found\"). Pass it positionally so the request routes to the session's\n\t\t\t\t// chain.\n\t\t\t\treturn (\n\t\t\t\t\ttarget.request as (a: unknown, chainId?: string) => Promise<unknown>\n\t\t\t\t)(next, caipNetworkId);\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"]}
|
|
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":["shareReplay","Observable","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} 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 {\n\tcreatePlatformAccounts$,\n\tgetCaip10Addresses,\n\tgetSessionCaip10s,\n} from \"../platformAccounts\";\nimport type { WalletConnectWallet } 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\t// WalletConnect's UniversalProvider reads the target CAIP chain id from\n\t\t\t\t// the SECOND positional argument of `request(args, chainId)`, not from a\n\t\t\t\t// field on the args object. This AppKit instance has no native eip155\n\t\t\t\t// adapter, so the provider has no default chain — without the positional\n\t\t\t\t// chain id every call is rejected (\"Unsupported chains\" / \"Method not\n\t\t\t\t// found\"). Pass it positionally so the request routes to the session's\n\t\t\t\t// chain.\n\t\t\t\treturn (\n\t\t\t\t\ttarget.request as (a: unknown, chainId?: string) => Promise<unknown>\n\t\t\t\t)(next, caipNetworkId);\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 raw of getCaip10Addresses(\n\t\t\t\t\tgetSessionCaip10s(session, \"eip155\"),\n\t\t\t\t)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\taddresses.add(getAddress(raw));\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// skip malformed CAIP-10 address\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 account of getSessionCaip10s(session, \"eip155\")) {\n\t\t\t\t\tconst ref = account.split(\":\")[1];\n\t\t\t\t\tif (ref) return `eip155:${ref}`;\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\tcreatePlatformAccounts$({\n\t\twallets$: ethereumWallets,\n\t\tgetInjectedAccounts$: getInjectedWalletAccounts$,\n\t\tgetWalletConnectAccounts$,\n\t\t// Re-emit on chain switches, not just account id changes.\n\t\taccountChangeKey: (account) => `${account.id}|${account.chainId ?? \"\"}`,\n\t});\n","import {\n\tcreateStore as createMipdStore,\n\ttype EIP6963ProviderDetail,\n} from \"mipd\";\nimport { Observable, shareReplay } from \"rxjs\";\nimport type { EIP1193Provider } from \"viem\";\nimport { clearCachedObservable } from \"../../utils/getCachedObservable\";\nimport { getWalletId } from \"../../utils/WalletId\";\nimport { createInjectedWallets$ } from \"../injectedWallets\";\nimport 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\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) =>\n\tcreateInjectedWallets$<EIP6963ProviderDetail, EthereumInjectedWallet>(store, {\n\t\tsources$: providersDetails$,\n\t\tgetWalletId: (pd) => getWalletId(\"ethereum\", pd.info.rdns),\n\t\tconnect: async (pd) => {\n\t\t\tawait (pd.provider as EIP1193Provider).request({\n\t\t\t\tmethod: \"eth_requestAccounts\",\n\t\t\t});\n\t\t},\n\t\t// Drop the cached account observable so a later reconnect rebuilds it\n\t\t// against the current provider, not a stale closure.\n\t\tonDisconnected: (walletId) => clearCachedObservable(`accounts:${walletId}`),\n\t\tbuildWallet: ({\n\t\t\tsource: pd,\n\t\t\twalletId,\n\t\t\tisConnected,\n\t\t\tconnect,\n\t\t\tdisconnect,\n\t\t}) => ({\n\t\t\tplatform: \"ethereum\",\n\t\t\ttype: \"injected\",\n\t\t\tid: walletId,\n\t\t\tname: pd.info.name,\n\t\t\ticon: pd.info.icon,\n\t\t\tprovider: pd.provider as EIP1193Provider,\n\t\t\tisConnected,\n\t\t\tsourceId: pd.info.rdns,\n\t\t\tconnect,\n\t\t\tdisconnect,\n\t\t}),\n\t});\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"]}
|