@kheopskit/core 5.2.0 → 5.3.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/README.md +1 -0
- package/dist/{errors-Caq2csKx.mjs → errors-BLFP1dQI.mjs} +5 -5
- package/dist/{errors-Caq2csKx.mjs.map → errors-BLFP1dQI.mjs.map} +1 -1
- package/dist/{errors-DPw6pc2H.js → errors-DYWVPHrR.js} +5 -5
- package/dist/errors-DYWVPHrR.js.map +1 -0
- package/dist/ethereum.d.mts +4 -4
- package/dist/ethereum.d.ts +4 -4
- package/dist/ethereum.js +2 -2
- package/dist/ethereum.js.map +1 -1
- package/dist/ethereum.mjs +2 -2
- package/dist/{iconCache-CicUSbR1.js → iconCache-DUtkJlaX.js} +2 -2
- package/dist/{iconCache-CicUSbR1.js.map → iconCache-DUtkJlaX.js.map} +1 -1
- package/dist/{iconCache-Cml-6Rft.mjs → iconCache-pP2ES4pJ.mjs} +2 -2
- package/dist/{iconCache-Cml-6Rft.mjs.map → iconCache-pP2ES4pJ.mjs.map} +1 -1
- package/dist/index.d.mts +12 -12
- package/dist/index.d.ts +12 -12
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{injectedWallets-B1MCxAE9.js → injectedWallets-BqR-_aAy.js} +2 -2
- package/dist/injectedWallets-BqR-_aAy.js.map +1 -0
- package/dist/{injectedWallets-B3Vysfvr.mjs → injectedWallets-Uz4hPuoW.mjs} +2 -2
- package/dist/{injectedWallets-B3Vysfvr.mjs.map → injectedWallets-Uz4hPuoW.mjs.map} +1 -1
- package/dist/internal.d.mts +6 -6
- package/dist/internal.d.ts +6 -6
- package/dist/internal.js +1 -1
- package/dist/internal.mjs +1 -1
- package/dist/polkadot.d.mts +4 -4
- package/dist/polkadot.d.ts +4 -4
- package/dist/polkadot.js +6 -6
- package/dist/polkadot.js.map +1 -1
- package/dist/polkadot.mjs +5 -5
- package/dist/polkadot.mjs.map +1 -1
- package/dist/solana.d.mts +7 -7
- package/dist/solana.d.ts +7 -7
- package/dist/solana.js +2 -2
- package/dist/solana.js.map +1 -1
- package/dist/solana.mjs +2 -2
- package/dist/{types-Cb-vuEru.d.ts → types-AxUDtkR-.d.mts} +9 -1
- package/dist/{types-Cb-vuEru.d.mts → types-AxUDtkR-.d.ts} +9 -1
- package/dist/types-DKU-SNio.js.map +1 -1
- package/dist/types-jnifAAA0.mjs.map +1 -1
- package/package.json +8 -8
- package/dist/errors-DPw6pc2H.js.map +0 -1
- package/dist/injectedWallets-B1MCxAE9.js.map +0 -1
package/dist/solana.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solana.js","names":["KheopskitError","KheopskitError","getCachedObservable$","Observable","getWalletAccountId","getWalletConnectSessionAccounts$","getSessionCaip10s","getCaip10Addresses","createPlatformAccounts$","Observable","createInjectedWallets$","getWalletId","KheopskitError","clearCachedObservablesByPrefix"],"sources":["../src/api/solana/chains.ts","../src/api/solana/signer.ts","../src/api/solana/accounts.ts","../src/api/solana/wallets.ts","../src/api/solana/plugin.ts"],"sourcesContent":["import { KheopskitError } from \"../errors\";\n\n/**\n * Wallet Standard chain identifiers for Solana clusters.\n *\n * These are the values wallets advertise in their `chains` arrays and the\n * values kheopskit accepts in `solana({ chain })`.\n *\n * @see https://github.com/anza-xyz/wallet-standard\n */\nexport type SolanaChainId =\n\t| \"solana:mainnet\"\n\t| \"solana:devnet\"\n\t| \"solana:testnet\"\n\t| \"solana:localnet\";\n\nexport const DEFAULT_SOLANA_CHAIN: SolanaChainId = \"solana:mainnet\";\n\nconst SOLANA_CHAIN_IDS = [\n\t\"solana:mainnet\",\n\t\"solana:devnet\",\n\t\"solana:testnet\",\n\t\"solana:localnet\",\n] as const satisfies SolanaChainId[];\n\nexport const isSolanaChainId = (value: unknown): value is SolanaChainId =>\n\ttypeof value === \"string\" &&\n\t(SOLANA_CHAIN_IDS as readonly string[]).includes(value);\n\n/**\n * Maps Wallet Standard chain ids to the CAIP-2 chain ids used by WalletConnect.\n *\n * CAIP-2 ids use the first 32 characters of the cluster's genesis hash as the\n * reference. The values below match `@reown/appkit/networks` (solana,\n * solanaDevnet, solanaTestnet), which is what AppKit puts in session namespaces.\n *\n * `localnet` has no canonical CAIP-2 id and cannot be used over WalletConnect.\n */\nconst SOLANA_CHAIN_TO_CAIP2 = {\n\t\"solana:mainnet\": \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\",\n\t\"solana:devnet\": \"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1\",\n\t\"solana:testnet\": \"solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z\",\n} as const satisfies Partial<Record<SolanaChainId, string>>;\n\n/**\n * Returns the CAIP-2 chain id for a Solana chain, for use in WalletConnect\n * requests and when reading WalletConnect session namespaces.\n *\n * @throws if the chain has no canonical CAIP-2 id (e.g. localnet)\n */\nexport const getSolanaCaip2 = (chain: SolanaChainId): string => {\n\tconst caip2 = (SOLANA_CHAIN_TO_CAIP2 as Record<string, string | undefined>)[\n\t\tchain\n\t];\n\tif (!caip2)\n\t\tthrow new KheopskitError(\n\t\t\t\"UNSUPPORTED_CHAIN\",\n\t\t\t`Solana chain \"${chain}\" cannot be used over WalletConnect (no CAIP-2 id).`,\n\t\t);\n\treturn caip2;\n};\n\n/**\n * AppKit's *deprecated* CAIP-2 cluster ids (its `deprecatedCaipNetworkId`\n * values). Some wallets still place accounts in the WC session under these, so\n * map them back to a {@link SolanaChainId} instead of silently falling back to\n * the configured chain. Requests always use the current ids from\n * {@link SOLANA_CHAIN_TO_CAIP2}; testnet has no deprecated id.\n */\nconst DEPRECATED_CAIP2_TO_SOLANA_CHAIN: Record<string, SolanaChainId> = {\n\t\"solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ\": \"solana:mainnet\",\n\t\"solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K\": \"solana:devnet\",\n};\n\nconst CAIP2_TO_SOLANA_CHAIN: Record<string, SolanaChainId> = {\n\t...Object.fromEntries(\n\t\tObject.entries(SOLANA_CHAIN_TO_CAIP2).map(([chain, caip2]) => [\n\t\t\tcaip2,\n\t\t\tchain as SolanaChainId,\n\t\t]),\n\t),\n\t...DEPRECATED_CAIP2_TO_SOLANA_CHAIN,\n};\n\n/**\n * Maps a CAIP-2 chain id (as found in WalletConnect session namespaces) back to\n * its {@link SolanaChainId}, or `undefined` if it isn't a recognised cluster.\n */\nexport const getSolanaChainIdFromCaip2 = (\n\tcaip2: string,\n): SolanaChainId | undefined => CAIP2_TO_SOLANA_CHAIN[caip2];\n","import {\n\taddress,\n\tgetBase58Decoder,\n\tgetBase58Encoder,\n\tgetBase64Decoder,\n\tgetBase64Encoder,\n\tgetTransactionDecoder,\n\tgetTransactionEncoder,\n\ttype SignableMessage,\n\ttype SignatureBytes,\n\ttype TransactionModifyingSigner,\n} from \"@solana/kit\";\nimport type {\n\tSolanaSignAndSendTransactionFeature,\n\tSolanaSignMessageFeature,\n\tSolanaSignTransactionFeature,\n} from \"@solana/wallet-standard-features\";\nimport type {\n\tWalletAccount,\n\tWallet as WalletStandardWallet,\n} from \"@wallet-standard/base\";\nimport { KheopskitError } from \"../errors\";\nimport type { WalletConnectProvider } from \"../types\";\nimport { getSolanaCaip2, type SolanaChainId } from \"./chains\";\nimport type { SolanaSigner } from \"./types\";\n\nconst SOLANA_SIGN_MESSAGE = \"solana:signMessage\";\nconst SOLANA_SIGN_TRANSACTION = \"solana:signTransaction\";\nconst SOLANA_SIGN_AND_SEND_TRANSACTION = \"solana:signAndSendTransaction\";\n\ntype SignMessageApi = SolanaSignMessageFeature[typeof SOLANA_SIGN_MESSAGE];\ntype SignTransactionApi =\n\tSolanaSignTransactionFeature[typeof SOLANA_SIGN_TRANSACTION];\ntype SignAndSendApi =\n\tSolanaSignAndSendTransactionFeature[typeof SOLANA_SIGN_AND_SEND_TRANSACTION];\n\n/** The branded array type expected back from a transaction-modifying signer. */\ntype SignedTransactions = Awaited<\n\tReturnType<TransactionModifyingSigner[\"modifyAndSignTransactions\"]>\n>;\n\nconst requireFeature = <T>(wallet: WalletStandardWallet, name: string): T => {\n\tconst feature = (wallet.features as Record<string, unknown>)[name];\n\tif (!feature)\n\t\tthrow new KheopskitError(\n\t\t\t\"FEATURE_NOT_SUPPORTED\",\n\t\t\t`wallet \"${wallet.name}\" does not support ${name}`,\n\t\t);\n\treturn feature as T;\n};\n\n/**\n * Builds a {@link SolanaSigner} backed by a Wallet Standard wallet's\n * `solana:*` features (injected wallets).\n *\n * Transactions are exchanged as wire bytes; messages and signatures as raw\n * bytes. Calling a method whose feature the wallet does not advertise throws.\n */\nexport const createInjectedSolanaSigner = (\n\twallet: WalletStandardWallet,\n\taccount: WalletAccount,\n\tchain: SolanaChainId,\n): SolanaSigner => {\n\tconst signerAddress = address(account.address);\n\n\treturn {\n\t\taddress: signerAddress,\n\t\tmodifyAndSignMessages: async (messages) => {\n\t\t\tconst feature = requireFeature<SignMessageApi>(\n\t\t\t\twallet,\n\t\t\t\tSOLANA_SIGN_MESSAGE,\n\t\t\t);\n\t\t\tconst outputs = await feature.signMessage(\n\t\t\t\t...messages.map((m) => ({ account, message: m.content })),\n\t\t\t);\n\t\t\treturn messages.map((m, i) => {\n\t\t\t\tconst output = outputs[i];\n\t\t\t\tif (!output) throw new Error(\"[kheopskit] missing signMessage output\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: output.signedMessage,\n\t\t\t\t\tsignatures: {\n\t\t\t\t\t\t...m.signatures,\n\t\t\t\t\t\t[signerAddress]: output.signature as SignatureBytes,\n\t\t\t\t\t},\n\t\t\t\t} satisfies SignableMessage;\n\t\t\t});\n\t\t},\n\t\tmodifyAndSignTransactions: async (transactions) => {\n\t\t\tconst feature = requireFeature<SignTransactionApi>(\n\t\t\t\twallet,\n\t\t\t\tSOLANA_SIGN_TRANSACTION,\n\t\t\t);\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst decoder = getTransactionDecoder();\n\t\t\tconst outputs = await feature.signTransaction(\n\t\t\t\t...transactions.map((tx) => ({\n\t\t\t\t\taccount,\n\t\t\t\t\ttransaction: new Uint8Array(encoder.encode(tx)),\n\t\t\t\t\tchain,\n\t\t\t\t})),\n\t\t\t);\n\t\t\treturn transactions.map((_tx, i) => {\n\t\t\t\tconst output = outputs[i];\n\t\t\t\tif (!output)\n\t\t\t\t\tthrow new Error(\"[kheopskit] missing signTransaction output\");\n\t\t\t\treturn decoder.decode(output.signedTransaction);\n\t\t\t}) as unknown as SignedTransactions;\n\t\t},\n\t\tsignAndSendTransactions: async (transactions) => {\n\t\t\tconst feature = requireFeature<SignAndSendApi>(\n\t\t\t\twallet,\n\t\t\t\tSOLANA_SIGN_AND_SEND_TRANSACTION,\n\t\t\t);\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst outputs = await feature.signAndSendTransaction(\n\t\t\t\t...transactions.map((tx) => ({\n\t\t\t\t\taccount,\n\t\t\t\t\ttransaction: new Uint8Array(encoder.encode(tx)),\n\t\t\t\t\tchain,\n\t\t\t\t})),\n\t\t\t);\n\t\t\treturn outputs.map((output) => output.signature as SignatureBytes);\n\t\t},\n\t};\n};\n\n/**\n * Builds a {@link SolanaSigner} backed by a WalletConnect session, adapting the\n * `solana_*` RPC methods to the same interface as the injected signer.\n *\n * The CAIP-2 chain id is derived from {@link SolanaChainId}; transactions are\n * base64-encoded and messages/signatures base58-encoded, per the WalletConnect\n * Solana spec.\n */\nexport const createWalletConnectSolanaSigner = (\n\tprovider: WalletConnectProvider,\n\taccountAddress: string,\n\tchain: SolanaChainId,\n): SolanaSigner => {\n\tconst signerAddress = address(accountAddress);\n\n\tconst request = <T>(method: string, params: unknown): Promise<T> => {\n\t\tif (!provider.session)\n\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\t\t// Resolved lazily (not at signer construction) so building a signer for a\n\t\t// cluster without a CAIP-2 id (e.g. localnet) doesn't throw until a request\n\t\t// is actually attempted.\n\t\treturn provider.client.request<T>({\n\t\t\ttopic: provider.session.topic,\n\t\t\tchainId: getSolanaCaip2(chain),\n\t\t\trequest: { method, params },\n\t\t});\n\t};\n\n\treturn {\n\t\taddress: signerAddress,\n\t\tmodifyAndSignMessages: async (messages) => {\n\t\t\t// @solana/kit naming is the inverse of the value direction here: a\n\t\t\t// Decoder turns bytes -> string (so `toBase58` produces a base58 string),\n\t\t\t// an Encoder turns string -> bytes (so `fromBase58` parses one).\n\t\t\tconst toBase58 = getBase58Decoder();\n\t\t\tconst fromBase58 = getBase58Encoder();\n\t\t\treturn Promise.all(\n\t\t\t\tmessages.map(async (m) => {\n\t\t\t\t\tconst { signature } = await request<{ signature: string }>(\n\t\t\t\t\t\t\"solana_signMessage\",\n\t\t\t\t\t\t{ pubkey: accountAddress, message: toBase58.decode(m.content) },\n\t\t\t\t\t);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: m.content,\n\t\t\t\t\t\tsignatures: {\n\t\t\t\t\t\t\t...m.signatures,\n\t\t\t\t\t\t\t[signerAddress]: fromBase58.encode(signature) as SignatureBytes,\n\t\t\t\t\t\t},\n\t\t\t\t\t} satisfies SignableMessage;\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t\tmodifyAndSignTransactions: async (transactions) => {\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst decoder = getTransactionDecoder();\n\t\t\tconst toBase64 = getBase64Decoder();\n\t\t\tconst fromBase64 = getBase64Encoder();\n\t\t\tconst fromBase58 = getBase58Encoder();\n\t\t\tconst signed = await Promise.all(\n\t\t\t\ttransactions.map(async (tx) => {\n\t\t\t\t\tconst result = await request<{\n\t\t\t\t\t\ttransaction?: string;\n\t\t\t\t\t\tsignature?: string;\n\t\t\t\t\t}>(\"solana_signTransaction\", {\n\t\t\t\t\t\ttransaction: toBase64.decode(encoder.encode(tx)),\n\t\t\t\t\t});\n\t\t\t\t\t// Wallets may return either the full signed transaction (base64)\n\t\t\t\t\t// or just the signature (base58) to merge into the original.\n\t\t\t\t\tif (result.transaction)\n\t\t\t\t\t\treturn decoder.decode(fromBase64.encode(result.transaction));\n\t\t\t\t\tif (result.signature)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...tx,\n\t\t\t\t\t\t\tsignatures: {\n\t\t\t\t\t\t\t\t...tx.signatures,\n\t\t\t\t\t\t\t\t[signerAddress]: fromBase58.encode(\n\t\t\t\t\t\t\t\t\tresult.signature,\n\t\t\t\t\t\t\t\t) as SignatureBytes,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"[kheopskit] solana_signTransaction returned no transaction or signature\",\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn signed as unknown as SignedTransactions;\n\t\t},\n\t\tsignAndSendTransactions: async (transactions) => {\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst toBase64 = getBase64Decoder();\n\t\t\tconst fromBase58 = getBase58Encoder();\n\t\t\treturn Promise.all(\n\t\t\t\ttransactions.map(async (tx) => {\n\t\t\t\t\tconst { signature } = await request<{ signature: string }>(\n\t\t\t\t\t\t\"solana_signAndSendTransaction\",\n\t\t\t\t\t\t{ transaction: toBase64.decode(encoder.encode(tx)) },\n\t\t\t\t\t);\n\t\t\t\t\treturn fromBase58.encode(signature) as SignatureBytes;\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t};\n};\n","import type { StandardEventsFeature } from \"@wallet-standard/features\";\nimport { Observable, of, shareReplay } from \"rxjs\";\nimport { getWalletAccountId } from \"../../utils\";\nimport { getCachedObservable$ } from \"../../utils/getCachedObservable\";\nimport {\n\tcreatePlatformAccounts$,\n\tgetCaip10Addresses,\n\tgetSessionCaip10s,\n\tgetWalletConnectSessionAccounts$,\n} from \"../platformAccounts\";\nimport type { WalletConnectWallet } from \"../types\";\nimport { getSolanaChainIdFromCaip2, type SolanaChainId } from \"./chains\";\nimport {\n\tcreateInjectedSolanaSigner,\n\tcreateWalletConnectSolanaSigner,\n} from \"./signer\";\nimport type {\n\tSolanaAccount,\n\tSolanaInjectedWallet,\n\tSolanaWallet,\n} from \"./types\";\n\ntype StandardEventsApi = StandardEventsFeature[\"standard:events\"];\n\nconst getInjectedWalletAccounts$ = (\n\twallet: SolanaInjectedWallet,\n\tchain: SolanaChainId,\n): Observable<SolanaAccount[]> => {\n\tif (!wallet.isConnected) return of([]);\n\n\treturn getCachedObservable$(`accounts:${wallet.id}:${chain}`, () =>\n\t\tnew Observable<SolanaAccount[]>((subscriber) => {\n\t\t\tconst standardWallet = wallet.wallet;\n\n\t\t\tconst buildAccounts = (): SolanaAccount[] =>\n\t\t\t\tstandardWallet.accounts.map(\n\t\t\t\t\t(account): SolanaAccount => ({\n\t\t\t\t\t\tid: getWalletAccountId(wallet.id, account.address),\n\t\t\t\t\t\tplatform: \"solana\",\n\t\t\t\t\t\taddress: account.address,\n\t\t\t\t\t\tchains: wallet.chains,\n\t\t\t\t\t\tsigner: createInjectedSolanaSigner(standardWallet, account, chain),\n\t\t\t\t\t\tgetSigner: (c) =>\n\t\t\t\t\t\t\tcreateInjectedSolanaSigner(standardWallet, account, c),\n\t\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\tsubscriber.next(buildAccounts());\n\n\t\t\t// Re-emit when the wallet's authorized accounts change.\n\t\t\tconst eventsFeature = (\n\t\t\t\tstandardWallet.features as Record<string, unknown>\n\t\t\t)[\"standard:events\"] as StandardEventsApi | undefined;\n\t\t\tconst off = eventsFeature?.on(\"change\", () =>\n\t\t\t\tsubscriber.next(buildAccounts()),\n\t\t\t);\n\n\t\t\treturn () => {\n\t\t\t\toff?.();\n\t\t\t};\n\t\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 })),\n\t);\n};\n\nconst getWalletConnectAccounts$ = (\n\twallet: WalletConnectWallet,\n\tchain: SolanaChainId,\n): Observable<SolanaAccount[]> =>\n\tgetWalletConnectSessionAccounts$({\n\t\twallet,\n\t\tplatform: \"solana\",\n\t\tnamespace: \"solana\",\n\t\tcacheKey: `accounts:${wallet.id}:solana:${chain}`,\n\t\tbuildAccounts: (provider) => {\n\t\t\tconst session = provider.session;\n\t\t\tif (!session) return [];\n\n\t\t\tconst solanaCaip10s = getSessionCaip10s(session, \"solana\");\n\t\t\tconst addresses = getCaip10Addresses(solanaCaip10s);\n\n\t\t\t// Clusters the session actually advertises (\"solana:<chainRef>\" from\n\t\t\t// each CAIP-10 entry), mapped back to SolanaChainId. Falls back to the\n\t\t\t// configured chain when none are recognised.\n\t\t\tconst advertisedChains = [\n\t\t\t\t...new Set(\n\t\t\t\t\tsolanaCaip10s\n\t\t\t\t\t\t.map((account) => account.split(\":\").slice(0, 2).join(\":\"))\n\t\t\t\t\t\t.map(getSolanaChainIdFromCaip2)\n\t\t\t\t\t\t.filter((c): c is SolanaChainId => !!c),\n\t\t\t\t),\n\t\t\t];\n\t\t\tconst chains = advertisedChains.length ? advertisedChains : [chain];\n\n\t\t\treturn addresses.map(\n\t\t\t\t(accountAddress): SolanaAccount => ({\n\t\t\t\t\tid: getWalletAccountId(wallet.id, accountAddress),\n\t\t\t\t\tplatform: \"solana\",\n\t\t\t\t\taddress: accountAddress,\n\t\t\t\t\tchains,\n\t\t\t\t\tsigner: createWalletConnectSolanaSigner(\n\t\t\t\t\t\tprovider,\n\t\t\t\t\t\taccountAddress,\n\t\t\t\t\t\tchain,\n\t\t\t\t\t),\n\t\t\t\t\tgetSigner: (c) =>\n\t\t\t\t\t\tcreateWalletConnectSolanaSigner(provider, accountAddress, c),\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\t\t},\n\t});\n\nexport const getSolanaAccounts$ = (\n\tsolanaWallets$: Observable<(SolanaWallet | WalletConnectWallet)[]>,\n\tsolanaChain: SolanaChainId,\n) =>\n\tcreatePlatformAccounts$({\n\t\twallets$: solanaWallets$,\n\t\tgetInjectedAccounts$: (wallet) =>\n\t\t\tgetInjectedWalletAccounts$(wallet, solanaChain),\n\t\tgetWalletConnectAccounts$: (wallet) =>\n\t\t\tgetWalletConnectAccounts$(wallet, solanaChain),\n\t\t// Re-emit when the advertised clusters change, not just on id changes.\n\t\taccountChangeKey: (account) => `${account.id}|${account.chains.join(\",\")}`,\n\t});\n","import { getWallets } from \"@wallet-standard/app\";\nimport type { Wallet as WalletStandardWallet } from \"@wallet-standard/base\";\nimport type {\n\tStandardConnectFeature,\n\tStandardDisconnectFeature,\n} from \"@wallet-standard/features\";\nimport { Observable, shareReplay } from \"rxjs\";\nimport { clearCachedObservablesByPrefix } from \"../../utils/getCachedObservable\";\nimport { getWalletId } from \"../../utils/WalletId\";\nimport { KheopskitError } from \"../errors\";\nimport { createInjectedWallets$ } from \"../injectedWallets\";\nimport type { KheopskitStore } from \"../store\";\nimport { isSolanaChainId, type SolanaChainId } from \"./chains\";\nimport type { SolanaInjectedWallet } from \"./types\";\n\ntype ConnectApi = StandardConnectFeature[\"standard:connect\"];\ntype DisconnectApi = StandardDisconnectFeature[\"standard:disconnect\"];\n\nconst SOLANA_NAMESPACE_PREFIX = \"solana:\";\n\n/** A Wallet Standard wallet is Solana-capable if it advertises a solana chain or feature. */\nconst isSolanaWallet = (wallet: WalletStandardWallet): boolean =>\n\twallet.chains.some((chain) => chain.startsWith(SOLANA_NAMESPACE_PREFIX)) ||\n\tObject.keys(wallet.features).some((feature) =>\n\t\tfeature.startsWith(SOLANA_NAMESPACE_PREFIX),\n\t);\n\nconst getSolanaChains = (wallet: WalletStandardWallet): SolanaChainId[] =>\n\twallet.chains.filter((chain): chain is SolanaChainId =>\n\t\tisSolanaChainId(chain),\n\t);\n\n/**\n * Observable of Solana-capable Wallet Standard wallets, updated as wallets\n * register/unregister. Returns an empty array during SSR.\n */\nconst walletStandardWallets$ = new Observable<readonly WalletStandardWallet[]>(\n\t(subscriber) => {\n\t\t// Guard against SSR - the Wallet Standard registry 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 { get, on } = getWallets();\n\t\tconst emit = () => subscriber.next(get().filter(isSolanaWallet));\n\n\t\temit();\n\n\t\tconst offRegister = on(\"register\", emit);\n\t\tconst offUnregister = on(\"unregister\", emit);\n\n\t\treturn () => {\n\t\t\toffRegister();\n\t\t\toffUnregister();\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 getSolanaWallets$ = (store: KheopskitStore) =>\n\tcreateInjectedWallets$<WalletStandardWallet, SolanaInjectedWallet>(store, {\n\t\tsources$: walletStandardWallets$,\n\t\tgetWalletId: (wallet) => getWalletId(\"solana\", wallet.name),\n\t\tconnect: async (wallet, walletId) => {\n\t\t\tconst feature = (wallet.features as Record<string, unknown>)[\n\t\t\t\t\"standard:connect\"\n\t\t\t] as ConnectApi | undefined;\n\t\t\tif (!feature)\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"FEATURE_NOT_SUPPORTED\",\n\t\t\t\t\t`wallet ${walletId} does not support standard:connect`,\n\t\t\t\t\t{ walletId },\n\t\t\t\t);\n\n\t\t\tawait feature.connect();\n\t\t},\n\t\t// standard:disconnect is an optional feature. Await it when present so a\n\t\t// failed disconnect rejects the returned promise; if absent we still\n\t\t// clear local state.\n\t\tdisconnect: async (wallet) => {\n\t\t\tconst feature = (wallet.features as Record<string, unknown>)[\n\t\t\t\t\"standard:disconnect\"\n\t\t\t] as DisconnectApi | undefined;\n\t\t\tawait feature?.disconnect();\n\t\t},\n\t\t// Drop cached account observables for this wallet so a later reconnect\n\t\t// rebuilds them against the current wallet handle, not a stale closure.\n\t\tonDisconnected: (walletId) =>\n\t\t\tclearCachedObservablesByPrefix(`accounts:${walletId}:`),\n\t\tbuildWallet: ({\n\t\t\tsource: wallet,\n\t\t\twalletId,\n\t\t\tisConnected,\n\t\t\tconnect,\n\t\t\tdisconnect,\n\t\t}) => ({\n\t\t\tplatform: \"solana\",\n\t\t\ttype: \"injected\",\n\t\t\tid: walletId,\n\t\t\tsourceId: wallet.name,\n\t\t\twallet,\n\t\t\tchains: getSolanaChains(wallet),\n\t\t\tname: wallet.name,\n\t\t\ticon: wallet.icon,\n\t\t\tisConnected,\n\t\t\tconnect,\n\t\t\tdisconnect,\n\t\t}),\n\t});\n","import type { KheopskitPlatform, PlatformContext } from \"../types\";\nimport { getSolanaAccounts$ } from \"./accounts\";\nimport {\n\tDEFAULT_SOLANA_CHAIN,\n\tisSolanaChainId,\n\ttype SolanaChainId,\n} from \"./chains\";\nimport type { SolanaAccount, SolanaWallet } from \"./types\";\nimport { getSolanaWallets$ } from \"./wallets\";\n\nexport type SolanaPluginOptions = {\n\t/**\n\t * Solana cluster that account signers target. Each account also exposes a\n\t * `getSigner(chain)` factory for targeting another cluster.\n\t *\n\t * @default \"solana:mainnet\"\n\t */\n\tchain?: SolanaChainId;\n};\n\n/**\n * Solana platform plugin. Pass to `getKheopskit$({ platforms: [solana()] })`.\n *\n * @example\n * ```ts\n * import { solana } from \"@kheopskit/core/solana\";\n * solana({ chain: \"solana:mainnet\" });\n * ```\n */\nexport const solana = (\n\toptions: SolanaPluginOptions = {},\n): KheopskitPlatform<\"solana\", SolanaWallet, SolanaAccount> => {\n\tconst chain = options.chain ?? DEFAULT_SOLANA_CHAIN;\n\n\tif (!isSolanaChainId(chain)) {\n\t\tconsole.warn(\n\t\t\t`[kheopskit] Unknown solana chain: ${JSON.stringify(chain)}. Valid values: \"solana:mainnet\", \"solana:devnet\", \"solana:testnet\", \"solana:localnet\".`,\n\t\t);\n\t}\n\n\treturn {\n\t\tplatform: \"solana\",\n\t\tgetWallets$: (ctx: PlatformContext) => getSolanaWallets$(ctx.store),\n\t\tgetAccounts$: (wallets$) => getSolanaAccounts$(wallets$, chain),\n\t};\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"solana.js","names":["KheopskitError","KheopskitError","address","getTransactionEncoder","getTransactionDecoder","getBase58Decoder","getBase58Encoder","getBase64Decoder","getBase64Encoder","of","getCachedObservable$","Observable","getWalletAccountId","shareReplay","getWalletConnectSessionAccounts$","getSessionCaip10s","getCaip10Addresses","createPlatformAccounts$","Observable","getWallets","shareReplay","createInjectedWallets$","getWalletId","KheopskitError","clearCachedObservablesByPrefix"],"sources":["../src/api/solana/chains.ts","../src/api/solana/signer.ts","../src/api/solana/accounts.ts","../src/api/solana/wallets.ts","../src/api/solana/plugin.ts"],"sourcesContent":["import { KheopskitError } from \"../errors\";\n\n/**\n * Wallet Standard chain identifiers for Solana clusters.\n *\n * These are the values wallets advertise in their `chains` arrays and the\n * values kheopskit accepts in `solana({ chain })`.\n *\n * @see https://github.com/anza-xyz/wallet-standard\n */\nexport type SolanaChainId =\n\t| \"solana:mainnet\"\n\t| \"solana:devnet\"\n\t| \"solana:testnet\"\n\t| \"solana:localnet\";\n\nexport const DEFAULT_SOLANA_CHAIN: SolanaChainId = \"solana:mainnet\";\n\nconst SOLANA_CHAIN_IDS = [\n\t\"solana:mainnet\",\n\t\"solana:devnet\",\n\t\"solana:testnet\",\n\t\"solana:localnet\",\n] as const satisfies SolanaChainId[];\n\nexport const isSolanaChainId = (value: unknown): value is SolanaChainId =>\n\ttypeof value === \"string\" &&\n\t(SOLANA_CHAIN_IDS as readonly string[]).includes(value);\n\n/**\n * Maps Wallet Standard chain ids to the CAIP-2 chain ids used by WalletConnect.\n *\n * CAIP-2 ids use the first 32 characters of the cluster's genesis hash as the\n * reference. The values below match `@reown/appkit/networks` (solana,\n * solanaDevnet, solanaTestnet), which is what AppKit puts in session namespaces.\n *\n * `localnet` has no canonical CAIP-2 id and cannot be used over WalletConnect.\n */\nconst SOLANA_CHAIN_TO_CAIP2 = {\n\t\"solana:mainnet\": \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\",\n\t\"solana:devnet\": \"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1\",\n\t\"solana:testnet\": \"solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z\",\n} as const satisfies Partial<Record<SolanaChainId, string>>;\n\n/**\n * Returns the CAIP-2 chain id for a Solana chain, for use in WalletConnect\n * requests and when reading WalletConnect session namespaces.\n *\n * @throws if the chain has no canonical CAIP-2 id (e.g. localnet)\n */\nexport const getSolanaCaip2 = (chain: SolanaChainId): string => {\n\tconst caip2 = (SOLANA_CHAIN_TO_CAIP2 as Record<string, string | undefined>)[\n\t\tchain\n\t];\n\tif (!caip2)\n\t\tthrow new KheopskitError(\n\t\t\t\"UNSUPPORTED_CHAIN\",\n\t\t\t`Solana chain \"${chain}\" cannot be used over WalletConnect (no CAIP-2 id).`,\n\t\t);\n\treturn caip2;\n};\n\n/**\n * AppKit's *deprecated* CAIP-2 cluster ids (its `deprecatedCaipNetworkId`\n * values). Some wallets still place accounts in the WC session under these, so\n * map them back to a {@link SolanaChainId} instead of silently falling back to\n * the configured chain. Requests always use the current ids from\n * {@link SOLANA_CHAIN_TO_CAIP2}; testnet has no deprecated id.\n */\nconst DEPRECATED_CAIP2_TO_SOLANA_CHAIN: Record<string, SolanaChainId> = {\n\t\"solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ\": \"solana:mainnet\",\n\t\"solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K\": \"solana:devnet\",\n};\n\nconst CAIP2_TO_SOLANA_CHAIN: Record<string, SolanaChainId> = {\n\t...Object.fromEntries(\n\t\tObject.entries(SOLANA_CHAIN_TO_CAIP2).map(([chain, caip2]) => [\n\t\t\tcaip2,\n\t\t\tchain as SolanaChainId,\n\t\t]),\n\t),\n\t...DEPRECATED_CAIP2_TO_SOLANA_CHAIN,\n};\n\n/**\n * Maps a CAIP-2 chain id (as found in WalletConnect session namespaces) back to\n * its {@link SolanaChainId}, or `undefined` if it isn't a recognised cluster.\n */\nexport const getSolanaChainIdFromCaip2 = (\n\tcaip2: string,\n): SolanaChainId | undefined => CAIP2_TO_SOLANA_CHAIN[caip2];\n","import {\n\taddress,\n\tgetBase58Decoder,\n\tgetBase58Encoder,\n\tgetBase64Decoder,\n\tgetBase64Encoder,\n\tgetTransactionDecoder,\n\tgetTransactionEncoder,\n\ttype SignableMessage,\n\ttype SignatureBytes,\n\ttype TransactionModifyingSigner,\n} from \"@solana/kit\";\nimport type {\n\tSolanaSignAndSendTransactionFeature,\n\tSolanaSignMessageFeature,\n\tSolanaSignTransactionFeature,\n} from \"@solana/wallet-standard-features\";\nimport type {\n\tWalletAccount,\n\tWallet as WalletStandardWallet,\n} from \"@wallet-standard/base\";\nimport { KheopskitError } from \"../errors\";\nimport type { WalletConnectProvider } from \"../types\";\nimport { getSolanaCaip2, type SolanaChainId } from \"./chains\";\nimport type { SolanaSigner } from \"./types\";\n\nconst SOLANA_SIGN_MESSAGE = \"solana:signMessage\";\nconst SOLANA_SIGN_TRANSACTION = \"solana:signTransaction\";\nconst SOLANA_SIGN_AND_SEND_TRANSACTION = \"solana:signAndSendTransaction\";\n\ntype SignMessageApi = SolanaSignMessageFeature[typeof SOLANA_SIGN_MESSAGE];\ntype SignTransactionApi =\n\tSolanaSignTransactionFeature[typeof SOLANA_SIGN_TRANSACTION];\ntype SignAndSendApi =\n\tSolanaSignAndSendTransactionFeature[typeof SOLANA_SIGN_AND_SEND_TRANSACTION];\n\n/** The branded array type expected back from a transaction-modifying signer. */\ntype SignedTransactions = Awaited<\n\tReturnType<TransactionModifyingSigner[\"modifyAndSignTransactions\"]>\n>;\n\nconst requireFeature = <T>(wallet: WalletStandardWallet, name: string): T => {\n\tconst feature = (wallet.features as Record<string, unknown>)[name];\n\tif (!feature)\n\t\tthrow new KheopskitError(\n\t\t\t\"FEATURE_NOT_SUPPORTED\",\n\t\t\t`wallet \"${wallet.name}\" does not support ${name}`,\n\t\t);\n\treturn feature as T;\n};\n\n/**\n * Builds a {@link SolanaSigner} backed by a Wallet Standard wallet's\n * `solana:*` features (injected wallets).\n *\n * Transactions are exchanged as wire bytes; messages and signatures as raw\n * bytes. Calling a method whose feature the wallet does not advertise throws.\n */\nexport const createInjectedSolanaSigner = (\n\twallet: WalletStandardWallet,\n\taccount: WalletAccount,\n\tchain: SolanaChainId,\n): SolanaSigner => {\n\tconst signerAddress = address(account.address);\n\n\treturn {\n\t\taddress: signerAddress,\n\t\tmodifyAndSignMessages: async (messages) => {\n\t\t\tconst feature = requireFeature<SignMessageApi>(\n\t\t\t\twallet,\n\t\t\t\tSOLANA_SIGN_MESSAGE,\n\t\t\t);\n\t\t\tconst outputs = await feature.signMessage(\n\t\t\t\t...messages.map((m) => ({ account, message: m.content })),\n\t\t\t);\n\t\t\treturn messages.map((m, i) => {\n\t\t\t\tconst output = outputs[i];\n\t\t\t\tif (!output) throw new Error(\"[kheopskit] missing signMessage output\");\n\t\t\t\treturn {\n\t\t\t\t\tcontent: output.signedMessage,\n\t\t\t\t\tsignatures: {\n\t\t\t\t\t\t...m.signatures,\n\t\t\t\t\t\t[signerAddress]: output.signature as SignatureBytes,\n\t\t\t\t\t},\n\t\t\t\t} satisfies SignableMessage;\n\t\t\t});\n\t\t},\n\t\tmodifyAndSignTransactions: async (transactions) => {\n\t\t\tconst feature = requireFeature<SignTransactionApi>(\n\t\t\t\twallet,\n\t\t\t\tSOLANA_SIGN_TRANSACTION,\n\t\t\t);\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst decoder = getTransactionDecoder();\n\t\t\tconst outputs = await feature.signTransaction(\n\t\t\t\t...transactions.map((tx) => ({\n\t\t\t\t\taccount,\n\t\t\t\t\ttransaction: new Uint8Array(encoder.encode(tx)),\n\t\t\t\t\tchain,\n\t\t\t\t})),\n\t\t\t);\n\t\t\treturn transactions.map((_tx, i) => {\n\t\t\t\tconst output = outputs[i];\n\t\t\t\tif (!output)\n\t\t\t\t\tthrow new Error(\"[kheopskit] missing signTransaction output\");\n\t\t\t\treturn decoder.decode(output.signedTransaction);\n\t\t\t}) as unknown as SignedTransactions;\n\t\t},\n\t\tsignAndSendTransactions: async (transactions) => {\n\t\t\tconst feature = requireFeature<SignAndSendApi>(\n\t\t\t\twallet,\n\t\t\t\tSOLANA_SIGN_AND_SEND_TRANSACTION,\n\t\t\t);\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst outputs = await feature.signAndSendTransaction(\n\t\t\t\t...transactions.map((tx) => ({\n\t\t\t\t\taccount,\n\t\t\t\t\ttransaction: new Uint8Array(encoder.encode(tx)),\n\t\t\t\t\tchain,\n\t\t\t\t})),\n\t\t\t);\n\t\t\treturn outputs.map((output) => output.signature as SignatureBytes);\n\t\t},\n\t};\n};\n\n/**\n * Builds a {@link SolanaSigner} backed by a WalletConnect session, adapting the\n * `solana_*` RPC methods to the same interface as the injected signer.\n *\n * The CAIP-2 chain id is derived from {@link SolanaChainId}; transactions are\n * base64-encoded and messages/signatures base58-encoded, per the WalletConnect\n * Solana spec.\n */\nexport const createWalletConnectSolanaSigner = (\n\tprovider: WalletConnectProvider,\n\taccountAddress: string,\n\tchain: SolanaChainId,\n): SolanaSigner => {\n\tconst signerAddress = address(accountAddress);\n\n\tconst request = <T>(method: string, params: unknown): Promise<T> => {\n\t\tif (!provider.session)\n\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\t\t// Resolved lazily (not at signer construction) so building a signer for a\n\t\t// cluster without a CAIP-2 id (e.g. localnet) doesn't throw until a request\n\t\t// is actually attempted.\n\t\treturn provider.client.request<T>({\n\t\t\ttopic: provider.session.topic,\n\t\t\tchainId: getSolanaCaip2(chain),\n\t\t\trequest: { method, params },\n\t\t});\n\t};\n\n\treturn {\n\t\taddress: signerAddress,\n\t\tmodifyAndSignMessages: async (messages) => {\n\t\t\t// @solana/kit naming is the inverse of the value direction here: a\n\t\t\t// Decoder turns bytes -> string (so `toBase58` produces a base58 string),\n\t\t\t// an Encoder turns string -> bytes (so `fromBase58` parses one).\n\t\t\tconst toBase58 = getBase58Decoder();\n\t\t\tconst fromBase58 = getBase58Encoder();\n\t\t\treturn Promise.all(\n\t\t\t\tmessages.map(async (m) => {\n\t\t\t\t\tconst { signature } = await request<{ signature: string }>(\n\t\t\t\t\t\t\"solana_signMessage\",\n\t\t\t\t\t\t{ pubkey: accountAddress, message: toBase58.decode(m.content) },\n\t\t\t\t\t);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: m.content,\n\t\t\t\t\t\tsignatures: {\n\t\t\t\t\t\t\t...m.signatures,\n\t\t\t\t\t\t\t[signerAddress]: fromBase58.encode(signature) as SignatureBytes,\n\t\t\t\t\t\t},\n\t\t\t\t\t} satisfies SignableMessage;\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t\tmodifyAndSignTransactions: async (transactions) => {\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst decoder = getTransactionDecoder();\n\t\t\tconst toBase64 = getBase64Decoder();\n\t\t\tconst fromBase64 = getBase64Encoder();\n\t\t\tconst fromBase58 = getBase58Encoder();\n\t\t\tconst signed = await Promise.all(\n\t\t\t\ttransactions.map(async (tx) => {\n\t\t\t\t\tconst result = await request<{\n\t\t\t\t\t\ttransaction?: string;\n\t\t\t\t\t\tsignature?: string;\n\t\t\t\t\t}>(\"solana_signTransaction\", {\n\t\t\t\t\t\ttransaction: toBase64.decode(encoder.encode(tx)),\n\t\t\t\t\t});\n\t\t\t\t\t// Wallets may return either the full signed transaction (base64)\n\t\t\t\t\t// or just the signature (base58) to merge into the original.\n\t\t\t\t\tif (result.transaction)\n\t\t\t\t\t\treturn decoder.decode(fromBase64.encode(result.transaction));\n\t\t\t\t\tif (result.signature)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...tx,\n\t\t\t\t\t\t\tsignatures: {\n\t\t\t\t\t\t\t\t...tx.signatures,\n\t\t\t\t\t\t\t\t[signerAddress]: fromBase58.encode(\n\t\t\t\t\t\t\t\t\tresult.signature,\n\t\t\t\t\t\t\t\t) as SignatureBytes,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"[kheopskit] solana_signTransaction returned no transaction or signature\",\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn signed as unknown as SignedTransactions;\n\t\t},\n\t\tsignAndSendTransactions: async (transactions) => {\n\t\t\tconst encoder = getTransactionEncoder();\n\t\t\tconst toBase64 = getBase64Decoder();\n\t\t\tconst fromBase58 = getBase58Encoder();\n\t\t\treturn Promise.all(\n\t\t\t\ttransactions.map(async (tx) => {\n\t\t\t\t\tconst { signature } = await request<{ signature: string }>(\n\t\t\t\t\t\t\"solana_signAndSendTransaction\",\n\t\t\t\t\t\t{ transaction: toBase64.decode(encoder.encode(tx)) },\n\t\t\t\t\t);\n\t\t\t\t\treturn fromBase58.encode(signature) as SignatureBytes;\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t};\n};\n","import type { StandardEventsFeature } from \"@wallet-standard/features\";\nimport { Observable, of, shareReplay } from \"rxjs\";\nimport { getWalletAccountId } from \"../../utils\";\nimport { getCachedObservable$ } from \"../../utils/getCachedObservable\";\nimport {\n\tcreatePlatformAccounts$,\n\tgetCaip10Addresses,\n\tgetSessionCaip10s,\n\tgetWalletConnectSessionAccounts$,\n} from \"../platformAccounts\";\nimport type { WalletConnectWallet } from \"../types\";\nimport { getSolanaChainIdFromCaip2, type SolanaChainId } from \"./chains\";\nimport {\n\tcreateInjectedSolanaSigner,\n\tcreateWalletConnectSolanaSigner,\n} from \"./signer\";\nimport type {\n\tSolanaAccount,\n\tSolanaInjectedWallet,\n\tSolanaWallet,\n} from \"./types\";\n\ntype StandardEventsApi = StandardEventsFeature[\"standard:events\"];\n\nconst getInjectedWalletAccounts$ = (\n\twallet: SolanaInjectedWallet,\n\tchain: SolanaChainId,\n): Observable<SolanaAccount[]> => {\n\tif (!wallet.isConnected) return of([]);\n\n\treturn getCachedObservable$(`accounts:${wallet.id}:${chain}`, () =>\n\t\tnew Observable<SolanaAccount[]>((subscriber) => {\n\t\t\tconst standardWallet = wallet.wallet;\n\n\t\t\tconst buildAccounts = (): SolanaAccount[] =>\n\t\t\t\tstandardWallet.accounts.map(\n\t\t\t\t\t(account): SolanaAccount => ({\n\t\t\t\t\t\tid: getWalletAccountId(wallet.id, account.address),\n\t\t\t\t\t\tplatform: \"solana\",\n\t\t\t\t\t\taddress: account.address,\n\t\t\t\t\t\tchains: wallet.chains,\n\t\t\t\t\t\tsigner: createInjectedSolanaSigner(standardWallet, account, chain),\n\t\t\t\t\t\tgetSigner: (c) =>\n\t\t\t\t\t\t\tcreateInjectedSolanaSigner(standardWallet, account, c),\n\t\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\tsubscriber.next(buildAccounts());\n\n\t\t\t// Re-emit when the wallet's authorized accounts change.\n\t\t\tconst eventsFeature = (\n\t\t\t\tstandardWallet.features as Record<string, unknown>\n\t\t\t)[\"standard:events\"] as StandardEventsApi | undefined;\n\t\t\tconst off = eventsFeature?.on(\"change\", () =>\n\t\t\t\tsubscriber.next(buildAccounts()),\n\t\t\t);\n\n\t\t\treturn () => {\n\t\t\t\toff?.();\n\t\t\t};\n\t\t}).pipe(shareReplay({ refCount: true, bufferSize: 1 })),\n\t);\n};\n\nconst getWalletConnectAccounts$ = (\n\twallet: WalletConnectWallet,\n\tchain: SolanaChainId,\n): Observable<SolanaAccount[]> =>\n\tgetWalletConnectSessionAccounts$({\n\t\twallet,\n\t\tplatform: \"solana\",\n\t\tnamespace: \"solana\",\n\t\tcacheKey: `accounts:${wallet.id}:solana:${chain}`,\n\t\tbuildAccounts: (provider) => {\n\t\t\tconst session = provider.session;\n\t\t\tif (!session) return [];\n\n\t\t\tconst solanaCaip10s = getSessionCaip10s(session, \"solana\");\n\t\t\tconst addresses = getCaip10Addresses(solanaCaip10s);\n\n\t\t\t// Clusters the session actually advertises (\"solana:<chainRef>\" from\n\t\t\t// each CAIP-10 entry), mapped back to SolanaChainId. Falls back to the\n\t\t\t// configured chain when none are recognised.\n\t\t\tconst advertisedChains = [\n\t\t\t\t...new Set(\n\t\t\t\t\tsolanaCaip10s\n\t\t\t\t\t\t.map((account) => account.split(\":\").slice(0, 2).join(\":\"))\n\t\t\t\t\t\t.map(getSolanaChainIdFromCaip2)\n\t\t\t\t\t\t.filter((c): c is SolanaChainId => !!c),\n\t\t\t\t),\n\t\t\t];\n\t\t\tconst chains = advertisedChains.length ? advertisedChains : [chain];\n\n\t\t\treturn addresses.map(\n\t\t\t\t(accountAddress): SolanaAccount => ({\n\t\t\t\t\tid: getWalletAccountId(wallet.id, accountAddress),\n\t\t\t\t\tplatform: \"solana\",\n\t\t\t\t\taddress: accountAddress,\n\t\t\t\t\tchains,\n\t\t\t\t\tsigner: createWalletConnectSolanaSigner(\n\t\t\t\t\t\tprovider,\n\t\t\t\t\t\taccountAddress,\n\t\t\t\t\t\tchain,\n\t\t\t\t\t),\n\t\t\t\t\tgetSigner: (c) =>\n\t\t\t\t\t\tcreateWalletConnectSolanaSigner(provider, accountAddress, c),\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\t\t},\n\t});\n\nexport const getSolanaAccounts$ = (\n\tsolanaWallets$: Observable<(SolanaWallet | WalletConnectWallet)[]>,\n\tsolanaChain: SolanaChainId,\n) =>\n\tcreatePlatformAccounts$({\n\t\twallets$: solanaWallets$,\n\t\tgetInjectedAccounts$: (wallet) =>\n\t\t\tgetInjectedWalletAccounts$(wallet, solanaChain),\n\t\tgetWalletConnectAccounts$: (wallet) =>\n\t\t\tgetWalletConnectAccounts$(wallet, solanaChain),\n\t\t// Re-emit when the advertised clusters change, not just on id changes.\n\t\taccountChangeKey: (account) => `${account.id}|${account.chains.join(\",\")}`,\n\t});\n","import { getWallets } from \"@wallet-standard/app\";\nimport type { Wallet as WalletStandardWallet } from \"@wallet-standard/base\";\nimport type {\n\tStandardConnectFeature,\n\tStandardDisconnectFeature,\n} from \"@wallet-standard/features\";\nimport { Observable, shareReplay } from \"rxjs\";\nimport { clearCachedObservablesByPrefix } from \"../../utils/getCachedObservable\";\nimport { getWalletId } from \"../../utils/WalletId\";\nimport { KheopskitError } from \"../errors\";\nimport { createInjectedWallets$ } from \"../injectedWallets\";\nimport type { KheopskitStore } from \"../store\";\nimport { isSolanaChainId, type SolanaChainId } from \"./chains\";\nimport type { SolanaInjectedWallet } from \"./types\";\n\ntype ConnectApi = StandardConnectFeature[\"standard:connect\"];\ntype DisconnectApi = StandardDisconnectFeature[\"standard:disconnect\"];\n\nconst SOLANA_NAMESPACE_PREFIX = \"solana:\";\n\n/** A Wallet Standard wallet is Solana-capable if it advertises a solana chain or feature. */\nconst isSolanaWallet = (wallet: WalletStandardWallet): boolean =>\n\twallet.chains.some((chain) => chain.startsWith(SOLANA_NAMESPACE_PREFIX)) ||\n\tObject.keys(wallet.features).some((feature) =>\n\t\tfeature.startsWith(SOLANA_NAMESPACE_PREFIX),\n\t);\n\nconst getSolanaChains = (wallet: WalletStandardWallet): SolanaChainId[] =>\n\twallet.chains.filter((chain): chain is SolanaChainId =>\n\t\tisSolanaChainId(chain),\n\t);\n\n/**\n * Observable of Solana-capable Wallet Standard wallets, updated as wallets\n * register/unregister. Returns an empty array during SSR.\n */\nconst walletStandardWallets$ = new Observable<readonly WalletStandardWallet[]>(\n\t(subscriber) => {\n\t\t// Guard against SSR - the Wallet Standard registry 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 { get, on } = getWallets();\n\t\tconst emit = () => subscriber.next(get().filter(isSolanaWallet));\n\n\t\temit();\n\n\t\tconst offRegister = on(\"register\", emit);\n\t\tconst offUnregister = on(\"unregister\", emit);\n\n\t\treturn () => {\n\t\t\toffRegister();\n\t\t\toffUnregister();\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 getSolanaWallets$ = (store: KheopskitStore) =>\n\tcreateInjectedWallets$<WalletStandardWallet, SolanaInjectedWallet>(store, {\n\t\tsources$: walletStandardWallets$,\n\t\tgetWalletId: (wallet) => getWalletId(\"solana\", wallet.name),\n\t\tconnect: async (wallet, walletId) => {\n\t\t\tconst feature = (wallet.features as Record<string, unknown>)[\n\t\t\t\t\"standard:connect\"\n\t\t\t] as ConnectApi | undefined;\n\t\t\tif (!feature)\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"FEATURE_NOT_SUPPORTED\",\n\t\t\t\t\t`wallet ${walletId} does not support standard:connect`,\n\t\t\t\t\t{ walletId },\n\t\t\t\t);\n\n\t\t\tawait feature.connect();\n\t\t},\n\t\t// standard:disconnect is an optional feature. Await it when present so a\n\t\t// failed disconnect rejects the returned promise; if absent we still\n\t\t// clear local state.\n\t\tdisconnect: async (wallet) => {\n\t\t\tconst feature = (wallet.features as Record<string, unknown>)[\n\t\t\t\t\"standard:disconnect\"\n\t\t\t] as DisconnectApi | undefined;\n\t\t\tawait feature?.disconnect();\n\t\t},\n\t\t// Drop cached account observables for this wallet so a later reconnect\n\t\t// rebuilds them against the current wallet handle, not a stale closure.\n\t\tonDisconnected: (walletId) =>\n\t\t\tclearCachedObservablesByPrefix(`accounts:${walletId}:`),\n\t\tbuildWallet: ({\n\t\t\tsource: wallet,\n\t\t\twalletId,\n\t\t\tisConnected,\n\t\t\tconnect,\n\t\t\tdisconnect,\n\t\t}) => ({\n\t\t\tplatform: \"solana\",\n\t\t\ttype: \"injected\",\n\t\t\tid: walletId,\n\t\t\tsourceId: wallet.name,\n\t\t\twallet,\n\t\t\tchains: getSolanaChains(wallet),\n\t\t\tname: wallet.name,\n\t\t\ticon: wallet.icon,\n\t\t\tisConnected,\n\t\t\tconnect,\n\t\t\tdisconnect,\n\t\t}),\n\t});\n","import type { KheopskitPlatform, PlatformContext } from \"../types\";\nimport { getSolanaAccounts$ } from \"./accounts\";\nimport {\n\tDEFAULT_SOLANA_CHAIN,\n\tisSolanaChainId,\n\ttype SolanaChainId,\n} from \"./chains\";\nimport type { SolanaAccount, SolanaWallet } from \"./types\";\nimport { getSolanaWallets$ } from \"./wallets\";\n\nexport type SolanaPluginOptions = {\n\t/**\n\t * Solana cluster that account signers target. Each account also exposes a\n\t * `getSigner(chain)` factory for targeting another cluster.\n\t *\n\t * @default \"solana:mainnet\"\n\t */\n\tchain?: SolanaChainId;\n};\n\n/**\n * Solana platform plugin. Pass to `getKheopskit$({ platforms: [solana()] })`.\n *\n * @example\n * ```ts\n * import { solana } from \"@kheopskit/core/solana\";\n * solana({ chain: \"solana:mainnet\" });\n * ```\n */\nexport const solana = (\n\toptions: SolanaPluginOptions = {},\n): KheopskitPlatform<\"solana\", SolanaWallet, SolanaAccount> => {\n\tconst chain = options.chain ?? DEFAULT_SOLANA_CHAIN;\n\n\tif (!isSolanaChainId(chain)) {\n\t\tconsole.warn(\n\t\t\t`[kheopskit] Unknown solana chain: ${JSON.stringify(chain)}. Valid values: \"solana:mainnet\", \"solana:devnet\", \"solana:testnet\", \"solana:localnet\".`,\n\t\t);\n\t}\n\n\treturn {\n\t\tplatform: \"solana\",\n\t\tgetWallets$: (ctx: PlatformContext) => getSolanaWallets$(ctx.store),\n\t\tgetAccounts$: (wallets$) => getSolanaAccounts$(wallets$, chain),\n\t};\n};\n"],"mappings":"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"}
|
package/dist/solana.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { d as getCachedObservable$, i as getWalletId, n as isWalletConnectWallet, t as isInjectedWallet, u as clearCachedObservablesByPrefix } from "./types-jnifAAA0.mjs";
|
|
2
|
-
import { n as getWalletAccountId, o as isSolanaAddress, t as KheopskitError } from "./errors-
|
|
3
|
-
import { a as getWalletConnectSessionAccounts$, i as getSessionCaip10s, n as createPlatformAccounts$, r as getCaip10Addresses, t as createInjectedWallets$ } from "./injectedWallets-
|
|
2
|
+
import { n as getWalletAccountId, o as isSolanaAddress, t as KheopskitError } from "./errors-BLFP1dQI.mjs";
|
|
3
|
+
import { a as getWalletConnectSessionAccounts$, i as getSessionCaip10s, n as createPlatformAccounts$, r as getCaip10Addresses, t as createInjectedWallets$ } from "./injectedWallets-Uz4hPuoW.mjs";
|
|
4
4
|
import { Observable, of, shareReplay } from "rxjs";
|
|
5
5
|
import { address, getBase58Decoder, getBase58Encoder, getBase64Decoder, getBase64Encoder, getTransactionDecoder, getTransactionEncoder } from "@solana/kit";
|
|
6
6
|
import { getWallets } from "@wallet-standard/app";
|
|
@@ -222,6 +222,14 @@ type KheopskitConfig<P extends readonly KheopskitPlatform[] = readonly Kheopskit
|
|
|
222
222
|
*/
|
|
223
223
|
platforms: P;
|
|
224
224
|
walletConnect?: WalletConnectConfig;
|
|
225
|
+
/**
|
|
226
|
+
* Dapp name sent to Polkadot injected extensions on connect. Some
|
|
227
|
+
* extensions (e.g. polkadot.js) warn about a suspicious origin when it's
|
|
228
|
+
* empty.
|
|
229
|
+
*
|
|
230
|
+
* @default walletConnect.metadata.name, then window.location.hostname
|
|
231
|
+
*/
|
|
232
|
+
appName?: string;
|
|
225
233
|
debug: boolean;
|
|
226
234
|
/**
|
|
227
235
|
* Custom storage key for persisting wallet connection state.
|
|
@@ -327,4 +335,4 @@ type CachedAccount = {
|
|
|
327
335
|
};
|
|
328
336
|
//#endregion
|
|
329
337
|
export { WalletId as C, WalletAccountId as D, parseWalletId as E, getWalletAccountId as O, isWalletConnectWallet as S, isValidWalletId as T, WalletConnectWallet as _, CachedAccount as a, WalletType as b, KheopskitPlatform as c, KheopskitStoreData as d, PlatformContext as f, WalletConnectProvider as g, WalletConnectMetadata as h, BaseWalletAccount as i, parseWalletAccountId as k, KheopskitState as l, WalletConnectConfig as m, AppKitInstance as n, CachedWallet as o, PolkadotAccountType as p, BaseWallet as r, KheopskitConfig as s, AccountOf as t, KheopskitStore as u, WalletOf as v, getWalletId as w, isInjectedWallet as x, WalletPlatform as y };
|
|
330
|
-
//# sourceMappingURL=types-
|
|
338
|
+
//# sourceMappingURL=types-AxUDtkR-.d.mts.map
|
|
@@ -222,6 +222,14 @@ type KheopskitConfig<P extends readonly KheopskitPlatform[] = readonly Kheopskit
|
|
|
222
222
|
*/
|
|
223
223
|
platforms: P;
|
|
224
224
|
walletConnect?: WalletConnectConfig;
|
|
225
|
+
/**
|
|
226
|
+
* Dapp name sent to Polkadot injected extensions on connect. Some
|
|
227
|
+
* extensions (e.g. polkadot.js) warn about a suspicious origin when it's
|
|
228
|
+
* empty.
|
|
229
|
+
*
|
|
230
|
+
* @default walletConnect.metadata.name, then window.location.hostname
|
|
231
|
+
*/
|
|
232
|
+
appName?: string;
|
|
225
233
|
debug: boolean;
|
|
226
234
|
/**
|
|
227
235
|
* Custom storage key for persisting wallet connection state.
|
|
@@ -327,4 +335,4 @@ type CachedAccount = {
|
|
|
327
335
|
};
|
|
328
336
|
//#endregion
|
|
329
337
|
export { WalletId as C, WalletAccountId as D, parseWalletId as E, getWalletAccountId as O, isWalletConnectWallet as S, isValidWalletId as T, WalletConnectWallet as _, CachedAccount as a, WalletType as b, KheopskitPlatform as c, KheopskitStoreData as d, PlatformContext as f, WalletConnectProvider as g, WalletConnectMetadata as h, BaseWalletAccount as i, parseWalletAccountId as k, KheopskitState as l, WalletConnectConfig as m, AppKitInstance as n, CachedWallet as o, PolkadotAccountType as p, BaseWallet as r, KheopskitConfig as s, AccountOf as t, KheopskitStore as u, WalletOf as v, getWalletId as w, isInjectedWallet as x, WalletPlatform as y };
|
|
330
|
-
//# sourceMappingURL=types-
|
|
338
|
+
//# sourceMappingURL=types-AxUDtkR-.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types-DKU-SNio.js","names":[],"sources":["../src/utils/getCachedObservable.ts","../src/utils/isWalletPlatform.ts","../src/utils/WalletId.ts","../src/api/types.ts"],"sourcesContent":["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 { 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\";\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":";AAIA,MAAM,eAAe,OAAO,IAAI,2BAA2B;AAE3D,MAAM,iBAAmD;CACxD,MAAM,IAAI;CAIV,IAAI,QAAQ,EAAE;CACd,IAAI,CAAC,OAAO;EACX,wBAAQ,IAAI,IAAI;EAChB,EAAE,gBAAgB;CACnB;CACA,OAAO;AACR;AAEA,MAAa,wBACZ,KACA,WACS;CACT,MAAM,QAAQ,SAAS;CACvB,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,KAAK,OAAO,CAAwB;CAEnE,OAAO,MAAM,IAAI,GAAG;AACrB;;;;;AAMA,MAAa,yBAAyB,QAAsB;CAC3D,SAAS,CAAC,CAAC,OAAO,GAAG;AACtB;;;;;;;;AASA,MAAa,kCAAkC,WAAyB;CACvE,MAAM,QAAQ,SAAS;CACvB,KAAK,MAAM,OAAO,MAAM,KAAK,GAC5B,IAAI,IAAI,WAAW,MAAM,GAAG,MAAM,OAAO,GAAG;AAE9C;;;;;AAMA,MAAa,kCAAwC;CACpD,SAAS,CAAC,CAAC,MAAM;AAClB;;;ACvDA,MAAa,oBACZ,aAEA,OAAO,aAAa,YACpB;CAAC;CAAY;CAAY;AAAQ,CAAC,CAAC,SAAS,QAA0B;;;;;;;;ACIvE,MAAa,2BAAqC;AAElD,MAAa,eACZ,UACA,eACc;CACd,IAAI,CAAC,iBAAiB,QAAQ,GAAG,MAAM,IAAI,MAAM,kBAAkB;CACnE,IAAI,CAAC,YAAY,MAAM,IAAI,MAAM,cAAc;CAC/C,OAAO,GAAG,SAAS,GAAG;AACvB;AAEA,MAAa,iBAAiB,aAAqB;CAClD,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,kBAAkB;CACjD,MAAM,CAAC,UAAU,cAAc,SAAS,MAAM,GAAG;CACjD,IAAI,CAAC,iBAAiB,QAAQ,GAAG,MAAM,IAAI,MAAM,kBAAkB;CACnE,IAAI,CAAC,YAAY,MAAM,IAAI,MAAM,iBAAiB;CAClD,OAAO;EAAE;EAAU;CAAW;AAC/B;;;;;AAMA,MAAa,mBAAmB,aAA4C;CAC3E,IAAI,OAAO,aAAa,YAAY,CAAC,UAAU,OAAO;CACtD,IAAI,aAAA,iBAAuC,OAAO;CAClD,MAAM,CAAC,UAAU,cAAc,SAAS,MAAM,GAAG;CACjD,OAAO,iBAAiB,QAAQ,KAAK,CAAC,CAAC;AACxC;;;;AC4EA,MAAa,yBACZ,WACmC,OAAO,SAAS;;;;;;;;;;;;;;;AAgBpD,MAAa,oBACZ,WAC+C,OAAO,SAAS"}
|
|
1
|
+
{"version":3,"file":"types-DKU-SNio.js","names":[],"sources":["../src/utils/getCachedObservable.ts","../src/utils/isWalletPlatform.ts","../src/utils/WalletId.ts","../src/api/types.ts"],"sourcesContent":["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 { 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\";\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\t/**\n\t * Dapp name sent to Polkadot injected extensions on connect. Some\n\t * extensions (e.g. polkadot.js) warn about a suspicious origin when it's\n\t * empty.\n\t *\n\t * @default walletConnect.metadata.name, then window.location.hostname\n\t */\n\tappName?: string;\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":";AAIA,MAAM,eAAe,OAAO,IAAI,2BAA2B;AAE3D,MAAM,iBAAmD;CACxD,MAAM,IAAI;CAIV,IAAI,QAAQ,EAAE;CACd,IAAI,CAAC,OAAO;EACX,wBAAQ,IAAI,IAAI;EAChB,EAAE,gBAAgB;CACnB;CACA,OAAO;AACR;AAEA,MAAa,wBACZ,KACA,WACS;CACT,MAAM,QAAQ,SAAS;CACvB,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,KAAK,OAAO,CAAwB;CAEnE,OAAO,MAAM,IAAI,GAAG;AACrB;;;;;AAMA,MAAa,yBAAyB,QAAsB;CAC3D,SAAS,CAAC,CAAC,OAAO,GAAG;AACtB;;;;;;;;AASA,MAAa,kCAAkC,WAAyB;CACvE,MAAM,QAAQ,SAAS;CACvB,KAAK,MAAM,OAAO,MAAM,KAAK,GAC5B,IAAI,IAAI,WAAW,MAAM,GAAG,MAAM,OAAO,GAAG;AAE9C;;;;;AAMA,MAAa,kCAAwC;CACpD,SAAS,CAAC,CAAC,MAAM;AAClB;;;ACvDA,MAAa,oBACZ,aAEA,OAAO,aAAa,YACpB;CAAC;CAAY;CAAY;AAAQ,CAAC,CAAC,SAAS,QAA0B;;;;;;;;ACIvE,MAAa,2BAAqC;AAElD,MAAa,eACZ,UACA,eACc;CACd,IAAI,CAAC,iBAAiB,QAAQ,GAAG,MAAM,IAAI,MAAM,kBAAkB;CACnE,IAAI,CAAC,YAAY,MAAM,IAAI,MAAM,cAAc;CAC/C,OAAO,GAAG,SAAS,GAAG;AACvB;AAEA,MAAa,iBAAiB,aAAqB;CAClD,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,kBAAkB;CACjD,MAAM,CAAC,UAAU,cAAc,SAAS,MAAM,GAAG;CACjD,IAAI,CAAC,iBAAiB,QAAQ,GAAG,MAAM,IAAI,MAAM,kBAAkB;CACnE,IAAI,CAAC,YAAY,MAAM,IAAI,MAAM,iBAAiB;CAClD,OAAO;EAAE;EAAU;CAAW;AAC/B;;;;;AAMA,MAAa,mBAAmB,aAA4C;CAC3E,IAAI,OAAO,aAAa,YAAY,CAAC,UAAU,OAAO;CACtD,IAAI,aAAA,iBAAuC,OAAO;CAClD,MAAM,CAAC,UAAU,cAAc,SAAS,MAAM,GAAG;CACjD,OAAO,iBAAiB,QAAQ,KAAK,CAAC,CAAC;AACxC;;;;AC4EA,MAAa,yBACZ,WACmC,OAAO,SAAS;;;;;;;;;;;;;;;AAgBpD,MAAa,oBACZ,WAC+C,OAAO,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types-jnifAAA0.mjs","names":[],"sources":["../src/utils/getCachedObservable.ts","../src/utils/isWalletPlatform.ts","../src/utils/WalletId.ts","../src/api/types.ts"],"sourcesContent":["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 { 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\";\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":";AAIA,MAAM,eAAe,OAAO,IAAI,2BAA2B;AAE3D,MAAM,iBAAmD;CACxD,MAAM,IAAI;CAIV,IAAI,QAAQ,EAAE;CACd,IAAI,CAAC,OAAO;EACX,wBAAQ,IAAI,IAAI;EAChB,EAAE,gBAAgB;CACnB;CACA,OAAO;AACR;AAEA,MAAa,wBACZ,KACA,WACS;CACT,MAAM,QAAQ,SAAS;CACvB,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,KAAK,OAAO,CAAwB;CAEnE,OAAO,MAAM,IAAI,GAAG;AACrB;;;;;AAMA,MAAa,yBAAyB,QAAsB;CAC3D,SAAS,CAAC,CAAC,OAAO,GAAG;AACtB;;;;;;;;AASA,MAAa,kCAAkC,WAAyB;CACvE,MAAM,QAAQ,SAAS;CACvB,KAAK,MAAM,OAAO,MAAM,KAAK,GAC5B,IAAI,IAAI,WAAW,MAAM,GAAG,MAAM,OAAO,GAAG;AAE9C;;;;;AAMA,MAAa,kCAAwC;CACpD,SAAS,CAAC,CAAC,MAAM;AAClB;;;ACvDA,MAAa,oBACZ,aAEA,OAAO,aAAa,YACpB;CAAC;CAAY;CAAY;AAAQ,CAAC,CAAC,SAAS,QAA0B;;;;;;;;ACIvE,MAAa,2BAAqC;AAElD,MAAa,eACZ,UACA,eACc;CACd,IAAI,CAAC,iBAAiB,QAAQ,GAAG,MAAM,IAAI,MAAM,kBAAkB;CACnE,IAAI,CAAC,YAAY,MAAM,IAAI,MAAM,cAAc;CAC/C,OAAO,GAAG,SAAS,GAAG;AACvB;AAEA,MAAa,iBAAiB,aAAqB;CAClD,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,kBAAkB;CACjD,MAAM,CAAC,UAAU,cAAc,SAAS,MAAM,GAAG;CACjD,IAAI,CAAC,iBAAiB,QAAQ,GAAG,MAAM,IAAI,MAAM,kBAAkB;CACnE,IAAI,CAAC,YAAY,MAAM,IAAI,MAAM,iBAAiB;CAClD,OAAO;EAAE;EAAU;CAAW;AAC/B;;;;;AAMA,MAAa,mBAAmB,aAA4C;CAC3E,IAAI,OAAO,aAAa,YAAY,CAAC,UAAU,OAAO;CACtD,IAAI,aAAA,iBAAuC,OAAO;CAClD,MAAM,CAAC,UAAU,cAAc,SAAS,MAAM,GAAG;CACjD,OAAO,iBAAiB,QAAQ,KAAK,CAAC,CAAC;AACxC;;;;AC4EA,MAAa,yBACZ,WACmC,OAAO,SAAS;;;;;;;;;;;;;;;AAgBpD,MAAa,oBACZ,WAC+C,OAAO,SAAS"}
|
|
1
|
+
{"version":3,"file":"types-jnifAAA0.mjs","names":[],"sources":["../src/utils/getCachedObservable.ts","../src/utils/isWalletPlatform.ts","../src/utils/WalletId.ts","../src/api/types.ts"],"sourcesContent":["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 { 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\";\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\t/**\n\t * Dapp name sent to Polkadot injected extensions on connect. Some\n\t * extensions (e.g. polkadot.js) warn about a suspicious origin when it's\n\t * empty.\n\t *\n\t * @default walletConnect.metadata.name, then window.location.hostname\n\t */\n\tappName?: string;\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":";AAIA,MAAM,eAAe,OAAO,IAAI,2BAA2B;AAE3D,MAAM,iBAAmD;CACxD,MAAM,IAAI;CAIV,IAAI,QAAQ,EAAE;CACd,IAAI,CAAC,OAAO;EACX,wBAAQ,IAAI,IAAI;EAChB,EAAE,gBAAgB;CACnB;CACA,OAAO;AACR;AAEA,MAAa,wBACZ,KACA,WACS;CACT,MAAM,QAAQ,SAAS;CACvB,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,KAAK,OAAO,CAAwB;CAEnE,OAAO,MAAM,IAAI,GAAG;AACrB;;;;;AAMA,MAAa,yBAAyB,QAAsB;CAC3D,SAAS,CAAC,CAAC,OAAO,GAAG;AACtB;;;;;;;;AASA,MAAa,kCAAkC,WAAyB;CACvE,MAAM,QAAQ,SAAS;CACvB,KAAK,MAAM,OAAO,MAAM,KAAK,GAC5B,IAAI,IAAI,WAAW,MAAM,GAAG,MAAM,OAAO,GAAG;AAE9C;;;;;AAMA,MAAa,kCAAwC;CACpD,SAAS,CAAC,CAAC,MAAM;AAClB;;;ACvDA,MAAa,oBACZ,aAEA,OAAO,aAAa,YACpB;CAAC;CAAY;CAAY;AAAQ,CAAC,CAAC,SAAS,QAA0B;;;;;;;;ACIvE,MAAa,2BAAqC;AAElD,MAAa,eACZ,UACA,eACc;CACd,IAAI,CAAC,iBAAiB,QAAQ,GAAG,MAAM,IAAI,MAAM,kBAAkB;CACnE,IAAI,CAAC,YAAY,MAAM,IAAI,MAAM,cAAc;CAC/C,OAAO,GAAG,SAAS,GAAG;AACvB;AAEA,MAAa,iBAAiB,aAAqB;CAClD,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,kBAAkB;CACjD,MAAM,CAAC,UAAU,cAAc,SAAS,MAAM,GAAG;CACjD,IAAI,CAAC,iBAAiB,QAAQ,GAAG,MAAM,IAAI,MAAM,kBAAkB;CACnE,IAAI,CAAC,YAAY,MAAM,IAAI,MAAM,iBAAiB;CAClD,OAAO;EAAE;EAAU;CAAW;AAC/B;;;;;AAMA,MAAa,mBAAmB,aAA4C;CAC3E,IAAI,OAAO,aAAa,YAAY,CAAC,UAAU,OAAO;CACtD,IAAI,aAAA,iBAAuC,OAAO;CAClD,MAAM,CAAC,UAAU,cAAc,SAAS,MAAM,GAAG;CACjD,OAAO,iBAAiB,QAAQ,KAAK,CAAC,CAAC;AACxC;;;;AC4EA,MAAa,yBACZ,WACmC,OAAO,SAAS;;;;;;;;;;;;;;;AAgBpD,MAAa,oBACZ,WAC+C,OAAO,SAAS"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kheopskit/core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"private": false,
|
|
6
6
|
"sideEffects": false,
|
|
@@ -109,22 +109,22 @@
|
|
|
109
109
|
}
|
|
110
110
|
},
|
|
111
111
|
"dependencies": {
|
|
112
|
-
"@noble/hashes": "^2.
|
|
113
|
-
"@scure/base": "^2.
|
|
112
|
+
"@noble/hashes": "^2.4.0",
|
|
113
|
+
"@scure/base": "^2.4.0",
|
|
114
114
|
"lodash-es": "^4.18.1"
|
|
115
115
|
},
|
|
116
116
|
"devDependencies": {
|
|
117
|
-
"@reown/appkit": "^1.8.
|
|
118
|
-
"@solana/kit": "^
|
|
119
|
-
"@solana/wallet-standard-features": "^1.
|
|
117
|
+
"@reown/appkit": "^1.8.24",
|
|
118
|
+
"@solana/kit": "^8.4.0",
|
|
119
|
+
"@solana/wallet-standard-features": "^1.5.0",
|
|
120
120
|
"@types/lodash-es": "^4.17.12",
|
|
121
121
|
"@wallet-standard/app": "^1.1.1",
|
|
122
122
|
"@wallet-standard/base": "^1.1.1",
|
|
123
123
|
"@wallet-standard/features": "^1.1.1",
|
|
124
124
|
"mipd": "^0.0.7",
|
|
125
|
-
"polkadot-api": "^3.
|
|
125
|
+
"polkadot-api": "^3.2.0",
|
|
126
126
|
"rxjs": "^7.8.2",
|
|
127
|
-
"viem": "^2.
|
|
127
|
+
"viem": "^2.57.0"
|
|
128
128
|
},
|
|
129
129
|
"tsdown": {
|
|
130
130
|
"entry": [
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors-DPw6pc2H.js","names":["base58","base58"],"sources":["../src/utils/isEthereumAddress.ts","../src/utils/isSolanaAddress.ts","../src/utils/isSs58Address.ts","../src/utils/isValidAddress.ts","../src/utils/WalletAccountId.ts","../src/api/errors.ts"],"sourcesContent":["import { keccak_256 } from \"@noble/hashes/sha3.js\";\n\nconst HEX_ADDRESS = /^0x[0-9a-fA-F]{40}$/;\nconst encoder = new TextEncoder();\n\n/**\n * Verifies the EIP-55 mixed-case checksum of an Ethereum address.\n * Dependency-free (keccak via @noble/hashes) so core stays decoupled from viem.\n */\nconst isChecksumValid = (address: string): boolean => {\n\tconst hex = address.slice(2);\n\tconst hash = keccak_256(encoder.encode(hex.toLowerCase()));\n\tfor (let i = 0; i < 40; i++) {\n\t\tconst char = hex.charAt(i);\n\t\tconst isLetter =\n\t\t\t(char >= \"a\" && char <= \"f\") || (char >= \"A\" && char <= \"F\");\n\t\tif (!isLetter) continue;\n\t\tconst byte = hash[i >> 1] ?? 0;\n\t\tconst nibble = i % 2 === 0 ? byte >> 4 : byte & 0x0f;\n\t\tconst isUpper = char <= \"F\";\n\t\tif (isUpper !== nibble >= 8) return false;\n\t}\n\treturn true;\n};\n\n/**\n * Returns true if `address` is a valid Ethereum address.\n *\n * Mirrors viem's `isAddress` (strict): the shape must be `0x` + 40 hex, and a\n * mixed-case address must pass the EIP-55 checksum. All-lowercase addresses are\n * accepted as non-checksummed.\n */\nexport const isEthereumAddress = (address: string): boolean => {\n\tif (!HEX_ADDRESS.test(address)) return false;\n\tif (address === address.toLowerCase()) return true;\n\treturn isChecksumValid(address);\n};\n","import { base58 } from \"@scure/base\";\n\n/**\n * Returns true if the value is a valid Solana address: a base58-encoded\n * 32-byte ed25519 public key.\n *\n * Solana addresses carry no checksum, so this is a pure base58 + length check.\n * Dependency-free (base58 via @scure/base) so core stays decoupled from\n * @solana/kit.\n */\nexport const isSolanaAddress = (address: string): boolean => {\n\tif (!address) return false;\n\ttry {\n\t\treturn base58.decode(address).length === 32;\n\t} catch {\n\t\treturn false;\n\t}\n};\n","import { blake2b } from \"@noble/hashes/blake2.js\";\nimport { base58 } from \"@scure/base\";\n\n// The \"SS58PRE\" prefix used in the SS58 checksum preimage.\nconst SS58PRE = new Uint8Array([0x53, 0x53, 0x35, 0x38, 0x50, 0x52, 0x45]);\n\n/**\n * Returns true if `address` is a valid SS58-encoded 32-byte account id (the\n * only form Substrate wallets inject), verifying the blake2b-512 checksum.\n *\n * Dependency-free (base58 via @scure/base, blake2b via @noble/hashes) so core\n * stays decoupled from polkadot-api.\n */\nexport const isSs58Address = (address: string): boolean => {\n\tif (!address) return false;\n\n\tlet decoded: Uint8Array;\n\ttry {\n\t\tdecoded = base58.decode(address);\n\t} catch {\n\t\treturn false;\n\t}\n\n\t// First byte encodes the network prefix; the high bit is reserved/invalid.\n\tconst firstByte = decoded[0];\n\tif (firstByte === undefined || firstByte & 0b1000_0000) return false;\n\t// The 0b0100_0000 bit marks a 2-byte prefix.\n\tconst prefixLength = firstByte & 0b0100_0000 ? 2 : 1;\n\n\t// AccountId32 layout: prefix + 32-byte pubkey + 2-byte checksum.\n\tif (decoded.length !== prefixLength + 32 + 2) return false;\n\n\tconst body = decoded.subarray(0, decoded.length - 2);\n\tconst preimage = new Uint8Array(SS58PRE.length + body.length);\n\tpreimage.set(SS58PRE);\n\tpreimage.set(body, SS58PRE.length);\n\tconst hash = blake2b(preimage, { dkLen: 64 });\n\n\treturn (\n\t\tdecoded[decoded.length - 2] === hash[0] &&\n\t\tdecoded[decoded.length - 1] === hash[1]\n\t);\n};\n","import { isEthereumAddress } from \"./isEthereumAddress\";\nimport { isSolanaAddress } from \"./isSolanaAddress\";\nimport { isSs58Address } from \"./isSs58Address\";\n\nexport const isValidAddress = (address: string): boolean => {\n\tif (address.startsWith(\"0x\")) return isEthereumAddress(address);\n\t// SS58 (checksummed) and Solana (base58, no checksum) are disjoint: a\n\t// 32-byte Solana pubkey fails SS58 decoding, and an SS58 address decodes to\n\t// more than 32 bytes so it fails the Solana length check.\n\treturn isSs58Address(address) || isSolanaAddress(address);\n};\n","import { isValidAddress } from \"./isValidAddress\";\n\nexport type WalletAccountId = string;\n\nexport const getWalletAccountId = (\n\twalletId: string,\n\taddress: string,\n): WalletAccountId => {\n\tif (!walletId) throw new Error(\"Missing walletId\");\n\tif (!isValidAddress(address)) throw new Error(\"Invalid address\");\n\treturn `${walletId}::${address}`;\n};\n\nexport const parseWalletAccountId = (accountId: string) => {\n\tif (!accountId) throw new Error(\"Invalid walletAccountId\");\n\tconst [walletId, address] = accountId.split(\"::\");\n\tif (!walletId) throw new Error(\"Missing walletId\");\n\tif (!address || !isValidAddress(address)) throw new Error(\"Invalid address\");\n\treturn { walletId, address };\n};\n","import type { WalletId } from \"../utils/WalletId\";\n\n/**\n * Stable error codes thrown by kheopskit. Catch a {@link KheopskitError} and\n * branch on `error.code` instead of matching message strings.\n */\nexport type KheopskitErrorCode =\n\t/** `connect()` called on a wallet that is already connected. */\n\t| \"WALLET_ALREADY_CONNECTED\"\n\t/** `disconnect()` called on a wallet that is not connected. */\n\t| \"WALLET_NOT_CONNECTED\"\n\t/** The wallet does not advertise a capability kheopskit needs to proceed. */\n\t| \"FEATURE_NOT_SUPPORTED\"\n\t/** No active WalletConnect session for the requested operation. */\n\t| \"NO_SESSION\"\n\t/** No provider available for the requested namespace. */\n\t| \"NO_PROVIDER\"\n\t/** The installed polkadot-api version exposes neither `getTxCreatorFromPjs` (v3) nor `getPolkadotSignerFromPjs` (v2). */\n\t| \"UNSUPPORTED_VERSION\"\n\t/** The requested chain cannot be used for this operation (e.g. a Solana cluster with no CAIP-2 id over WalletConnect). */\n\t| \"UNSUPPORTED_CHAIN\";\n\n/**\n * Error thrown by kheopskit wallet/account operations. Carries a stable\n * {@link KheopskitErrorCode} and, when relevant, the offending wallet id.\n *\n * @example\n * ```ts\n * try {\n * await wallet.connect();\n * } catch (error) {\n * if (error instanceof KheopskitError && error.code === \"WALLET_ALREADY_CONNECTED\") {\n * // ignore\n * } else throw error;\n * }\n * ```\n */\nexport class KheopskitError extends Error {\n\treadonly code: KheopskitErrorCode;\n\t/** The wallet id this error relates to, when applicable. */\n\treadonly walletId?: WalletId;\n\n\tconstructor(\n\t\tcode: KheopskitErrorCode,\n\t\tmessage: string,\n\t\toptions?: { walletId?: WalletId; cause?: unknown },\n\t) {\n\t\tsuper(`[kheopskit] ${message}`, { cause: options?.cause });\n\t\tthis.name = \"KheopskitError\";\n\t\tthis.code = code;\n\t\tthis.walletId = options?.walletId;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"injectedWallets-B1MCxAE9.js","names":["Observable","isWalletConnectWallet","getCachedObservable$","Observable","BehaviorSubject","KheopskitError"],"sources":["../src/api/platformAccounts.ts","../src/api/injectedWallets.ts"],"sourcesContent":["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"],"mappings":";;;;;AA+CA,MAAa,2BAGX,EACD,UACA,sBACA,2BACA,aACA,oBAAoB,YAAY,QAAQ,SACiC;CACzE,MAAM,qBAAqB,GAAe,MACzC,EAAE,WAAW,EAAE,UACf,EAAE,OAAO,SAAS,MAAM;EACvB,MAAM,QAAQ,EAAE;EAChB,OAAO,CAAC,CAAC,SAAS,iBAAiB,OAAO,MAAM,iBAAiB,KAAK;CACvE,CAAC;CAEF,OAAO,IAAIA,KAAAA,YAAwB,eAAe;EACjD,MAAM,MAAM,SACV,MAAA,GAAA,KAAA,IAAA,EACK,YAAY,QAAQ,QAAQ,MAAM,EAAE,WAAW,CAAC,IAAA,GAAA,KAAA,UAAA,EAC1C,YACV,QAAQ,UAAA,GAAA,KAAA,cAAA,CACS,CACd,GAAG,QACD,QAAQ,MAAoB,CAACC,cAAAA,sBAAsB,CAAC,CAAC,CAAC,CACtD,IAAI,oBAAoB,GAC1B,GAAG,QACD,OAAOA,cAAAA,qBAAqB,CAAC,CAC7B,IAAI,yBAAyB,CAChC,CAAC,KAAA,GAAA,KAAA,GAAA,CACG,CAAC,CAAC,CACT,IAAA,GAAA,KAAA,IAAA,EACK,aAAa;GACjB,MAAM,OAAO,SAAS,KAAK;GAC3B,OAAO,cAAc,YAAY,IAAI,IAAI;EAC1C,CAAC,IAAA,GAAA,KAAA,qBAAA,CACoB,iBAAiB,CACvC,CAAC,CACA,UAAU,UAAU;EAEtB,aAAa;GACZ,IAAI,YAAY;EACjB;CACD,CAAC,CAAC,CAAC,MAAA,GAAA,KAAA,YAAA,CAAiB;EAAE,UAAU;EAAM,YAAY;CAAE,CAAC,CAAC;AACvD;;;;;AAMA,MAAa,qBACZ,SACA,cAEA,OAAO,OAAO,QAAQ,UAAU,CAAC,CAC/B,SAAS,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,CAClC,QAAQ,YAAY,QAAQ,WAAW,GAAG,UAAU,EAAE,CAAC;;;;;AAM1D,MAAa,sBAAsB,YAAgC,CAClE,GAAG,IAAI,IACN,QACE,KAAK,YAAY,QAAQ,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,CACvC,QAAQ,YAA+B,CAAC,CAAC,OAAO,CACnD,CACD;;;;;;;;;;;AAYA,MAAa,oCAEX,YAS4B;CAC7B,MAAM,EAAE,QAAQ,UAAU,WAAW,UAAU,kBAAkB;CACjE,MAAM,WAAW,OAAO,OAAO,YAAY,SAAS;CAEpD,IAAI,CAAC,OAAO,UAAU,SAAS,QAAQ,KAAK,CAAC,UAAU,SAAS,QAAA,GAAA,KAAA,GAAA,CAAU,CAAC,CAAC;CAE5E,OAAOC,cAAAA,qBAAqB,gBAC3B,IAAIF,KAAAA,YAAwB,eAAe;EAC1C,WAAW,KAAK,cAAc,QAAQ,CAAC;EAIvC,MAAM,eAAe,WAAW,KAAK,cAAc,QAAQ,CAAC;EAC5D,SAAS,GAAG,kBAAkB,MAAM;EACpC,SAAS,GAAG,mBAAmB,MAAM;EAErC,aAAa;GACZ,SAAS,IAAI,kBAAkB,MAAM;GACrC,SAAS,IAAI,mBAAmB,MAAM;EACvC;CACD,CAAC,CAAC,CAAC,MAAA,GAAA,KAAA,YAAA,CAAiB;EAAE,UAAU;EAAM,YAAY;CAAE,CAAC,CAAC,CACvD;AACD;;;;;;;AChJA,MAAM,gBAGL,GACA,MACa;CACb,IAAI,EAAE,WAAW,EAAE,QAAQ,OAAO;CAClC,OAAO,EAAE,OACP,GAAG,MACH,EAAE,OAAO,EAAE,EAAE,EAAE,MACf,EAAE,gBAAgB,EAAE,EAAE,EAAE,eACxB,EAAE,SAAS,EAAE,EAAE,EAAE,IACnB;AACD;;;;;;;;AAyDA,MAAa,0BAKZ,OACA,YAEA,IAAIG,KAAAA,YAAuB,eAAe;CACzC,MAAM,WAAW,IAAIC,KAAAA,gCAAwC,IAAI,IAAI,CAAC;CAEtE,MAAM,UAAU,OAAO,QAAiB,aAAuB;EAC9D,IAAI,SAAS,MAAM,IAAI,QAAQ,GAC9B,MAAM,IAAIC,eAAAA,eACT,4BACA,UAAU,SAAS,wBACnB,EAAE,SAAS,CACZ;EAED,MAAM,SAAS,MAAM,QAAQ,QAAQ,QAAQ,QAAQ;EAErD,MAAM,OAAO,IAAI,IAAI,SAAS,KAAK;EACnC,KAAK,IAAI,UAAU,MAAM;EACzB,SAAS,KAAK,IAAI;EAElB,MAAM,mBAAmB,QAAQ;CAClC;CAEA,MAAM,aAAa,OAAO,QAAiB,aAAuB;EACjE,IAAI,CAAC,SAAS,MAAM,IAAI,QAAQ,GAC/B,MAAM,IAAIA,eAAAA,eACT,wBACA,UAAU,SAAS,oBACnB,EAAE,SAAS,CACZ;EAED,MAAM,QAAQ,aAAa,QAAQ,QAAQ;EAE3C,MAAM,OAAO,IAAI,IAAI,SAAS,KAAK;EACnC,KAAK,OAAO,QAAQ;EACpB,SAAS,KAAK,IAAI;EAElB,MAAM,sBAAsB,QAAQ;EAEpC,QAAQ,iBAAiB,QAAQ;CAClC;CAEA,MAAM,OAAA,GAAA,KAAA,cAAA,CAAoB,CAAC,QAAQ,UAAU,QAAQ,CAAC,CAAC,CACrD,MAAA,GAAA,KAAA,IAAA,EACK,CAAC,SAAS,aACd,QAAQ,KAAK,WAAoB;EAChC,MAAM,WAAW,QAAQ,YAAY,MAAM;EAC3C,OAAO,QAAQ,YAAY;GAC1B;GACA;GACA,QAAQ,QAAQ,IAAI,QAAQ;GAC5B,aAAa,QAAQ,IAAI,QAAQ;GACjC,eAAe,QAAQ,QAAQ,QAAQ;GACvC,kBAAkB,WAAW,QAAQ,QAAQ;EAC9C,CAAC;CACF,CAAC,CACF,IAAA,GAAA,KAAA,qBAAA,CACqB,YAAY,CAClC,CAAC,CACA,UAAU,UAAU;CAEtB,aAAa;EACZ,IAAI,YAAY;CACjB;AACD,CAAC,CAAC,CAAC,MAAA,GAAA,KAAA,YAAA,CAAiB;CAAE,UAAU;CAAM,YAAY;AAAE,CAAC,CAAC"}
|