@kheopskit/core 5.1.2 → 5.2.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/MIGRATING_TO_V4.md +1 -1
- package/dist/errors-Caq2csKx.mjs.map +1 -1
- package/dist/errors-DPw6pc2H.js.map +1 -1
- package/dist/{iconCache-DS4zNiP1.js → iconCache-CicUSbR1.js} +2 -2
- package/dist/iconCache-CicUSbR1.js.map +1 -0
- package/dist/{iconCache-BSa42Sui.mjs → iconCache-Cml-6Rft.mjs} +2 -2
- package/dist/iconCache-Cml-6Rft.mjs.map +1 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.mjs +1 -1
- package/dist/polkadot.d.mts +7 -4
- package/dist/polkadot.d.ts +7 -4
- package/dist/polkadot.js +44 -2
- package/dist/polkadot.js.map +1 -1
- package/dist/polkadot.mjs +23 -3
- package/dist/polkadot.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/iconCache-BSa42Sui.mjs.map +0 -1
- package/dist/iconCache-DS4zNiP1.js.map +0 -1
package/MIGRATING_TO_V4.md
CHANGED
|
@@ -226,7 +226,7 @@ cross-platform signer, by design (the SDKs differ). Guard access behind
|
|
|
226
226
|
|----------|-----------------|
|
|
227
227
|
| Ethereum | `account.client` — a viem `WalletClient` (switch chains via the client) |
|
|
228
228
|
| Solana | `account.signer` (bound to the configured cluster) and `account.getSigner(chain)` for another cluster |
|
|
229
|
-
| Polkadot | `account.
|
|
229
|
+
| Polkadot | `account.txCreator` (polkadot-api v3) or `account.polkadotSigner` (v2) |
|
|
230
230
|
|
|
231
231
|
## 11. New public exports
|
|
232
232
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors-Caq2csKx.mjs","names":[],"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 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":";;;;AAEA,MAAM,cAAc;AACpB,MAAM,UAAU,IAAI,YAAY;;;;;AAMhC,MAAM,mBAAmB,YAA6B;CACrD,MAAM,MAAM,QAAQ,MAAM,CAAC;CAC3B,MAAM,OAAO,WAAW,QAAQ,OAAO,IAAI,YAAY,CAAC,CAAC;CACzD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC5B,MAAM,OAAO,IAAI,OAAO,CAAC;EAGzB,IAAI,EADF,QAAQ,OAAO,QAAQ,OAAS,QAAQ,OAAO,QAAQ,MAC1C;EACf,MAAM,OAAO,KAAK,KAAK,MAAM;EAC7B,MAAM,SAAS,IAAI,MAAM,IAAI,QAAQ,IAAI,OAAO;EAEhD,IADgB,QAAQ,QACR,UAAU,GAAG,OAAO;CACrC;CACA,OAAO;AACR;;;;;;;;AASA,MAAa,qBAAqB,YAA6B;CAC9D,IAAI,CAAC,YAAY,KAAK,OAAO,GAAG,OAAO;CACvC,IAAI,YAAY,QAAQ,YAAY,GAAG,OAAO;CAC9C,OAAO,gBAAgB,OAAO;AAC/B;;;;;;;;;;;AC1BA,MAAa,mBAAmB,YAA6B;CAC5D,IAAI,CAAC,SAAS,OAAO;CACrB,IAAI;EACH,OAAO,OAAO,OAAO,OAAO,CAAC,CAAC,WAAW;CAC1C,QAAQ;EACP,OAAO;CACR;AACD;;;ACbA,MAAM,UAAU,IAAI,WAAW;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI,CAAC;;;;;;;;AASzE,MAAa,iBAAiB,YAA6B;CAC1D,IAAI,CAAC,SAAS,OAAO;CAErB,IAAI;CACJ,IAAI;EACH,UAAU,OAAO,OAAO,OAAO;CAChC,QAAQ;EACP,OAAO;CACR;CAGA,MAAM,YAAY,QAAQ;CAC1B,IAAI,cAAc,KAAA,KAAa,YAAY,KAAa,OAAO;CAE/D,MAAM,eAAe,YAAY,KAAc,IAAI;CAGnD,IAAI,QAAQ,WAAW,eAAe,KAAK,GAAG,OAAO;CAErD,MAAM,OAAO,QAAQ,SAAS,GAAG,QAAQ,SAAS,CAAC;CACnD,MAAM,WAAW,IAAI,WAAW,QAAQ,SAAS,KAAK,MAAM;CAC5D,SAAS,IAAI,OAAO;CACpB,SAAS,IAAI,MAAM,QAAQ,MAAM;CACjC,MAAM,OAAO,QAAQ,UAAU,EAAE,OAAO,GAAG,CAAC;CAE5C,OACC,QAAQ,QAAQ,SAAS,OAAO,KAAK,MACrC,QAAQ,QAAQ,SAAS,OAAO,KAAK;AAEvC;;;ACtCA,MAAa,kBAAkB,YAA6B;CAC3D,IAAI,QAAQ,WAAW,IAAI,GAAG,OAAO,kBAAkB,OAAO;CAI9D,OAAO,cAAc,OAAO,KAAK,gBAAgB,OAAO;AACzD;;;ACNA,MAAa,sBACZ,UACA,YACqB;CACrB,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,kBAAkB;CACjD,IAAI,CAAC,eAAe,OAAO,GAAG,MAAM,IAAI,MAAM,iBAAiB;CAC/D,OAAO,GAAG,SAAS,IAAI;AACxB;AAEA,MAAa,wBAAwB,cAAsB;CAC1D,IAAI,CAAC,WAAW,MAAM,IAAI,MAAM,yBAAyB;CACzD,MAAM,CAAC,UAAU,WAAW,UAAU,MAAM,IAAI;CAChD,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,kBAAkB;CACjD,IAAI,CAAC,WAAW,CAAC,eAAe,OAAO,GAAG,MAAM,IAAI,MAAM,iBAAiB;CAC3E,OAAO;EAAE;EAAU;CAAQ;AAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"errors-Caq2csKx.mjs","names":[],"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":";;;;AAEA,MAAM,cAAc;AACpB,MAAM,UAAU,IAAI,YAAY;;;;;AAMhC,MAAM,mBAAmB,YAA6B;CACrD,MAAM,MAAM,QAAQ,MAAM,CAAC;CAC3B,MAAM,OAAO,WAAW,QAAQ,OAAO,IAAI,YAAY,CAAC,CAAC;CACzD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC5B,MAAM,OAAO,IAAI,OAAO,CAAC;EAGzB,IAAI,EADF,QAAQ,OAAO,QAAQ,OAAS,QAAQ,OAAO,QAAQ,MAC1C;EACf,MAAM,OAAO,KAAK,KAAK,MAAM;EAC7B,MAAM,SAAS,IAAI,MAAM,IAAI,QAAQ,IAAI,OAAO;EAEhD,IADgB,QAAQ,QACR,UAAU,GAAG,OAAO;CACrC;CACA,OAAO;AACR;;;;;;;;AASA,MAAa,qBAAqB,YAA6B;CAC9D,IAAI,CAAC,YAAY,KAAK,OAAO,GAAG,OAAO;CACvC,IAAI,YAAY,QAAQ,YAAY,GAAG,OAAO;CAC9C,OAAO,gBAAgB,OAAO;AAC/B;;;;;;;;;;;AC1BA,MAAa,mBAAmB,YAA6B;CAC5D,IAAI,CAAC,SAAS,OAAO;CACrB,IAAI;EACH,OAAO,OAAO,OAAO,OAAO,CAAC,CAAC,WAAW;CAC1C,QAAQ;EACP,OAAO;CACR;AACD;;;ACbA,MAAM,UAAU,IAAI,WAAW;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI,CAAC;;;;;;;;AASzE,MAAa,iBAAiB,YAA6B;CAC1D,IAAI,CAAC,SAAS,OAAO;CAErB,IAAI;CACJ,IAAI;EACH,UAAU,OAAO,OAAO,OAAO;CAChC,QAAQ;EACP,OAAO;CACR;CAGA,MAAM,YAAY,QAAQ;CAC1B,IAAI,cAAc,KAAA,KAAa,YAAY,KAAa,OAAO;CAE/D,MAAM,eAAe,YAAY,KAAc,IAAI;CAGnD,IAAI,QAAQ,WAAW,eAAe,KAAK,GAAG,OAAO;CAErD,MAAM,OAAO,QAAQ,SAAS,GAAG,QAAQ,SAAS,CAAC;CACnD,MAAM,WAAW,IAAI,WAAW,QAAQ,SAAS,KAAK,MAAM;CAC5D,SAAS,IAAI,OAAO;CACpB,SAAS,IAAI,MAAM,QAAQ,MAAM;CACjC,MAAM,OAAO,QAAQ,UAAU,EAAE,OAAO,GAAG,CAAC;CAE5C,OACC,QAAQ,QAAQ,SAAS,OAAO,KAAK,MACrC,QAAQ,QAAQ,SAAS,OAAO,KAAK;AAEvC;;;ACtCA,MAAa,kBAAkB,YAA6B;CAC3D,IAAI,QAAQ,WAAW,IAAI,GAAG,OAAO,kBAAkB,OAAO;CAI9D,OAAO,cAAc,OAAO,KAAK,gBAAgB,OAAO;AACzD;;;ACNA,MAAa,sBACZ,UACA,YACqB;CACrB,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,kBAAkB;CACjD,IAAI,CAAC,eAAe,OAAO,GAAG,MAAM,IAAI,MAAM,iBAAiB;CAC/D,OAAO,GAAG,SAAS,IAAI;AACxB;AAEA,MAAa,wBAAwB,cAAsB;CAC1D,IAAI,CAAC,WAAW,MAAM,IAAI,MAAM,yBAAyB;CACzD,MAAM,CAAC,UAAU,WAAW,UAAU,MAAM,IAAI;CAChD,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,kBAAkB;CACjD,IAAI,CAAC,WAAW,CAAC,eAAe,OAAO,GAAG,MAAM,IAAI,MAAM,iBAAiB;CAC3E,OAAO;EAAE;EAAU;CAAQ;AAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACkBA,IAAa,iBAAb,cAAoC,MAAM;CAKzC,YACC,MACA,SACA,SACC;EACD,MAAM,eAAe,WAAW,EAAE,OAAO,SAAS,MAAM,CAAC;EATjD,gBAAA,MAAA,QAAA,KAAA,CAAA;EAEA,gBAAA,MAAA,YAAA,KAAA,CAAA;EAQR,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,WAAW,SAAS;CAC1B;AACD"}
|
|
@@ -1 +1 @@
|
|
|
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 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":";;;;AAEA,MAAM,cAAc;AACpB,MAAM,UAAU,IAAI,YAAY;;;;;AAMhC,MAAM,mBAAmB,YAA6B;CACrD,MAAM,MAAM,QAAQ,MAAM,CAAC;CAC3B,MAAM,QAAA,GAAA,sBAAA,WAAA,CAAkB,QAAQ,OAAO,IAAI,YAAY,CAAC,CAAC;CACzD,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC5B,MAAM,OAAO,IAAI,OAAO,CAAC;EAGzB,IAAI,EADF,QAAQ,OAAO,QAAQ,OAAS,QAAQ,OAAO,QAAQ,MAC1C;EACf,MAAM,OAAO,KAAK,KAAK,MAAM;EAC7B,MAAM,SAAS,IAAI,MAAM,IAAI,QAAQ,IAAI,OAAO;EAEhD,IADgB,QAAQ,QACR,UAAU,GAAG,OAAO;CACrC;CACA,OAAO;AACR;;;;;;;;AASA,MAAa,qBAAqB,YAA6B;CAC9D,IAAI,CAAC,YAAY,KAAK,OAAO,GAAG,OAAO;CACvC,IAAI,YAAY,QAAQ,YAAY,GAAG,OAAO;CAC9C,OAAO,gBAAgB,OAAO;AAC/B;;;;;;;;;;;AC1BA,MAAa,mBAAmB,YAA6B;CAC5D,IAAI,CAAC,SAAS,OAAO;CACrB,IAAI;EACH,OAAOA,YAAAA,OAAO,OAAO,OAAO,CAAC,CAAC,WAAW;CAC1C,QAAQ;EACP,OAAO;CACR;AACD;;;ACbA,MAAM,UAAU,IAAI,WAAW;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI,CAAC;;;;;;;;AASzE,MAAa,iBAAiB,YAA6B;CAC1D,IAAI,CAAC,SAAS,OAAO;CAErB,IAAI;CACJ,IAAI;EACH,UAAUC,YAAAA,OAAO,OAAO,OAAO;CAChC,QAAQ;EACP,OAAO;CACR;CAGA,MAAM,YAAY,QAAQ;CAC1B,IAAI,cAAc,KAAA,KAAa,YAAY,KAAa,OAAO;CAE/D,MAAM,eAAe,YAAY,KAAc,IAAI;CAGnD,IAAI,QAAQ,WAAW,eAAe,KAAK,GAAG,OAAO;CAErD,MAAM,OAAO,QAAQ,SAAS,GAAG,QAAQ,SAAS,CAAC;CACnD,MAAM,WAAW,IAAI,WAAW,QAAQ,SAAS,KAAK,MAAM;CAC5D,SAAS,IAAI,OAAO;CACpB,SAAS,IAAI,MAAM,QAAQ,MAAM;CACjC,MAAM,QAAA,GAAA,wBAAA,QAAA,CAAe,UAAU,EAAE,OAAO,GAAG,CAAC;CAE5C,OACC,QAAQ,QAAQ,SAAS,OAAO,KAAK,MACrC,QAAQ,QAAQ,SAAS,OAAO,KAAK;AAEvC;;;ACtCA,MAAa,kBAAkB,YAA6B;CAC3D,IAAI,QAAQ,WAAW,IAAI,GAAG,OAAO,kBAAkB,OAAO;CAI9D,OAAO,cAAc,OAAO,KAAK,gBAAgB,OAAO;AACzD;;;ACNA,MAAa,sBACZ,UACA,YACqB;CACrB,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,kBAAkB;CACjD,IAAI,CAAC,eAAe,OAAO,GAAG,MAAM,IAAI,MAAM,iBAAiB;CAC/D,OAAO,GAAG,SAAS,IAAI;AACxB;AAEA,MAAa,wBAAwB,cAAsB;CAC1D,IAAI,CAAC,WAAW,MAAM,IAAI,MAAM,yBAAyB;CACzD,MAAM,CAAC,UAAU,WAAW,UAAU,MAAM,IAAI;CAChD,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,kBAAkB;CACjD,IAAI,CAAC,WAAW,CAAC,eAAe,OAAO,GAAG,MAAM,IAAI,MAAM,iBAAiB;CAC3E,OAAO;EAAE;EAAU;CAAQ;AAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
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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"}
|
|
@@ -63,7 +63,7 @@ const hydrateWallet = (cached) => {
|
|
|
63
63
|
* plain, serializable platform data that lives in the cache — Ethereum `chainId`
|
|
64
64
|
* and the Polkadot key `type`. Those render immediately on reload (no blank →
|
|
65
65
|
* value flicker) and match what the live account will report. Only the SDK
|
|
66
|
-
* handles (`client`/`signer`/`
|
|
66
|
+
* handles (`client`/`signer`/`txCreator`) are absent until the real account
|
|
67
67
|
* replaces this placeholder; signing stays gated on `isHydrating` until then.
|
|
68
68
|
*/
|
|
69
69
|
const hydrateAccount = (cached) => ({
|
|
@@ -393,4 +393,4 @@ Object.defineProperty(exports, "setCachedIcons", {
|
|
|
393
393
|
}
|
|
394
394
|
});
|
|
395
395
|
|
|
396
|
-
//# sourceMappingURL=iconCache-
|
|
396
|
+
//# sourceMappingURL=iconCache-CicUSbR1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iconCache-CicUSbR1.js","names":["POLKADOT_EXTENSIONS","parseWalletId","isWalletConnectWallet"],"sources":["../src/utils/hydrateState.ts","../src/utils/storage.ts","../src/utils/iconCache.ts"],"sourcesContent":["import {\n\ttype BaseWallet,\n\ttype BaseWalletAccount,\n\ttype CachedAccount,\n\ttype CachedWallet,\n\tisWalletConnectWallet,\n\ttype PolkadotAccountType,\n\ttype WalletConnectWallet,\n} from \"../api/types\";\nimport { POLKADOT_EXTENSIONS } from \"./polkadotExtensions\";\nimport type { WalletAccountId } from \"./WalletAccountId\";\nimport { parseWalletId, type WalletId } from \"./WalletId\";\n\n/**\n * Looks up the icon for a wallet from known Polkadot extensions only.\n * Ethereum icons will be populated from the localStorage icon cache via the merge function.\n *\n * Note: We DON'T use localStorage icon cache here because hydrateWallet is called\n * during SSR (server) and client hydration. localStorage isn't available on server,\n * so using it would cause a hydration mismatch. Icons for Ethereum wallets will be\n * populated when the hydration buffer merges cached wallets with live wallets.\n */\nconst lookupWalletIcon = (platform: string, identifier: string): string => {\n\t// Only Polkadot extensions have hardcoded icons that are safe for SSR\n\tif (platform === \"polkadot\") {\n\t\treturn POLKADOT_EXTENSIONS[identifier]?.icon ?? \"\";\n\t}\n\t// Ethereum icons come from localStorage or live wallets - not here\n\treturn \"\";\n};\n\n/**\n * Error thrown when trying to use a placeholder wallet that hasn't fully loaded yet.\n */\nclass PendingWalletError extends Error {\n\tconstructor(walletId: string) {\n\t\tsuper(\n\t\t\t`Wallet ${walletId} is still loading. Wait for isHydrating to be false before calling connect/disconnect.`,\n\t\t);\n\t\tthis.name = \"PendingWalletError\";\n\t}\n}\n\n/**\n * Converts a CachedWallet to a placeholder wallet for SSR hydration display.\n *\n * The placeholder carries only the SDK-free {@link BaseWallet} fields; the real\n * wallet (with its injected provider/extension/standard-wallet handle) replaces\n * it once it loads. connect/disconnect throw until then.\n */\nexport const hydrateWallet = (\n\tcached: CachedWallet,\n): BaseWallet | WalletConnectWallet => {\n\tconst throwPending = () => {\n\t\tthrow new PendingWalletError(cached.id);\n\t};\n\n\t// The platform-less WalletConnect connector. `appKit`/`platforms` are SDK\n\t// state absent until the live connector loads (cast like other placeholder\n\t// SDK handles); icon is filled from the localStorage cache by the caller.\n\tif (cached.type === \"walletconnect\") {\n\t\treturn {\n\t\t\tid: cached.id,\n\t\t\ttype: \"walletconnect\",\n\t\t\tplatforms: [],\n\t\t\tname: cached.name,\n\t\t\ticon: \"\",\n\t\t\tisConnected: cached.isConnected,\n\t\t\tconnect: throwPending,\n\t\t\tdisconnect: throwPending,\n\t\t} as unknown as WalletConnectWallet;\n\t}\n\n\tconst { platform, identifier } = parseWalletId(cached.id);\n\n\treturn {\n\t\tid: cached.id,\n\t\tplatform: cached.platform as BaseWallet[\"platform\"],\n\t\ttype: cached.type,\n\t\tname: cached.name,\n\t\ticon: lookupWalletIcon(platform, identifier),\n\t\tisConnected: cached.isConnected,\n\t\tconnect: throwPending,\n\t\tdisconnect: throwPending,\n\t};\n};\n\n/**\n * Converts a CachedAccount to a placeholder account for SSR hydration display.\n *\n * The placeholder carries the SDK-free {@link BaseWalletAccount} fields plus the\n * plain, serializable platform data that lives in the cache — Ethereum `chainId`\n * and the Polkadot key `type`. Those render immediately on reload (no blank →\n * value flicker) and match what the live account will report. Only the SDK\n * handles (`client`/`signer`/`txCreator`) are absent until the real account\n * replaces this placeholder; signing stays gated on `isHydrating` until then.\n */\nexport const hydrateAccount = (cached: CachedAccount): BaseWalletAccount => ({\n\tid: cached.id as WalletAccountId,\n\tplatform: cached.platform,\n\taddress: cached.address,\n\tname: cached.name,\n\twalletId: cached.walletId,\n\twalletName: cached.walletName,\n\t// Spread (not direct keys) so the extra platform fields don't trip the\n\t// excess-property check against BaseWalletAccount; they're read back via the\n\t// platform-specific account types once narrowed by `platform`.\n\t...(cached.platform === \"ethereum\" && { chainId: cached.chainId }),\n\t...(cached.platform === \"polkadot\" && {\n\t\ttype: cached.polkadotAccountType,\n\t}),\n});\n\n/**\n * Converts a wallet to a CachedWallet for storage.\n * Only extracts the serializable properties needed for hydration.\n */\nexport const serializeWallet = (\n\twallet: BaseWallet | WalletConnectWallet,\n): CachedWallet => ({\n\tid: wallet.id,\n\t// The WalletConnect connector has no platform.\n\tplatform: isWalletConnectWallet(wallet) ? undefined : wallet.platform,\n\ttype: wallet.type,\n\tname: wallet.name,\n\t// Note: icon is NOT stored to save cookie space\n\tisConnected: wallet.isConnected,\n});\n\n/**\n * Converts an account to a CachedAccount for storage.\n * Only extracts the serializable properties needed for hydration. Platform-only\n * fields (Ethereum chainId, Polkadot key type) are read defensively so this\n * stays SDK-free.\n */\nexport const serializeAccount = (\n\taccount: BaseWalletAccount,\n): CachedAccount => ({\n\tid: account.id,\n\tplatform: account.platform,\n\taddress: account.address,\n\tname: account.name,\n\tchainId:\n\t\taccount.platform === \"ethereum\"\n\t\t\t? (account as { chainId?: number }).chainId\n\t\t\t: undefined,\n\tpolkadotAccountType:\n\t\taccount.platform === \"polkadot\"\n\t\t\t? (account as { type?: PolkadotAccountType }).type\n\t\t\t: undefined,\n\twalletId: account.walletId as WalletId,\n\twalletName: account.walletName,\n});\n","export type Storage = {\n\tgetItem: (key: string) => string | null;\n\tsetItem: (key: string, value: string) => void;\n\tremoveItem: (key: string) => void;\n};\n\n/**\n * Extended storage interface with cross-tab sync support.\n */\nexport type SyncableStorage = Storage & {\n\t/**\n\t * Subscribe to storage changes from other tabs.\n\t * Returns an unsubscribe function.\n\t */\n\tsubscribe?: (\n\t\tkey: string,\n\t\tcallback: (value: string | null) => void,\n\t) => () => void;\n};\n\n/**\n * A no-op storage implementation that does nothing.\n * Useful for testing or SSR environments where no storage is needed.\n */\nexport const noopStorage: SyncableStorage = {\n\tgetItem: () => null,\n\tsetItem: () => {},\n\tremoveItem: () => {},\n};\n\n/**\n * Cached localStorage wrapper instance.\n * Lazily initialized on first access to avoid SSR issues.\n */\nlet _safeLocalStorage: SyncableStorage | null = null;\n\n/**\n * Creates the localStorage wrapper, testing for availability.\n * Returns noopStorage if localStorage is unavailable (SSR, private browsing, etc.)\n */\nconst createSafeLocalStorage = (): SyncableStorage => {\n\tif (typeof window === \"undefined\") return noopStorage;\n\n\ttry {\n\t\t// Test that localStorage is accessible (may throw in private browsing)\n\t\tconst testKey = \"__kheopskit_test__\";\n\t\twindow.localStorage.setItem(testKey, testKey);\n\t\twindow.localStorage.removeItem(testKey);\n\n\t\treturn {\n\t\t\tgetItem: (key: string) => window.localStorage.getItem(key),\n\t\t\tsetItem: (key: string, value: string) =>\n\t\t\t\twindow.localStorage.setItem(key, value),\n\t\t\tremoveItem: (key: string) => window.localStorage.removeItem(key),\n\t\t\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\t\t\tconst handler = (event: StorageEvent) => {\n\t\t\t\t\tif (event.key === key) {\n\t\t\t\t\t\tcallback(event.newValue);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\twindow.addEventListener(\"storage\", handler);\n\t\t\t\treturn () => window.removeEventListener(\"storage\", handler);\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn noopStorage;\n\t}\n};\n\n/**\n * A safe localStorage wrapper that falls back to noopStorage\n * when localStorage is not available (e.g., during SSR).\n * Includes cross-tab sync via the native 'storage' event.\n *\n * Lazily initialized on first access to be SSR-safe.\n */\nexport const getSafeLocalStorage = (): SyncableStorage => {\n\tif (_safeLocalStorage === null) {\n\t\t_safeLocalStorage = createSafeLocalStorage();\n\t}\n\treturn _safeLocalStorage;\n};\n\n/**\n * @deprecated Use getSafeLocalStorage() instead. This is kept for backward compatibility.\n * Returns a proxy that lazily initializes on first method call.\n */\nexport const safeLocalStorage: SyncableStorage = {\n\tgetItem: (key: string) => getSafeLocalStorage().getItem(key),\n\tsetItem: (key: string, value: string) =>\n\t\tgetSafeLocalStorage().setItem(key, value),\n\tremoveItem: (key: string) => getSafeLocalStorage().removeItem(key),\n\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\tconst storage = getSafeLocalStorage();\n\t\treturn storage.subscribe?.(key, callback) ?? (() => {});\n\t},\n};\n\n/**\n * Parse a cookie string to extract the value for a specific key.\n * @param cookieString - The full cookie header string (e.g., document.cookie or req.headers.cookie)\n * @param key - The cookie key to find\n * @returns The cookie value or null if not found\n */\nexport const parseCookie = (\n\tcookieString: string | undefined,\n\tkey: string,\n): string | null => {\n\tif (!cookieString) return null;\n\n\tfor (const cookie of cookieString.split(\";\")) {\n\t\tconst [k, ...v] = cookie.split(\"=\");\n\t\tconst cookieKey = k?.trim();\n\t\tif (cookieKey === key) {\n\t\t\ttry {\n\t\t\t\treturn decodeURIComponent(v.join(\"=\").trim());\n\t\t\t} catch {\n\t\t\t\treturn null; // Malformed cookie value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n};\n\n/**\n * Maximum recommended size for cookie storage (3KB to stay well under 4KB limit).\n *\n * @remarks\n * Cookie storage is subject to browser limits (typically 4KB per cookie).\n * When users connect many wallets, the auto-reconnect list may exceed this limit.\n * If this happens:\n * - A console warning will be logged\n * - Some browsers may silently reject the cookie\n * - Consider using fewer simultaneous wallet connections\n *\n * The stored data includes wallet IDs in format `platform:identifier`\n * (e.g., `polkadot:talisman`, `ethereum:io.metamask`).\n */\nexport const COOKIE_MAX_SIZE = 3 * 1024;\n\n/**\n * BroadcastChannel name for cross-tab cookie sync.\n */\nconst BROADCAST_CHANNEL_NAME = \"kheopskit-storage-sync\";\n\n/**\n * Singleton BroadcastChannel for cross-tab cookie sync.\n * Created once and shared across all cookieStorage instances.\n */\nlet sharedBroadcastChannel: BroadcastChannel | null = null;\n\nconst getBroadcastChannel = (): BroadcastChannel | null => {\n\tif (sharedBroadcastChannel) return sharedBroadcastChannel;\n\tif (typeof BroadcastChannel === \"undefined\") return null;\n\n\ttry {\n\t\tsharedBroadcastChannel = new BroadcastChannel(BROADCAST_CHANNEL_NAME);\n\t} catch {\n\t\t// BroadcastChannel not supported or failed\n\t}\n\treturn sharedBroadcastChannel;\n};\n\n/**\n * Check if the current connection is secure (HTTPS).\n * Must be called at runtime (inside methods) to work correctly after SSR hydration.\n */\nconst isSecureConnection = (): boolean =>\n\ttypeof window !== \"undefined\" && window.location.protocol === \"https:\";\n\n/**\n * A cookie-based storage implementation for SSR environments.\n * Reads cookies from an optional initial cookie string (for SSR hydration),\n * writes to document.cookie on the client.\n *\n * Features:\n * - Secure flag automatically added for HTTPS connections\n * - Cross-tab synchronization via BroadcastChannel API\n * - Size limit warning when data exceeds recommended limits\n *\n * @param initialCookies - Optional cookie string for server-side hydration\n */\nexport const cookieStorage = (initialCookies?: string): SyncableStorage => {\n\treturn {\n\t\tgetItem: (key: string) => {\n\t\t\t// On server, use initialCookies. On client, read from document.cookie\n\t\t\tconst cookieString =\n\t\t\t\ttypeof document !== \"undefined\" ? document.cookie : initialCookies;\n\t\t\treturn parseCookie(cookieString, key);\n\t\t},\n\t\tsetItem: (key: string, value: string) => {\n\t\t\tif (typeof document === \"undefined\") return;\n\n\t\t\t// Warn if value exceeds recommended size\n\t\t\tconst encodedValue = encodeURIComponent(value);\n\t\t\tif (encodedValue.length > COOKIE_MAX_SIZE) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[kheopskit] Cookie value for \"${key}\" exceeds recommended size limit (${encodedValue.length} > ${COOKIE_MAX_SIZE} bytes). ` +\n\t\t\t\t\t\t\"This may cause issues with cookie storage. Consider reducing the number of connected wallets.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Set cookie with 1 year expiry\n\t\t\tconst expires = new Date();\n\t\t\texpires.setFullYear(expires.getFullYear() + 1);\n\n\t\t\t// Build cookie string with security attributes\n\t\t\tlet cookieStr = `${key}=${encodedValue};expires=${expires.toUTCString()};path=/;SameSite=Lax`;\n\t\t\tif (isSecureConnection()) {\n\t\t\t\tcookieStr += \";Secure\";\n\t\t\t}\n\n\t\t\t// biome-ignore lint: necessary for cookie storage - direct cookie assignment is the standard API\n\t\t\tdocument.cookie = cookieStr;\n\n\t\t\t// Broadcast change to other tabs\n\t\t\tgetBroadcastChannel()?.postMessage({ type: \"set\", key, value });\n\t\t},\n\t\tremoveItem: (key: string) => {\n\t\t\tif (typeof document === \"undefined\") return;\n\n\t\t\t// Build delete cookie string\n\t\t\tlet cookieStr = `${key}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/;SameSite=Lax`;\n\t\t\tif (isSecureConnection()) {\n\t\t\t\tcookieStr += \";Secure\";\n\t\t\t}\n\n\t\t\t// biome-ignore lint: necessary for cookie storage - direct cookie assignment is the standard API\n\t\t\tdocument.cookie = cookieStr;\n\n\t\t\t// Broadcast change to other tabs\n\t\t\tgetBroadcastChannel()?.postMessage({ type: \"remove\", key });\n\t\t},\n\t\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\t\tconst channel = getBroadcastChannel();\n\t\t\tif (!channel) return () => {};\n\n\t\t\tconst handler = (event: MessageEvent) => {\n\t\t\t\tconst data = event.data as {\n\t\t\t\t\ttype: string;\n\t\t\t\t\tkey: string;\n\t\t\t\t\tvalue?: string;\n\t\t\t\t};\n\t\t\t\tif (data.key === key) {\n\t\t\t\t\tif (data.type === \"set\") {\n\t\t\t\t\t\tcallback(data.value ?? null);\n\t\t\t\t\t} else if (data.type === \"remove\") {\n\t\t\t\t\t\tcallback(null);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tchannel.addEventListener(\"message\", handler);\n\t\t\treturn () => {\n\t\t\t\tchannel.removeEventListener(\"message\", handler);\n\t\t\t};\n\t\t},\n\t};\n};\n\n/**\n * Cleanup the shared BroadcastChannel used for cross-tab cookie sync.\n * Call this when you're done using cookie storage (e.g., in tests or when unmounting).\n *\n * @remarks\n * In normal browser usage, you typically don't need to call this -\n * the channel will be cleaned up when the page is closed.\n * This is primarily useful for testing environments where multiple\n * test runs may accumulate channels.\n */\nexport const cleanupBroadcastChannel = (): void => {\n\tif (sharedBroadcastChannel) {\n\t\tsharedBroadcastChannel.close();\n\t\tsharedBroadcastChannel = null;\n\t}\n};\n","import { safeLocalStorage } from \"./storage\";\n\n/**\n * Storage key for the icon cache in localStorage.\n */\nconst ICON_CACHE_KEY = \"kheopskit-icons\";\n\n/**\n * Icon cache type: a map of wallet ID to icon data URI or URL.\n */\ntype IconCache = Record<string, string>;\n\n/**\n * In-memory cache to avoid repeated localStorage reads.\n */\nlet memoryCache: IconCache | null = null;\n\n/**\n * Loads the icon cache from localStorage.\n */\nconst loadCache = (): IconCache => {\n\tif (memoryCache !== null) return memoryCache;\n\n\ttry {\n\t\tconst stored = safeLocalStorage.getItem(ICON_CACHE_KEY);\n\t\tmemoryCache = stored ? (JSON.parse(stored) as IconCache) : {};\n\t} catch {\n\t\tmemoryCache = {};\n\t}\n\treturn memoryCache;\n};\n\n/**\n * Saves the icon cache to localStorage.\n */\nconst saveCache = (cache: IconCache): void => {\n\ttry {\n\t\tsafeLocalStorage.setItem(ICON_CACHE_KEY, JSON.stringify(cache));\n\t\tmemoryCache = cache;\n\t} catch {\n\t\t// localStorage may be full or unavailable\n\t}\n};\n\n/**\n * Gets a cached icon for a wallet.\n * @param walletId - The wallet ID (e.g., \"ethereum:io.talisman\")\n * @returns The cached icon data URI, or undefined if not cached\n */\nexport const getCachedIcon = (walletId: string): string | undefined => {\n\tconst cache = loadCache();\n\treturn cache[walletId] || undefined;\n};\n\n/**\n * Sets multiple cached icons at once.\n * More efficient than calling setCachedIcon multiple times.\n * @param icons - Map of wallet ID to icon\n */\nexport const setCachedIcons = (icons: Record<string, string>): void => {\n\tconst cache = loadCache();\n\tlet changed = false;\n\n\tfor (const [walletId, icon] of Object.entries(icons)) {\n\t\tif (icon && cache[walletId] !== icon) {\n\t\t\tcache[walletId] = icon;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\tif (changed) {\n\t\tsaveCache(cache);\n\t}\n};\n"],"mappings":"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"}
|
|
@@ -63,7 +63,7 @@ const hydrateWallet = (cached) => {
|
|
|
63
63
|
* plain, serializable platform data that lives in the cache — Ethereum `chainId`
|
|
64
64
|
* and the Polkadot key `type`. Those render immediately on reload (no blank →
|
|
65
65
|
* value flicker) and match what the live account will report. Only the SDK
|
|
66
|
-
* handles (`client`/`signer`/`
|
|
66
|
+
* handles (`client`/`signer`/`txCreator`) are absent until the real account
|
|
67
67
|
* replaces this placeholder; signing stays gated on `isHydrating` until then.
|
|
68
68
|
*/
|
|
69
69
|
const hydrateAccount = (cached) => ({
|
|
@@ -340,4 +340,4 @@ const setCachedIcons = (icons) => {
|
|
|
340
340
|
//#endregion
|
|
341
341
|
export { safeLocalStorage as a, serializeAccount as c, getSafeLocalStorage as i, serializeWallet as l, setCachedIcons as n, hydrateAccount as o, cookieStorage as r, hydrateWallet as s, getCachedIcon as t };
|
|
342
342
|
|
|
343
|
-
//# sourceMappingURL=iconCache-
|
|
343
|
+
//# sourceMappingURL=iconCache-Cml-6Rft.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iconCache-Cml-6Rft.mjs","names":[],"sources":["../src/utils/hydrateState.ts","../src/utils/storage.ts","../src/utils/iconCache.ts"],"sourcesContent":["import {\n\ttype BaseWallet,\n\ttype BaseWalletAccount,\n\ttype CachedAccount,\n\ttype CachedWallet,\n\tisWalletConnectWallet,\n\ttype PolkadotAccountType,\n\ttype WalletConnectWallet,\n} from \"../api/types\";\nimport { POLKADOT_EXTENSIONS } from \"./polkadotExtensions\";\nimport type { WalletAccountId } from \"./WalletAccountId\";\nimport { parseWalletId, type WalletId } from \"./WalletId\";\n\n/**\n * Looks up the icon for a wallet from known Polkadot extensions only.\n * Ethereum icons will be populated from the localStorage icon cache via the merge function.\n *\n * Note: We DON'T use localStorage icon cache here because hydrateWallet is called\n * during SSR (server) and client hydration. localStorage isn't available on server,\n * so using it would cause a hydration mismatch. Icons for Ethereum wallets will be\n * populated when the hydration buffer merges cached wallets with live wallets.\n */\nconst lookupWalletIcon = (platform: string, identifier: string): string => {\n\t// Only Polkadot extensions have hardcoded icons that are safe for SSR\n\tif (platform === \"polkadot\") {\n\t\treturn POLKADOT_EXTENSIONS[identifier]?.icon ?? \"\";\n\t}\n\t// Ethereum icons come from localStorage or live wallets - not here\n\treturn \"\";\n};\n\n/**\n * Error thrown when trying to use a placeholder wallet that hasn't fully loaded yet.\n */\nclass PendingWalletError extends Error {\n\tconstructor(walletId: string) {\n\t\tsuper(\n\t\t\t`Wallet ${walletId} is still loading. Wait for isHydrating to be false before calling connect/disconnect.`,\n\t\t);\n\t\tthis.name = \"PendingWalletError\";\n\t}\n}\n\n/**\n * Converts a CachedWallet to a placeholder wallet for SSR hydration display.\n *\n * The placeholder carries only the SDK-free {@link BaseWallet} fields; the real\n * wallet (with its injected provider/extension/standard-wallet handle) replaces\n * it once it loads. connect/disconnect throw until then.\n */\nexport const hydrateWallet = (\n\tcached: CachedWallet,\n): BaseWallet | WalletConnectWallet => {\n\tconst throwPending = () => {\n\t\tthrow new PendingWalletError(cached.id);\n\t};\n\n\t// The platform-less WalletConnect connector. `appKit`/`platforms` are SDK\n\t// state absent until the live connector loads (cast like other placeholder\n\t// SDK handles); icon is filled from the localStorage cache by the caller.\n\tif (cached.type === \"walletconnect\") {\n\t\treturn {\n\t\t\tid: cached.id,\n\t\t\ttype: \"walletconnect\",\n\t\t\tplatforms: [],\n\t\t\tname: cached.name,\n\t\t\ticon: \"\",\n\t\t\tisConnected: cached.isConnected,\n\t\t\tconnect: throwPending,\n\t\t\tdisconnect: throwPending,\n\t\t} as unknown as WalletConnectWallet;\n\t}\n\n\tconst { platform, identifier } = parseWalletId(cached.id);\n\n\treturn {\n\t\tid: cached.id,\n\t\tplatform: cached.platform as BaseWallet[\"platform\"],\n\t\ttype: cached.type,\n\t\tname: cached.name,\n\t\ticon: lookupWalletIcon(platform, identifier),\n\t\tisConnected: cached.isConnected,\n\t\tconnect: throwPending,\n\t\tdisconnect: throwPending,\n\t};\n};\n\n/**\n * Converts a CachedAccount to a placeholder account for SSR hydration display.\n *\n * The placeholder carries the SDK-free {@link BaseWalletAccount} fields plus the\n * plain, serializable platform data that lives in the cache — Ethereum `chainId`\n * and the Polkadot key `type`. Those render immediately on reload (no blank →\n * value flicker) and match what the live account will report. Only the SDK\n * handles (`client`/`signer`/`txCreator`) are absent until the real account\n * replaces this placeholder; signing stays gated on `isHydrating` until then.\n */\nexport const hydrateAccount = (cached: CachedAccount): BaseWalletAccount => ({\n\tid: cached.id as WalletAccountId,\n\tplatform: cached.platform,\n\taddress: cached.address,\n\tname: cached.name,\n\twalletId: cached.walletId,\n\twalletName: cached.walletName,\n\t// Spread (not direct keys) so the extra platform fields don't trip the\n\t// excess-property check against BaseWalletAccount; they're read back via the\n\t// platform-specific account types once narrowed by `platform`.\n\t...(cached.platform === \"ethereum\" && { chainId: cached.chainId }),\n\t...(cached.platform === \"polkadot\" && {\n\t\ttype: cached.polkadotAccountType,\n\t}),\n});\n\n/**\n * Converts a wallet to a CachedWallet for storage.\n * Only extracts the serializable properties needed for hydration.\n */\nexport const serializeWallet = (\n\twallet: BaseWallet | WalletConnectWallet,\n): CachedWallet => ({\n\tid: wallet.id,\n\t// The WalletConnect connector has no platform.\n\tplatform: isWalletConnectWallet(wallet) ? undefined : wallet.platform,\n\ttype: wallet.type,\n\tname: wallet.name,\n\t// Note: icon is NOT stored to save cookie space\n\tisConnected: wallet.isConnected,\n});\n\n/**\n * Converts an account to a CachedAccount for storage.\n * Only extracts the serializable properties needed for hydration. Platform-only\n * fields (Ethereum chainId, Polkadot key type) are read defensively so this\n * stays SDK-free.\n */\nexport const serializeAccount = (\n\taccount: BaseWalletAccount,\n): CachedAccount => ({\n\tid: account.id,\n\tplatform: account.platform,\n\taddress: account.address,\n\tname: account.name,\n\tchainId:\n\t\taccount.platform === \"ethereum\"\n\t\t\t? (account as { chainId?: number }).chainId\n\t\t\t: undefined,\n\tpolkadotAccountType:\n\t\taccount.platform === \"polkadot\"\n\t\t\t? (account as { type?: PolkadotAccountType }).type\n\t\t\t: undefined,\n\twalletId: account.walletId as WalletId,\n\twalletName: account.walletName,\n});\n","export type Storage = {\n\tgetItem: (key: string) => string | null;\n\tsetItem: (key: string, value: string) => void;\n\tremoveItem: (key: string) => void;\n};\n\n/**\n * Extended storage interface with cross-tab sync support.\n */\nexport type SyncableStorage = Storage & {\n\t/**\n\t * Subscribe to storage changes from other tabs.\n\t * Returns an unsubscribe function.\n\t */\n\tsubscribe?: (\n\t\tkey: string,\n\t\tcallback: (value: string | null) => void,\n\t) => () => void;\n};\n\n/**\n * A no-op storage implementation that does nothing.\n * Useful for testing or SSR environments where no storage is needed.\n */\nexport const noopStorage: SyncableStorage = {\n\tgetItem: () => null,\n\tsetItem: () => {},\n\tremoveItem: () => {},\n};\n\n/**\n * Cached localStorage wrapper instance.\n * Lazily initialized on first access to avoid SSR issues.\n */\nlet _safeLocalStorage: SyncableStorage | null = null;\n\n/**\n * Creates the localStorage wrapper, testing for availability.\n * Returns noopStorage if localStorage is unavailable (SSR, private browsing, etc.)\n */\nconst createSafeLocalStorage = (): SyncableStorage => {\n\tif (typeof window === \"undefined\") return noopStorage;\n\n\ttry {\n\t\t// Test that localStorage is accessible (may throw in private browsing)\n\t\tconst testKey = \"__kheopskit_test__\";\n\t\twindow.localStorage.setItem(testKey, testKey);\n\t\twindow.localStorage.removeItem(testKey);\n\n\t\treturn {\n\t\t\tgetItem: (key: string) => window.localStorage.getItem(key),\n\t\t\tsetItem: (key: string, value: string) =>\n\t\t\t\twindow.localStorage.setItem(key, value),\n\t\t\tremoveItem: (key: string) => window.localStorage.removeItem(key),\n\t\t\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\t\t\tconst handler = (event: StorageEvent) => {\n\t\t\t\t\tif (event.key === key) {\n\t\t\t\t\t\tcallback(event.newValue);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\twindow.addEventListener(\"storage\", handler);\n\t\t\t\treturn () => window.removeEventListener(\"storage\", handler);\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn noopStorage;\n\t}\n};\n\n/**\n * A safe localStorage wrapper that falls back to noopStorage\n * when localStorage is not available (e.g., during SSR).\n * Includes cross-tab sync via the native 'storage' event.\n *\n * Lazily initialized on first access to be SSR-safe.\n */\nexport const getSafeLocalStorage = (): SyncableStorage => {\n\tif (_safeLocalStorage === null) {\n\t\t_safeLocalStorage = createSafeLocalStorage();\n\t}\n\treturn _safeLocalStorage;\n};\n\n/**\n * @deprecated Use getSafeLocalStorage() instead. This is kept for backward compatibility.\n * Returns a proxy that lazily initializes on first method call.\n */\nexport const safeLocalStorage: SyncableStorage = {\n\tgetItem: (key: string) => getSafeLocalStorage().getItem(key),\n\tsetItem: (key: string, value: string) =>\n\t\tgetSafeLocalStorage().setItem(key, value),\n\tremoveItem: (key: string) => getSafeLocalStorage().removeItem(key),\n\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\tconst storage = getSafeLocalStorage();\n\t\treturn storage.subscribe?.(key, callback) ?? (() => {});\n\t},\n};\n\n/**\n * Parse a cookie string to extract the value for a specific key.\n * @param cookieString - The full cookie header string (e.g., document.cookie or req.headers.cookie)\n * @param key - The cookie key to find\n * @returns The cookie value or null if not found\n */\nexport const parseCookie = (\n\tcookieString: string | undefined,\n\tkey: string,\n): string | null => {\n\tif (!cookieString) return null;\n\n\tfor (const cookie of cookieString.split(\";\")) {\n\t\tconst [k, ...v] = cookie.split(\"=\");\n\t\tconst cookieKey = k?.trim();\n\t\tif (cookieKey === key) {\n\t\t\ttry {\n\t\t\t\treturn decodeURIComponent(v.join(\"=\").trim());\n\t\t\t} catch {\n\t\t\t\treturn null; // Malformed cookie value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n};\n\n/**\n * Maximum recommended size for cookie storage (3KB to stay well under 4KB limit).\n *\n * @remarks\n * Cookie storage is subject to browser limits (typically 4KB per cookie).\n * When users connect many wallets, the auto-reconnect list may exceed this limit.\n * If this happens:\n * - A console warning will be logged\n * - Some browsers may silently reject the cookie\n * - Consider using fewer simultaneous wallet connections\n *\n * The stored data includes wallet IDs in format `platform:identifier`\n * (e.g., `polkadot:talisman`, `ethereum:io.metamask`).\n */\nexport const COOKIE_MAX_SIZE = 3 * 1024;\n\n/**\n * BroadcastChannel name for cross-tab cookie sync.\n */\nconst BROADCAST_CHANNEL_NAME = \"kheopskit-storage-sync\";\n\n/**\n * Singleton BroadcastChannel for cross-tab cookie sync.\n * Created once and shared across all cookieStorage instances.\n */\nlet sharedBroadcastChannel: BroadcastChannel | null = null;\n\nconst getBroadcastChannel = (): BroadcastChannel | null => {\n\tif (sharedBroadcastChannel) return sharedBroadcastChannel;\n\tif (typeof BroadcastChannel === \"undefined\") return null;\n\n\ttry {\n\t\tsharedBroadcastChannel = new BroadcastChannel(BROADCAST_CHANNEL_NAME);\n\t} catch {\n\t\t// BroadcastChannel not supported or failed\n\t}\n\treturn sharedBroadcastChannel;\n};\n\n/**\n * Check if the current connection is secure (HTTPS).\n * Must be called at runtime (inside methods) to work correctly after SSR hydration.\n */\nconst isSecureConnection = (): boolean =>\n\ttypeof window !== \"undefined\" && window.location.protocol === \"https:\";\n\n/**\n * A cookie-based storage implementation for SSR environments.\n * Reads cookies from an optional initial cookie string (for SSR hydration),\n * writes to document.cookie on the client.\n *\n * Features:\n * - Secure flag automatically added for HTTPS connections\n * - Cross-tab synchronization via BroadcastChannel API\n * - Size limit warning when data exceeds recommended limits\n *\n * @param initialCookies - Optional cookie string for server-side hydration\n */\nexport const cookieStorage = (initialCookies?: string): SyncableStorage => {\n\treturn {\n\t\tgetItem: (key: string) => {\n\t\t\t// On server, use initialCookies. On client, read from document.cookie\n\t\t\tconst cookieString =\n\t\t\t\ttypeof document !== \"undefined\" ? document.cookie : initialCookies;\n\t\t\treturn parseCookie(cookieString, key);\n\t\t},\n\t\tsetItem: (key: string, value: string) => {\n\t\t\tif (typeof document === \"undefined\") return;\n\n\t\t\t// Warn if value exceeds recommended size\n\t\t\tconst encodedValue = encodeURIComponent(value);\n\t\t\tif (encodedValue.length > COOKIE_MAX_SIZE) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[kheopskit] Cookie value for \"${key}\" exceeds recommended size limit (${encodedValue.length} > ${COOKIE_MAX_SIZE} bytes). ` +\n\t\t\t\t\t\t\"This may cause issues with cookie storage. Consider reducing the number of connected wallets.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Set cookie with 1 year expiry\n\t\t\tconst expires = new Date();\n\t\t\texpires.setFullYear(expires.getFullYear() + 1);\n\n\t\t\t// Build cookie string with security attributes\n\t\t\tlet cookieStr = `${key}=${encodedValue};expires=${expires.toUTCString()};path=/;SameSite=Lax`;\n\t\t\tif (isSecureConnection()) {\n\t\t\t\tcookieStr += \";Secure\";\n\t\t\t}\n\n\t\t\t// biome-ignore lint: necessary for cookie storage - direct cookie assignment is the standard API\n\t\t\tdocument.cookie = cookieStr;\n\n\t\t\t// Broadcast change to other tabs\n\t\t\tgetBroadcastChannel()?.postMessage({ type: \"set\", key, value });\n\t\t},\n\t\tremoveItem: (key: string) => {\n\t\t\tif (typeof document === \"undefined\") return;\n\n\t\t\t// Build delete cookie string\n\t\t\tlet cookieStr = `${key}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/;SameSite=Lax`;\n\t\t\tif (isSecureConnection()) {\n\t\t\t\tcookieStr += \";Secure\";\n\t\t\t}\n\n\t\t\t// biome-ignore lint: necessary for cookie storage - direct cookie assignment is the standard API\n\t\t\tdocument.cookie = cookieStr;\n\n\t\t\t// Broadcast change to other tabs\n\t\t\tgetBroadcastChannel()?.postMessage({ type: \"remove\", key });\n\t\t},\n\t\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\t\tconst channel = getBroadcastChannel();\n\t\t\tif (!channel) return () => {};\n\n\t\t\tconst handler = (event: MessageEvent) => {\n\t\t\t\tconst data = event.data as {\n\t\t\t\t\ttype: string;\n\t\t\t\t\tkey: string;\n\t\t\t\t\tvalue?: string;\n\t\t\t\t};\n\t\t\t\tif (data.key === key) {\n\t\t\t\t\tif (data.type === \"set\") {\n\t\t\t\t\t\tcallback(data.value ?? null);\n\t\t\t\t\t} else if (data.type === \"remove\") {\n\t\t\t\t\t\tcallback(null);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tchannel.addEventListener(\"message\", handler);\n\t\t\treturn () => {\n\t\t\t\tchannel.removeEventListener(\"message\", handler);\n\t\t\t};\n\t\t},\n\t};\n};\n\n/**\n * Cleanup the shared BroadcastChannel used for cross-tab cookie sync.\n * Call this when you're done using cookie storage (e.g., in tests or when unmounting).\n *\n * @remarks\n * In normal browser usage, you typically don't need to call this -\n * the channel will be cleaned up when the page is closed.\n * This is primarily useful for testing environments where multiple\n * test runs may accumulate channels.\n */\nexport const cleanupBroadcastChannel = (): void => {\n\tif (sharedBroadcastChannel) {\n\t\tsharedBroadcastChannel.close();\n\t\tsharedBroadcastChannel = null;\n\t}\n};\n","import { safeLocalStorage } from \"./storage\";\n\n/**\n * Storage key for the icon cache in localStorage.\n */\nconst ICON_CACHE_KEY = \"kheopskit-icons\";\n\n/**\n * Icon cache type: a map of wallet ID to icon data URI or URL.\n */\ntype IconCache = Record<string, string>;\n\n/**\n * In-memory cache to avoid repeated localStorage reads.\n */\nlet memoryCache: IconCache | null = null;\n\n/**\n * Loads the icon cache from localStorage.\n */\nconst loadCache = (): IconCache => {\n\tif (memoryCache !== null) return memoryCache;\n\n\ttry {\n\t\tconst stored = safeLocalStorage.getItem(ICON_CACHE_KEY);\n\t\tmemoryCache = stored ? (JSON.parse(stored) as IconCache) : {};\n\t} catch {\n\t\tmemoryCache = {};\n\t}\n\treturn memoryCache;\n};\n\n/**\n * Saves the icon cache to localStorage.\n */\nconst saveCache = (cache: IconCache): void => {\n\ttry {\n\t\tsafeLocalStorage.setItem(ICON_CACHE_KEY, JSON.stringify(cache));\n\t\tmemoryCache = cache;\n\t} catch {\n\t\t// localStorage may be full or unavailable\n\t}\n};\n\n/**\n * Gets a cached icon for a wallet.\n * @param walletId - The wallet ID (e.g., \"ethereum:io.talisman\")\n * @returns The cached icon data URI, or undefined if not cached\n */\nexport const getCachedIcon = (walletId: string): string | undefined => {\n\tconst cache = loadCache();\n\treturn cache[walletId] || undefined;\n};\n\n/**\n * Sets multiple cached icons at once.\n * More efficient than calling setCachedIcon multiple times.\n * @param icons - Map of wallet ID to icon\n */\nexport const setCachedIcons = (icons: Record<string, string>): void => {\n\tconst cache = loadCache();\n\tlet changed = false;\n\n\tfor (const [walletId, icon] of Object.entries(icons)) {\n\t\tif (icon && cache[walletId] !== icon) {\n\t\t\tcache[walletId] = icon;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\tif (changed) {\n\t\tsaveCache(cache);\n\t}\n};\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -37,6 +37,8 @@ type KheopskitErrorCode =
|
|
|
37
37
|
"NO_SESSION" |
|
|
38
38
|
/** No provider available for the requested namespace. */
|
|
39
39
|
"NO_PROVIDER" |
|
|
40
|
+
/** The installed polkadot-api version exposes neither `getTxCreatorFromPjs` (v3) nor `getPolkadotSignerFromPjs` (v2). */
|
|
41
|
+
"UNSUPPORTED_VERSION" |
|
|
40
42
|
/** The requested chain cannot be used for this operation (e.g. a Solana cluster with no CAIP-2 id over WalletConnect). */
|
|
41
43
|
"UNSUPPORTED_CHAIN";
|
|
42
44
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ type KheopskitErrorCode =
|
|
|
37
37
|
"NO_SESSION" |
|
|
38
38
|
/** No provider available for the requested namespace. */
|
|
39
39
|
"NO_PROVIDER" |
|
|
40
|
+
/** The installed polkadot-api version exposes neither `getTxCreatorFromPjs` (v3) nor `getPolkadotSignerFromPjs` (v2). */
|
|
41
|
+
"UNSUPPORTED_VERSION" |
|
|
40
42
|
/** The requested chain cannot be used for this operation (e.g. a Solana cluster with no CAIP-2 id over WalletConnect). */
|
|
41
43
|
"UNSUPPORTED_CHAIN";
|
|
42
44
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_types = require("./types-DKU-SNio.js");
|
|
3
3
|
const require_errors = require("./errors-DPw6pc2H.js");
|
|
4
|
-
const require_iconCache = require("./iconCache-
|
|
4
|
+
const require_iconCache = require("./iconCache-CicUSbR1.js");
|
|
5
5
|
let rxjs = require("rxjs");
|
|
6
6
|
let lodash_es = require("lodash-es");
|
|
7
7
|
//#region src/api/appKit.ts
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as isValidWalletId, c as clearAllCachedObservables, i as getWalletId, n as isWalletConnectWallet, o as parseWalletId, r as WALLET_CONNECT_WALLET_ID, s as isWalletPlatform, t as isInjectedWallet, u as clearCachedObservablesByPrefix } from "./types-jnifAAA0.mjs";
|
|
2
2
|
import { i as isValidAddress, n as getWalletAccountId, r as parseWalletAccountId, t as KheopskitError } from "./errors-Caq2csKx.mjs";
|
|
3
|
-
import { a as safeLocalStorage, c as serializeAccount, l as serializeWallet, n as setCachedIcons, o as hydrateAccount, r as cookieStorage, s as hydrateWallet, t as getCachedIcon } from "./iconCache-
|
|
3
|
+
import { a as safeLocalStorage, c as serializeAccount, l as serializeWallet, n as setCachedIcons, o as hydrateAccount, r as cookieStorage, s as hydrateWallet, t as getCachedIcon } from "./iconCache-Cml-6Rft.mjs";
|
|
4
4
|
import { BehaviorSubject, Observable, Subscription, combineLatest, debounceTime, distinctUntilChanged, filter, from, map, mergeMap, of, shareReplay, startWith, switchMap, take, tap, throttleTime, timer } from "rxjs";
|
|
5
5
|
import { uniq } from "lodash-es";
|
|
6
6
|
//#region src/api/appKit.ts
|
package/dist/internal.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_types = require("./types-DKU-SNio.js");
|
|
3
|
-
const require_iconCache = require("./iconCache-
|
|
3
|
+
const require_iconCache = require("./iconCache-CicUSbR1.js");
|
|
4
4
|
exports.clearCachedObservable = require_types.clearCachedObservable;
|
|
5
5
|
exports.clearCachedObservablesByPrefix = require_types.clearCachedObservablesByPrefix;
|
|
6
6
|
exports.getSafeLocalStorage = require_iconCache.getSafeLocalStorage;
|
package/dist/internal.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { l as clearCachedObservable, u as clearCachedObservablesByPrefix } from "./types-jnifAAA0.mjs";
|
|
2
|
-
import { c as serializeAccount, i as getSafeLocalStorage, l as serializeWallet, n as setCachedIcons } from "./iconCache-
|
|
2
|
+
import { c as serializeAccount, i as getSafeLocalStorage, l as serializeWallet, n as setCachedIcons } from "./iconCache-Cml-6Rft.mjs";
|
|
3
3
|
export { clearCachedObservable, clearCachedObservablesByPrefix, getSafeLocalStorage, serializeAccount, serializeWallet, setCachedIcons };
|
package/dist/polkadot.d.mts
CHANGED
|
@@ -31,12 +31,15 @@ type PolkadotInjectedWallet = {
|
|
|
31
31
|
type PolkadotWallet = PolkadotInjectedWallet;
|
|
32
32
|
/**
|
|
33
33
|
* A Polkadot account. Inherits the fields of polkadot-api's
|
|
34
|
-
* `InjectedPolkadotAccount`
|
|
35
|
-
*
|
|
34
|
+
* `InjectedPolkadotAccount` and narrows `type` to {@link PolkadotAccountType}.
|
|
35
|
+
*
|
|
36
|
+
* The signing surface follows the installed polkadot-api version:
|
|
37
|
+
* **`txCreator`** (a `TxCreator`) on v3+, **`polkadotSigner`** (a
|
|
38
|
+
* `PolkadotSigner`) on v2.
|
|
36
39
|
*
|
|
37
40
|
* Per-platform signing surfaces differ: Ethereum exposes `client` (viem),
|
|
38
|
-
* Solana `signer`/`getSigner(chain)`.
|
|
39
|
-
* `state.isHydrating` is `true`.
|
|
41
|
+
* Solana `signer`/`getSigner(chain)`. The Polkadot signing surface is absent
|
|
42
|
+
* while `state.isHydrating` is `true`.
|
|
40
43
|
*/
|
|
41
44
|
type PolkadotAccount = Omit<InjectedPolkadotAccount, "type"> & {
|
|
42
45
|
type: PolkadotAccountType;
|
package/dist/polkadot.d.ts
CHANGED
|
@@ -31,12 +31,15 @@ type PolkadotInjectedWallet = {
|
|
|
31
31
|
type PolkadotWallet = PolkadotInjectedWallet;
|
|
32
32
|
/**
|
|
33
33
|
* A Polkadot account. Inherits the fields of polkadot-api's
|
|
34
|
-
* `InjectedPolkadotAccount`
|
|
35
|
-
*
|
|
34
|
+
* `InjectedPolkadotAccount` and narrows `type` to {@link PolkadotAccountType}.
|
|
35
|
+
*
|
|
36
|
+
* The signing surface follows the installed polkadot-api version:
|
|
37
|
+
* **`txCreator`** (a `TxCreator`) on v3+, **`polkadotSigner`** (a
|
|
38
|
+
* `PolkadotSigner`) on v2.
|
|
36
39
|
*
|
|
37
40
|
* Per-platform signing surfaces differ: Ethereum exposes `client` (viem),
|
|
38
|
-
* Solana `signer`/`getSigner(chain)`.
|
|
39
|
-
* `state.isHydrating` is `true`.
|
|
41
|
+
* Solana `signer`/`getSigner(chain)`. The Polkadot signing surface is absent
|
|
42
|
+
* while `state.isHydrating` is `true`.
|
|
40
43
|
*/
|
|
41
44
|
type PolkadotAccount = Omit<InjectedPolkadotAccount, "type"> & {
|
|
42
45
|
type: PolkadotAccountType;
|
package/dist/polkadot.js
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
2
24
|
const require_types = require("./types-DKU-SNio.js");
|
|
3
25
|
const require_errors = require("./errors-DPw6pc2H.js");
|
|
4
26
|
const require_polkadotExtensions = require("./polkadotExtensions-y4J9UzYl.js");
|
|
@@ -6,6 +28,7 @@ const require_injectedWallets = require("./injectedWallets-B1MCxAE9.js");
|
|
|
6
28
|
let rxjs = require("rxjs");
|
|
7
29
|
let lodash_es = require("lodash-es");
|
|
8
30
|
let polkadot_api_pjs_signer = require("polkadot-api/pjs-signer");
|
|
31
|
+
polkadot_api_pjs_signer = __toESM(polkadot_api_pjs_signer);
|
|
9
32
|
//#region src/api/polkadot/accounts.ts
|
|
10
33
|
const getInjectedWalletAccounts$ = (wallet) => {
|
|
11
34
|
if (!wallet.isConnected) return (0, rxjs.of)([]);
|
|
@@ -28,11 +51,29 @@ const getInjectedWalletAccounts$ = (wallet) => {
|
|
|
28
51
|
};
|
|
29
52
|
});
|
|
30
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* polkadot-api v3 replaced `polkadotSigner` (PolkadotSigner) with `txCreator`
|
|
56
|
+
* (TxCreator). Which one the app's installed version provides is detected at
|
|
57
|
+
* runtime so a single @kheopskit/core release supports both.
|
|
58
|
+
*/
|
|
59
|
+
const getPjsSignerField = () => {
|
|
60
|
+
const { getTxCreatorFromPjs, getPolkadotSignerFromPjs } = polkadot_api_pjs_signer;
|
|
61
|
+
if (getTxCreatorFromPjs) return {
|
|
62
|
+
field: "txCreator",
|
|
63
|
+
factory: getTxCreatorFromPjs
|
|
64
|
+
};
|
|
65
|
+
if (getPolkadotSignerFromPjs) return {
|
|
66
|
+
field: "polkadotSigner",
|
|
67
|
+
factory: getPolkadotSignerFromPjs
|
|
68
|
+
};
|
|
69
|
+
throw new require_errors.KheopskitError("UNSUPPORTED_VERSION", "Unsupported polkadot-api/pjs-signer version");
|
|
70
|
+
};
|
|
31
71
|
const getAppKitPolkadotSigner = (appKit, address) => {
|
|
32
72
|
const provider = appKit.getProvider("polkadot");
|
|
33
73
|
if (!provider) throw new require_errors.KheopskitError("NO_PROVIDER", "No provider found");
|
|
34
74
|
if (!provider.session) throw new require_errors.KheopskitError("NO_SESSION", "No session found");
|
|
35
|
-
|
|
75
|
+
const { field, factory } = getPjsSignerField();
|
|
76
|
+
const signer = factory(address, (transactionPayload) => {
|
|
36
77
|
if (!provider.session) throw new require_errors.KheopskitError("NO_SESSION", "No session found");
|
|
37
78
|
return provider.client.request({
|
|
38
79
|
topic: provider.session.topic,
|
|
@@ -61,6 +102,7 @@ const getAppKitPolkadotSigner = (appKit, address) => {
|
|
|
61
102
|
}
|
|
62
103
|
});
|
|
63
104
|
});
|
|
105
|
+
return { [field]: signer };
|
|
64
106
|
};
|
|
65
107
|
const getWalletConnectAccounts$ = (wallet) => require_injectedWallets.getWalletConnectSessionAccounts$({
|
|
66
108
|
wallet,
|
|
@@ -76,7 +118,7 @@ const getWalletConnectAccounts$ = (wallet) => require_injectedWallets.getWalletC
|
|
|
76
118
|
walletName: wallet.name,
|
|
77
119
|
walletId: wallet.id,
|
|
78
120
|
address,
|
|
79
|
-
|
|
121
|
+
...getAppKitPolkadotSigner(wallet.appKit, address),
|
|
80
122
|
genesisHash: null,
|
|
81
123
|
name: `${wallet.name} Polkadot`,
|
|
82
124
|
type: "sr25519"
|
package/dist/polkadot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"polkadot.js","names":["Observable","getWalletAccountId","KheopskitError","getWalletConnectSessionAccounts$","getCaip10Addresses","getSessionCaip10s","createPlatformAccounts$","getWalletId","Observable","isEqual","createInjectedWallets$","parseWalletId","POLKADOT_EXTENSIONS"],"sources":["../src/api/polkadot/accounts.ts","../src/api/polkadot/wallets.ts","../src/api/polkadot/plugin.ts"],"sourcesContent":["import {\n\tgetPolkadotSignerFromPjs,\n\ttype InjectedExtension,\n\ttype InjectedPolkadotAccount,\n} from \"polkadot-api/pjs-signer\";\nimport { Observable, of } from \"rxjs\";\nimport { getWalletAccountId } from \"../../utils\";\nimport { KheopskitError } from \"../errors\";\nimport {\n\tcreatePlatformAccounts$,\n\tgetCaip10Addresses,\n\tgetSessionCaip10s,\n\tgetWalletConnectSessionAccounts$,\n} from \"../platformAccounts\";\nimport type {\n\tAppKitInstance,\n\tPolkadotAccountType,\n\tWalletConnectWallet,\n} from \"../types\";\nimport type {\n\tPolkadotAccount,\n\tPolkadotInjectedWallet,\n\tPolkadotWallet,\n} from \"./types\";\n\nconst getInjectedWalletAccounts$ = (\n\twallet: PolkadotInjectedWallet,\n): Observable<PolkadotAccount[]> => {\n\tif (!wallet.isConnected) return of([]);\n\n\treturn new Observable<PolkadotAccount[]>((subscriber) => {\n\t\tconst getAccount = (account: InjectedPolkadotAccount): PolkadotAccount => ({\n\t\t\tid: getWalletAccountId(wallet.id, account.address),\n\t\t\t...account,\n\t\t\ttype: account.type ?? \"sr25519\",\n\t\t\tplatform: \"polkadot\",\n\t\t\twalletName: wallet.name,\n\t\t\twalletId: wallet.id,\n\t\t});\n\n\t\tconst extension = wallet.extension as InjectedExtension;\n\n\t\t// subscribe to changes\n\t\tconst unsubscribe = extension.subscribe((accounts) => {\n\t\t\tsubscriber.next(accounts.map(getAccount));\n\t\t});\n\n\t\t// initial value\n\t\tsubscriber.next(extension.getAccounts().map(getAccount));\n\n\t\treturn () => {\n\t\t\treturn unsubscribe();\n\t\t};\n\t});\n};\n\nconst getAppKitPolkadotSigner = (appKit: AppKitInstance, address: string) => {\n\tconst provider = appKit.getProvider(\"polkadot\");\n\tif (!provider) throw new KheopskitError(\"NO_PROVIDER\", \"No provider found\");\n\tif (!provider.session)\n\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\n\treturn getPolkadotSignerFromPjs(\n\t\taddress,\n\t\t(transactionPayload) => {\n\t\t\tif (!provider.session)\n\t\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\n\t\t\treturn provider.client.request({\n\t\t\t\ttopic: provider.session.topic,\n\t\t\t\tchainId: `polkadot:${transactionPayload.genesisHash.substring(2, 34)}`,\n\t\t\t\trequest: {\n\t\t\t\t\tmethod: \"polkadot_signTransaction\",\n\t\t\t\t\tparams: {\n\t\t\t\t\t\taddress,\n\t\t\t\t\t\ttransactionPayload,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t\tasync ({ address, data }) => {\n\t\t\tif (!provider.session)\n\t\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\t\t\tconst networks = appKit.getCaipNetworks(\"polkadot\");\n\t\t\tconst chainId = networks[0]?.caipNetworkId;\n\t\t\tif (!chainId)\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"NO_SESSION\",\n\t\t\t\t\t\"No CAIP network available for polkadot\",\n\t\t\t\t);\n\n\t\t\treturn provider.client.request({\n\t\t\t\ttopic: provider.session.topic,\n\t\t\t\tchainId,\n\t\t\t\trequest: {\n\t\t\t\t\tmethod: \"polkadot_signMessage\",\n\t\t\t\t\tparams: {\n\t\t\t\t\t\taddress,\n\t\t\t\t\t\tmessage: data,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t);\n};\n\nconst getWalletConnectAccounts$ = (\n\twallet: WalletConnectWallet,\n): Observable<PolkadotAccount[]> =>\n\tgetWalletConnectSessionAccounts$({\n\t\twallet,\n\t\tplatform: \"polkadot\",\n\t\tnamespace: \"polkadot\",\n\t\tcacheKey: `accounts:${wallet.id}:polkadot:`,\n\t\tbuildAccounts: (provider) => {\n\t\t\tconst session = provider.session;\n\t\t\tif (!session) return [];\n\n\t\t\tconst addresses = getCaip10Addresses(\n\t\t\t\tgetSessionCaip10s(session, \"polkadot\"),\n\t\t\t);\n\n\t\t\treturn addresses.map(\n\t\t\t\t(address): PolkadotAccount => ({\n\t\t\t\t\tid: getWalletAccountId(wallet.id, address),\n\t\t\t\t\tplatform: \"polkadot\",\n\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t\taddress,\n\t\t\t\t\tpolkadotSigner: getAppKitPolkadotSigner(wallet.appKit, address),\n\t\t\t\t\tgenesisHash: null,\n\t\t\t\t\tname: `${wallet.name} Polkadot`,\n\t\t\t\t\t// WalletConnect (Reown AppKit) doesn't expose account key type;\n\t\t\t\t\t// default to sr25519, which is the most common Polkadot key type.\n\t\t\t\t\ttype: \"sr25519\",\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t});\n\nexport const getPolkadotAccounts$ = (\n\tpolkadotWallets$: Observable<(PolkadotWallet | WalletConnectWallet)[]>,\n\tpolkadotAccountTypes: PolkadotAccountType[],\n) => {\n\tif (polkadotAccountTypes.length === 0) {\n\t\tconsole.warn(\n\t\t\t\"[kheopskit] config.polkadotAccountTypes is empty; all Polkadot accounts will be filtered out.\",\n\t\t);\n\t}\n\n\treturn createPlatformAccounts$({\n\t\twallets$: polkadotWallets$,\n\t\tgetInjectedAccounts$: getInjectedWalletAccounts$,\n\t\tgetWalletConnectAccounts$,\n\t\tmapAccounts: (accounts) =>\n\t\t\taccounts.filter((account) => polkadotAccountTypes.includes(account.type)),\n\t});\n};\n","import { isEqual } from \"lodash-es\";\nimport {\n\tconnectInjectedExtension,\n\tgetInjectedExtensions,\n\ttype InjectedExtension,\n} from \"polkadot-api/pjs-signer\";\nimport { distinctUntilChanged, Observable, shareReplay } from \"rxjs\";\nimport { POLKADOT_EXTENSIONS } from \"../../utils/polkadotExtensions\";\nimport {\n\tgetWalletId,\n\tparseWalletId,\n\ttype WalletId,\n} from \"../../utils/WalletId\";\nimport { createInjectedWallets$ } from \"../injectedWallets\";\nimport type { KheopskitStore } from \"../store\";\nimport type { PolkadotInjectedWallet } from \"./types\";\n\nconst getInjectedWalletsIds = () =>\n\ttypeof window === \"undefined\"\n\t\t? []\n\t\t: getInjectedExtensions().map((name) => getWalletId(\"polkadot\", name));\n\n// Create a polling observable that starts immediately and polls at intervals\nconst createWalletIdsPoller$ = () => {\n\treturn new Observable<WalletId[]>((subscriber) => {\n\t\t// Emit immediately on subscribe\n\t\tsubscriber.next(getInjectedWalletsIds());\n\n\t\t// Poll at shorter intervals initially, then slow down\n\t\tconst intervals = [100, 200, 300, 500];\n\t\tlet index = 0;\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\n\t\tconst poll = () => {\n\t\t\tsubscriber.next(getInjectedWalletsIds());\n\t\t\tif (index < intervals.length) {\n\t\t\t\tconst delay = intervals[index++];\n\t\t\t\ttimer = setTimeout(poll, delay);\n\t\t\t}\n\t\t};\n\n\t\t// Start polling after first immediate emission\n\t\tif (intervals.length > 0) {\n\t\t\ttimer = setTimeout(poll, intervals[index++] ?? 100);\n\t\t}\n\n\t\treturn () => {\n\t\t\t// Cancel any pending poll so it can't fire after unsubscribe.\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t};\n\t}).pipe(\n\t\tdistinctUntilChanged<WalletId[]>(isEqual),\n\t\tshareReplay({ refCount: true, bufferSize: 1 }),\n\t);\n};\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 getPolkadotWallets$ = (store: KheopskitStore) =>\n\tcreateInjectedWallets$<WalletId, PolkadotInjectedWallet, InjectedExtension>(\n\t\tstore,\n\t\t{\n\t\t\tsources$: createWalletIdsPoller$(),\n\t\t\tgetWalletId: (walletId) => walletId,\n\t\t\tconnect: (walletId) => {\n\t\t\t\tconst { identifier } = parseWalletId(walletId);\n\t\t\t\treturn connectInjectedExtension(identifier);\n\t\t\t},\n\t\t\tbuildWallet: ({ walletId, handle, isConnected, connect, disconnect }) => {\n\t\t\t\tconst { identifier } = parseWalletId(walletId);\n\t\t\t\tconst extInfo = POLKADOT_EXTENSIONS[identifier];\n\n\t\t\t\treturn {\n\t\t\t\t\tid: walletId,\n\t\t\t\t\ttype: \"injected\",\n\t\t\t\t\tplatform: \"polkadot\",\n\t\t\t\t\tname: extInfo?.name ?? identifier,\n\t\t\t\t\ticon: extInfo?.icon ?? \"\",\n\t\t\t\t\tsourceId: identifier,\n\t\t\t\t\textension: handle,\n\t\t\t\t\tisConnected,\n\t\t\t\t\tconnect,\n\t\t\t\t\tdisconnect,\n\t\t\t\t};\n\t\t\t},\n\t\t},\n\t);\n","import type {\n\tKheopskitPlatform,\n\tPlatformContext,\n\tPolkadotAccountType,\n} from \"../types\";\nimport { getPolkadotAccounts$ } from \"./accounts\";\nimport type { PolkadotAccount, PolkadotWallet } from \"./types\";\nimport { getPolkadotWallets$ } from \"./wallets\";\n\nconst DEFAULT_ACCOUNT_TYPES: PolkadotAccountType[] = [\n\t\"sr25519\",\n\t\"ed25519\",\n\t\"ecdsa\",\n];\n\nconst VALID_ACCOUNT_TYPES = new Set<string>([\n\t\"sr25519\",\n\t\"ed25519\",\n\t\"ecdsa\",\n\t\"ethereum\",\n]);\n\nexport type PolkadotPluginOptions = {\n\t/**\n\t * Allowed Polkadot account key types. Accounts with other key types are\n\t * filtered out from kheopskit state.\n\t *\n\t * @default [\"sr25519\", \"ed25519\", \"ecdsa\"]\n\t */\n\taccountTypes?: PolkadotAccountType[];\n};\n\n/**\n * Polkadot platform plugin. Pass to `getKheopskit$({ platforms: [polkadot()] })`.\n *\n * @example\n * ```ts\n * import { polkadot } from \"@kheopskit/core/polkadot\";\n * polkadot({ accountTypes: [\"sr25519\", \"ed25519\", \"ecdsa\"] });\n * ```\n */\nexport const polkadot = (\n\toptions: PolkadotPluginOptions = {},\n): KheopskitPlatform<\"polkadot\", PolkadotWallet, PolkadotAccount> => {\n\tconst accountTypes = options.accountTypes ?? DEFAULT_ACCOUNT_TYPES;\n\n\tconst invalid = accountTypes.filter((t) => !VALID_ACCOUNT_TYPES.has(t));\n\tif (invalid.length > 0) {\n\t\tconsole.warn(\n\t\t\t`[kheopskit] Unknown polkadot accountTypes: ${JSON.stringify(invalid)}. Valid values: \"sr25519\", \"ed25519\", \"ecdsa\", \"ethereum\".`,\n\t\t);\n\t}\n\n\treturn {\n\t\tplatform: \"polkadot\",\n\t\tgetWallets$: (ctx: PlatformContext) => getPolkadotWallets$(ctx.store),\n\t\tgetAccounts$: (wallets$) => getPolkadotAccounts$(wallets$, accountTypes),\n\t\tacceptsCachedAccount: (cached) =>\n\t\t\taccountTypes.includes(cached.polkadotAccountType ?? \"sr25519\"),\n\t};\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"polkadot.js","names":["Observable","getWalletAccountId","pjs","KheopskitError","getWalletConnectSessionAccounts$","getCaip10Addresses","getSessionCaip10s","createPlatformAccounts$","getWalletId","Observable","isEqual","createInjectedWallets$","parseWalletId","POLKADOT_EXTENSIONS"],"sources":["../src/api/polkadot/accounts.ts","../src/api/polkadot/wallets.ts","../src/api/polkadot/plugin.ts"],"sourcesContent":["import type {\n\tInjectedExtension,\n\tInjectedPolkadotAccount,\n\tSignPayload,\n\tSignRaw,\n} from \"polkadot-api/pjs-signer\";\nimport * as pjs from \"polkadot-api/pjs-signer\";\nimport { Observable, of } from \"rxjs\";\nimport { getWalletAccountId } from \"../../utils\";\nimport { KheopskitError } from \"../errors\";\nimport {\n\tcreatePlatformAccounts$,\n\tgetCaip10Addresses,\n\tgetSessionCaip10s,\n\tgetWalletConnectSessionAccounts$,\n} from \"../platformAccounts\";\nimport type {\n\tAppKitInstance,\n\tPolkadotAccountType,\n\tWalletConnectWallet,\n} from \"../types\";\nimport type {\n\tPolkadotAccount,\n\tPolkadotInjectedWallet,\n\tPolkadotWallet,\n} from \"./types\";\n\nconst getInjectedWalletAccounts$ = (\n\twallet: PolkadotInjectedWallet,\n): Observable<PolkadotAccount[]> => {\n\tif (!wallet.isConnected) return of([]);\n\n\treturn new Observable<PolkadotAccount[]>((subscriber) => {\n\t\tconst getAccount = (account: InjectedPolkadotAccount): PolkadotAccount => ({\n\t\t\tid: getWalletAccountId(wallet.id, account.address),\n\t\t\t...account,\n\t\t\ttype: account.type ?? \"sr25519\",\n\t\t\tplatform: \"polkadot\",\n\t\t\twalletName: wallet.name,\n\t\t\twalletId: wallet.id,\n\t\t});\n\n\t\tconst extension = wallet.extension as InjectedExtension;\n\n\t\t// subscribe to changes\n\t\tconst unsubscribe = extension.subscribe((accounts) => {\n\t\t\tsubscriber.next(accounts.map(getAccount));\n\t\t});\n\n\t\t// initial value\n\t\tsubscriber.next(extension.getAccounts().map(getAccount));\n\n\t\treturn () => {\n\t\t\treturn unsubscribe();\n\t\t};\n\t});\n};\n\ntype PjsSignerFactory = (\n\taddress: string,\n\tsignPayload: SignPayload,\n\tsignRaw: SignRaw,\n) => unknown;\n\ntype PjsSignerModule = {\n\tgetTxCreatorFromPjs?: PjsSignerFactory;\n\tgetPolkadotSignerFromPjs?: PjsSignerFactory;\n};\n\n/**\n * polkadot-api v3 replaced `polkadotSigner` (PolkadotSigner) with `txCreator`\n * (TxCreator). Which one the app's installed version provides is detected at\n * runtime so a single @kheopskit/core release supports both.\n */\nconst getPjsSignerField = (): {\n\tfield: \"txCreator\" | \"polkadotSigner\";\n\tfactory: PjsSignerFactory;\n} => {\n\tconst { getTxCreatorFromPjs, getPolkadotSignerFromPjs } =\n\t\tpjs as PjsSignerModule;\n\tif (getTxCreatorFromPjs)\n\t\treturn { field: \"txCreator\", factory: getTxCreatorFromPjs };\n\tif (getPolkadotSignerFromPjs)\n\t\treturn { field: \"polkadotSigner\", factory: getPolkadotSignerFromPjs };\n\tthrow new KheopskitError(\n\t\t\"UNSUPPORTED_VERSION\",\n\t\t\"Unsupported polkadot-api/pjs-signer version\",\n\t);\n};\n\nconst getAppKitPolkadotSigner = (appKit: AppKitInstance, address: string) => {\n\tconst provider = appKit.getProvider(\"polkadot\");\n\tif (!provider) throw new KheopskitError(\"NO_PROVIDER\", \"No provider found\");\n\tif (!provider.session)\n\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\n\tconst { field, factory } = getPjsSignerField();\n\n\tconst signer = factory(\n\t\taddress,\n\t\t(transactionPayload) => {\n\t\t\tif (!provider.session)\n\t\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\n\t\t\treturn provider.client.request({\n\t\t\t\ttopic: provider.session.topic,\n\t\t\t\tchainId: `polkadot:${transactionPayload.genesisHash.substring(2, 34)}`,\n\t\t\t\trequest: {\n\t\t\t\t\tmethod: \"polkadot_signTransaction\",\n\t\t\t\t\tparams: {\n\t\t\t\t\t\taddress,\n\t\t\t\t\t\ttransactionPayload,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t\tasync ({ address, data }) => {\n\t\t\tif (!provider.session)\n\t\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\t\t\tconst networks = appKit.getCaipNetworks(\"polkadot\");\n\t\t\tconst chainId = networks[0]?.caipNetworkId;\n\t\t\tif (!chainId)\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"NO_SESSION\",\n\t\t\t\t\t\"No CAIP network available for polkadot\",\n\t\t\t\t);\n\n\t\t\treturn provider.client.request({\n\t\t\t\ttopic: provider.session.topic,\n\t\t\t\tchainId,\n\t\t\t\trequest: {\n\t\t\t\t\tmethod: \"polkadot_signMessage\",\n\t\t\t\t\tparams: {\n\t\t\t\t\t\taddress,\n\t\t\t\t\t\tmessage: data,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t);\n\n\treturn { [field]: signer };\n};\n\nconst getWalletConnectAccounts$ = (\n\twallet: WalletConnectWallet,\n): Observable<PolkadotAccount[]> =>\n\tgetWalletConnectSessionAccounts$({\n\t\twallet,\n\t\tplatform: \"polkadot\",\n\t\tnamespace: \"polkadot\",\n\t\tcacheKey: `accounts:${wallet.id}:polkadot:`,\n\t\tbuildAccounts: (provider) => {\n\t\t\tconst session = provider.session;\n\t\t\tif (!session) return [];\n\n\t\t\tconst addresses = getCaip10Addresses(\n\t\t\t\tgetSessionCaip10s(session, \"polkadot\"),\n\t\t\t);\n\n\t\t\treturn addresses.map(\n\t\t\t\t(address) =>\n\t\t\t\t\t({\n\t\t\t\t\t\tid: getWalletAccountId(wallet.id, address),\n\t\t\t\t\t\tplatform: \"polkadot\",\n\t\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t\t\taddress,\n\t\t\t\t\t\t...getAppKitPolkadotSigner(wallet.appKit, address),\n\t\t\t\t\t\tgenesisHash: null,\n\t\t\t\t\t\tname: `${wallet.name} Polkadot`,\n\t\t\t\t\t\t// WalletConnect (Reown AppKit) doesn't expose account key type;\n\t\t\t\t\t\t// default to sr25519, which is the most common Polkadot key type.\n\t\t\t\t\t\ttype: \"sr25519\",\n\t\t\t\t\t}) as PolkadotAccount,\n\t\t\t);\n\t\t},\n\t});\n\nexport const getPolkadotAccounts$ = (\n\tpolkadotWallets$: Observable<(PolkadotWallet | WalletConnectWallet)[]>,\n\tpolkadotAccountTypes: PolkadotAccountType[],\n) => {\n\tif (polkadotAccountTypes.length === 0) {\n\t\tconsole.warn(\n\t\t\t\"[kheopskit] config.polkadotAccountTypes is empty; all Polkadot accounts will be filtered out.\",\n\t\t);\n\t}\n\n\treturn createPlatformAccounts$({\n\t\twallets$: polkadotWallets$,\n\t\tgetInjectedAccounts$: getInjectedWalletAccounts$,\n\t\tgetWalletConnectAccounts$,\n\t\tmapAccounts: (accounts) =>\n\t\t\taccounts.filter((account) => polkadotAccountTypes.includes(account.type)),\n\t});\n};\n","import { isEqual } from \"lodash-es\";\nimport {\n\tconnectInjectedExtension,\n\tgetInjectedExtensions,\n\ttype InjectedExtension,\n} from \"polkadot-api/pjs-signer\";\nimport { distinctUntilChanged, Observable, shareReplay } from \"rxjs\";\nimport { POLKADOT_EXTENSIONS } from \"../../utils/polkadotExtensions\";\nimport {\n\tgetWalletId,\n\tparseWalletId,\n\ttype WalletId,\n} from \"../../utils/WalletId\";\nimport { createInjectedWallets$ } from \"../injectedWallets\";\nimport type { KheopskitStore } from \"../store\";\nimport type { PolkadotInjectedWallet } from \"./types\";\n\nconst getInjectedWalletsIds = () =>\n\ttypeof window === \"undefined\"\n\t\t? []\n\t\t: getInjectedExtensions().map((name) => getWalletId(\"polkadot\", name));\n\n// Create a polling observable that starts immediately and polls at intervals\nconst createWalletIdsPoller$ = () => {\n\treturn new Observable<WalletId[]>((subscriber) => {\n\t\t// Emit immediately on subscribe\n\t\tsubscriber.next(getInjectedWalletsIds());\n\n\t\t// Poll at shorter intervals initially, then slow down\n\t\tconst intervals = [100, 200, 300, 500];\n\t\tlet index = 0;\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\n\t\tconst poll = () => {\n\t\t\tsubscriber.next(getInjectedWalletsIds());\n\t\t\tif (index < intervals.length) {\n\t\t\t\tconst delay = intervals[index++];\n\t\t\t\ttimer = setTimeout(poll, delay);\n\t\t\t}\n\t\t};\n\n\t\t// Start polling after first immediate emission\n\t\tif (intervals.length > 0) {\n\t\t\ttimer = setTimeout(poll, intervals[index++] ?? 100);\n\t\t}\n\n\t\treturn () => {\n\t\t\t// Cancel any pending poll so it can't fire after unsubscribe.\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t};\n\t}).pipe(\n\t\tdistinctUntilChanged<WalletId[]>(isEqual),\n\t\tshareReplay({ refCount: true, bufferSize: 1 }),\n\t);\n};\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 getPolkadotWallets$ = (store: KheopskitStore) =>\n\tcreateInjectedWallets$<WalletId, PolkadotInjectedWallet, InjectedExtension>(\n\t\tstore,\n\t\t{\n\t\t\tsources$: createWalletIdsPoller$(),\n\t\t\tgetWalletId: (walletId) => walletId,\n\t\t\tconnect: (walletId) => {\n\t\t\t\tconst { identifier } = parseWalletId(walletId);\n\t\t\t\treturn connectInjectedExtension(identifier);\n\t\t\t},\n\t\t\tbuildWallet: ({ walletId, handle, isConnected, connect, disconnect }) => {\n\t\t\t\tconst { identifier } = parseWalletId(walletId);\n\t\t\t\tconst extInfo = POLKADOT_EXTENSIONS[identifier];\n\n\t\t\t\treturn {\n\t\t\t\t\tid: walletId,\n\t\t\t\t\ttype: \"injected\",\n\t\t\t\t\tplatform: \"polkadot\",\n\t\t\t\t\tname: extInfo?.name ?? identifier,\n\t\t\t\t\ticon: extInfo?.icon ?? \"\",\n\t\t\t\t\tsourceId: identifier,\n\t\t\t\t\textension: handle,\n\t\t\t\t\tisConnected,\n\t\t\t\t\tconnect,\n\t\t\t\t\tdisconnect,\n\t\t\t\t};\n\t\t\t},\n\t\t},\n\t);\n","import type {\n\tKheopskitPlatform,\n\tPlatformContext,\n\tPolkadotAccountType,\n} from \"../types\";\nimport { getPolkadotAccounts$ } from \"./accounts\";\nimport type { PolkadotAccount, PolkadotWallet } from \"./types\";\nimport { getPolkadotWallets$ } from \"./wallets\";\n\nconst DEFAULT_ACCOUNT_TYPES: PolkadotAccountType[] = [\n\t\"sr25519\",\n\t\"ed25519\",\n\t\"ecdsa\",\n];\n\nconst VALID_ACCOUNT_TYPES = new Set<string>([\n\t\"sr25519\",\n\t\"ed25519\",\n\t\"ecdsa\",\n\t\"ethereum\",\n]);\n\nexport type PolkadotPluginOptions = {\n\t/**\n\t * Allowed Polkadot account key types. Accounts with other key types are\n\t * filtered out from kheopskit state.\n\t *\n\t * @default [\"sr25519\", \"ed25519\", \"ecdsa\"]\n\t */\n\taccountTypes?: PolkadotAccountType[];\n};\n\n/**\n * Polkadot platform plugin. Pass to `getKheopskit$({ platforms: [polkadot()] })`.\n *\n * @example\n * ```ts\n * import { polkadot } from \"@kheopskit/core/polkadot\";\n * polkadot({ accountTypes: [\"sr25519\", \"ed25519\", \"ecdsa\"] });\n * ```\n */\nexport const polkadot = (\n\toptions: PolkadotPluginOptions = {},\n): KheopskitPlatform<\"polkadot\", PolkadotWallet, PolkadotAccount> => {\n\tconst accountTypes = options.accountTypes ?? DEFAULT_ACCOUNT_TYPES;\n\n\tconst invalid = accountTypes.filter((t) => !VALID_ACCOUNT_TYPES.has(t));\n\tif (invalid.length > 0) {\n\t\tconsole.warn(\n\t\t\t`[kheopskit] Unknown polkadot accountTypes: ${JSON.stringify(invalid)}. Valid values: \"sr25519\", \"ed25519\", \"ecdsa\", \"ethereum\".`,\n\t\t);\n\t}\n\n\treturn {\n\t\tplatform: \"polkadot\",\n\t\tgetWallets$: (ctx: PlatformContext) => getPolkadotWallets$(ctx.store),\n\t\tgetAccounts$: (wallets$) => getPolkadotAccounts$(wallets$, accountTypes),\n\t\tacceptsCachedAccount: (cached) =>\n\t\t\taccountTypes.includes(cached.polkadotAccountType ?? \"sr25519\"),\n\t};\n};\n"],"mappings":"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"}
|
package/dist/polkadot.mjs
CHANGED
|
@@ -4,7 +4,8 @@ import { t as POLKADOT_EXTENSIONS } from "./polkadotExtensions-BoVKhNU_.mjs";
|
|
|
4
4
|
import { a as getWalletConnectSessionAccounts$, i as getSessionCaip10s, n as createPlatformAccounts$, r as getCaip10Addresses, t as createInjectedWallets$ } from "./injectedWallets-B3Vysfvr.mjs";
|
|
5
5
|
import { Observable, distinctUntilChanged, of, shareReplay } from "rxjs";
|
|
6
6
|
import { isEqual } from "lodash-es";
|
|
7
|
-
import
|
|
7
|
+
import * as pjs from "polkadot-api/pjs-signer";
|
|
8
|
+
import { connectInjectedExtension, getInjectedExtensions } from "polkadot-api/pjs-signer";
|
|
8
9
|
//#region src/api/polkadot/accounts.ts
|
|
9
10
|
const getInjectedWalletAccounts$ = (wallet) => {
|
|
10
11
|
if (!wallet.isConnected) return of([]);
|
|
@@ -27,11 +28,29 @@ const getInjectedWalletAccounts$ = (wallet) => {
|
|
|
27
28
|
};
|
|
28
29
|
});
|
|
29
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* polkadot-api v3 replaced `polkadotSigner` (PolkadotSigner) with `txCreator`
|
|
33
|
+
* (TxCreator). Which one the app's installed version provides is detected at
|
|
34
|
+
* runtime so a single @kheopskit/core release supports both.
|
|
35
|
+
*/
|
|
36
|
+
const getPjsSignerField = () => {
|
|
37
|
+
const { getTxCreatorFromPjs, getPolkadotSignerFromPjs } = pjs;
|
|
38
|
+
if (getTxCreatorFromPjs) return {
|
|
39
|
+
field: "txCreator",
|
|
40
|
+
factory: getTxCreatorFromPjs
|
|
41
|
+
};
|
|
42
|
+
if (getPolkadotSignerFromPjs) return {
|
|
43
|
+
field: "polkadotSigner",
|
|
44
|
+
factory: getPolkadotSignerFromPjs
|
|
45
|
+
};
|
|
46
|
+
throw new KheopskitError("UNSUPPORTED_VERSION", "Unsupported polkadot-api/pjs-signer version");
|
|
47
|
+
};
|
|
30
48
|
const getAppKitPolkadotSigner = (appKit, address) => {
|
|
31
49
|
const provider = appKit.getProvider("polkadot");
|
|
32
50
|
if (!provider) throw new KheopskitError("NO_PROVIDER", "No provider found");
|
|
33
51
|
if (!provider.session) throw new KheopskitError("NO_SESSION", "No session found");
|
|
34
|
-
|
|
52
|
+
const { field, factory } = getPjsSignerField();
|
|
53
|
+
const signer = factory(address, (transactionPayload) => {
|
|
35
54
|
if (!provider.session) throw new KheopskitError("NO_SESSION", "No session found");
|
|
36
55
|
return provider.client.request({
|
|
37
56
|
topic: provider.session.topic,
|
|
@@ -60,6 +79,7 @@ const getAppKitPolkadotSigner = (appKit, address) => {
|
|
|
60
79
|
}
|
|
61
80
|
});
|
|
62
81
|
});
|
|
82
|
+
return { [field]: signer };
|
|
63
83
|
};
|
|
64
84
|
const getWalletConnectAccounts$ = (wallet) => getWalletConnectSessionAccounts$({
|
|
65
85
|
wallet,
|
|
@@ -75,7 +95,7 @@ const getWalletConnectAccounts$ = (wallet) => getWalletConnectSessionAccounts$({
|
|
|
75
95
|
walletName: wallet.name,
|
|
76
96
|
walletId: wallet.id,
|
|
77
97
|
address,
|
|
78
|
-
|
|
98
|
+
...getAppKitPolkadotSigner(wallet.appKit, address),
|
|
79
99
|
genesisHash: null,
|
|
80
100
|
name: `${wallet.name} Polkadot`,
|
|
81
101
|
type: "sr25519"
|
package/dist/polkadot.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"polkadot.mjs","names":[],"sources":["../src/api/polkadot/accounts.ts","../src/api/polkadot/wallets.ts","../src/api/polkadot/plugin.ts"],"sourcesContent":["import {\n\tgetPolkadotSignerFromPjs,\n\ttype InjectedExtension,\n\ttype InjectedPolkadotAccount,\n} from \"polkadot-api/pjs-signer\";\nimport { Observable, of } from \"rxjs\";\nimport { getWalletAccountId } from \"../../utils\";\nimport { KheopskitError } from \"../errors\";\nimport {\n\tcreatePlatformAccounts$,\n\tgetCaip10Addresses,\n\tgetSessionCaip10s,\n\tgetWalletConnectSessionAccounts$,\n} from \"../platformAccounts\";\nimport type {\n\tAppKitInstance,\n\tPolkadotAccountType,\n\tWalletConnectWallet,\n} from \"../types\";\nimport type {\n\tPolkadotAccount,\n\tPolkadotInjectedWallet,\n\tPolkadotWallet,\n} from \"./types\";\n\nconst getInjectedWalletAccounts$ = (\n\twallet: PolkadotInjectedWallet,\n): Observable<PolkadotAccount[]> => {\n\tif (!wallet.isConnected) return of([]);\n\n\treturn new Observable<PolkadotAccount[]>((subscriber) => {\n\t\tconst getAccount = (account: InjectedPolkadotAccount): PolkadotAccount => ({\n\t\t\tid: getWalletAccountId(wallet.id, account.address),\n\t\t\t...account,\n\t\t\ttype: account.type ?? \"sr25519\",\n\t\t\tplatform: \"polkadot\",\n\t\t\twalletName: wallet.name,\n\t\t\twalletId: wallet.id,\n\t\t});\n\n\t\tconst extension = wallet.extension as InjectedExtension;\n\n\t\t// subscribe to changes\n\t\tconst unsubscribe = extension.subscribe((accounts) => {\n\t\t\tsubscriber.next(accounts.map(getAccount));\n\t\t});\n\n\t\t// initial value\n\t\tsubscriber.next(extension.getAccounts().map(getAccount));\n\n\t\treturn () => {\n\t\t\treturn unsubscribe();\n\t\t};\n\t});\n};\n\nconst getAppKitPolkadotSigner = (appKit: AppKitInstance, address: string) => {\n\tconst provider = appKit.getProvider(\"polkadot\");\n\tif (!provider) throw new KheopskitError(\"NO_PROVIDER\", \"No provider found\");\n\tif (!provider.session)\n\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\n\treturn getPolkadotSignerFromPjs(\n\t\taddress,\n\t\t(transactionPayload) => {\n\t\t\tif (!provider.session)\n\t\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\n\t\t\treturn provider.client.request({\n\t\t\t\ttopic: provider.session.topic,\n\t\t\t\tchainId: `polkadot:${transactionPayload.genesisHash.substring(2, 34)}`,\n\t\t\t\trequest: {\n\t\t\t\t\tmethod: \"polkadot_signTransaction\",\n\t\t\t\t\tparams: {\n\t\t\t\t\t\taddress,\n\t\t\t\t\t\ttransactionPayload,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t\tasync ({ address, data }) => {\n\t\t\tif (!provider.session)\n\t\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\t\t\tconst networks = appKit.getCaipNetworks(\"polkadot\");\n\t\t\tconst chainId = networks[0]?.caipNetworkId;\n\t\t\tif (!chainId)\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"NO_SESSION\",\n\t\t\t\t\t\"No CAIP network available for polkadot\",\n\t\t\t\t);\n\n\t\t\treturn provider.client.request({\n\t\t\t\ttopic: provider.session.topic,\n\t\t\t\tchainId,\n\t\t\t\trequest: {\n\t\t\t\t\tmethod: \"polkadot_signMessage\",\n\t\t\t\t\tparams: {\n\t\t\t\t\t\taddress,\n\t\t\t\t\t\tmessage: data,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t);\n};\n\nconst getWalletConnectAccounts$ = (\n\twallet: WalletConnectWallet,\n): Observable<PolkadotAccount[]> =>\n\tgetWalletConnectSessionAccounts$({\n\t\twallet,\n\t\tplatform: \"polkadot\",\n\t\tnamespace: \"polkadot\",\n\t\tcacheKey: `accounts:${wallet.id}:polkadot:`,\n\t\tbuildAccounts: (provider) => {\n\t\t\tconst session = provider.session;\n\t\t\tif (!session) return [];\n\n\t\t\tconst addresses = getCaip10Addresses(\n\t\t\t\tgetSessionCaip10s(session, \"polkadot\"),\n\t\t\t);\n\n\t\t\treturn addresses.map(\n\t\t\t\t(address): PolkadotAccount => ({\n\t\t\t\t\tid: getWalletAccountId(wallet.id, address),\n\t\t\t\t\tplatform: \"polkadot\",\n\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t\taddress,\n\t\t\t\t\tpolkadotSigner: getAppKitPolkadotSigner(wallet.appKit, address),\n\t\t\t\t\tgenesisHash: null,\n\t\t\t\t\tname: `${wallet.name} Polkadot`,\n\t\t\t\t\t// WalletConnect (Reown AppKit) doesn't expose account key type;\n\t\t\t\t\t// default to sr25519, which is the most common Polkadot key type.\n\t\t\t\t\ttype: \"sr25519\",\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t});\n\nexport const getPolkadotAccounts$ = (\n\tpolkadotWallets$: Observable<(PolkadotWallet | WalletConnectWallet)[]>,\n\tpolkadotAccountTypes: PolkadotAccountType[],\n) => {\n\tif (polkadotAccountTypes.length === 0) {\n\t\tconsole.warn(\n\t\t\t\"[kheopskit] config.polkadotAccountTypes is empty; all Polkadot accounts will be filtered out.\",\n\t\t);\n\t}\n\n\treturn createPlatformAccounts$({\n\t\twallets$: polkadotWallets$,\n\t\tgetInjectedAccounts$: getInjectedWalletAccounts$,\n\t\tgetWalletConnectAccounts$,\n\t\tmapAccounts: (accounts) =>\n\t\t\taccounts.filter((account) => polkadotAccountTypes.includes(account.type)),\n\t});\n};\n","import { isEqual } from \"lodash-es\";\nimport {\n\tconnectInjectedExtension,\n\tgetInjectedExtensions,\n\ttype InjectedExtension,\n} from \"polkadot-api/pjs-signer\";\nimport { distinctUntilChanged, Observable, shareReplay } from \"rxjs\";\nimport { POLKADOT_EXTENSIONS } from \"../../utils/polkadotExtensions\";\nimport {\n\tgetWalletId,\n\tparseWalletId,\n\ttype WalletId,\n} from \"../../utils/WalletId\";\nimport { createInjectedWallets$ } from \"../injectedWallets\";\nimport type { KheopskitStore } from \"../store\";\nimport type { PolkadotInjectedWallet } from \"./types\";\n\nconst getInjectedWalletsIds = () =>\n\ttypeof window === \"undefined\"\n\t\t? []\n\t\t: getInjectedExtensions().map((name) => getWalletId(\"polkadot\", name));\n\n// Create a polling observable that starts immediately and polls at intervals\nconst createWalletIdsPoller$ = () => {\n\treturn new Observable<WalletId[]>((subscriber) => {\n\t\t// Emit immediately on subscribe\n\t\tsubscriber.next(getInjectedWalletsIds());\n\n\t\t// Poll at shorter intervals initially, then slow down\n\t\tconst intervals = [100, 200, 300, 500];\n\t\tlet index = 0;\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\n\t\tconst poll = () => {\n\t\t\tsubscriber.next(getInjectedWalletsIds());\n\t\t\tif (index < intervals.length) {\n\t\t\t\tconst delay = intervals[index++];\n\t\t\t\ttimer = setTimeout(poll, delay);\n\t\t\t}\n\t\t};\n\n\t\t// Start polling after first immediate emission\n\t\tif (intervals.length > 0) {\n\t\t\ttimer = setTimeout(poll, intervals[index++] ?? 100);\n\t\t}\n\n\t\treturn () => {\n\t\t\t// Cancel any pending poll so it can't fire after unsubscribe.\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t};\n\t}).pipe(\n\t\tdistinctUntilChanged<WalletId[]>(isEqual),\n\t\tshareReplay({ refCount: true, bufferSize: 1 }),\n\t);\n};\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 getPolkadotWallets$ = (store: KheopskitStore) =>\n\tcreateInjectedWallets$<WalletId, PolkadotInjectedWallet, InjectedExtension>(\n\t\tstore,\n\t\t{\n\t\t\tsources$: createWalletIdsPoller$(),\n\t\t\tgetWalletId: (walletId) => walletId,\n\t\t\tconnect: (walletId) => {\n\t\t\t\tconst { identifier } = parseWalletId(walletId);\n\t\t\t\treturn connectInjectedExtension(identifier);\n\t\t\t},\n\t\t\tbuildWallet: ({ walletId, handle, isConnected, connect, disconnect }) => {\n\t\t\t\tconst { identifier } = parseWalletId(walletId);\n\t\t\t\tconst extInfo = POLKADOT_EXTENSIONS[identifier];\n\n\t\t\t\treturn {\n\t\t\t\t\tid: walletId,\n\t\t\t\t\ttype: \"injected\",\n\t\t\t\t\tplatform: \"polkadot\",\n\t\t\t\t\tname: extInfo?.name ?? identifier,\n\t\t\t\t\ticon: extInfo?.icon ?? \"\",\n\t\t\t\t\tsourceId: identifier,\n\t\t\t\t\textension: handle,\n\t\t\t\t\tisConnected,\n\t\t\t\t\tconnect,\n\t\t\t\t\tdisconnect,\n\t\t\t\t};\n\t\t\t},\n\t\t},\n\t);\n","import type {\n\tKheopskitPlatform,\n\tPlatformContext,\n\tPolkadotAccountType,\n} from \"../types\";\nimport { getPolkadotAccounts$ } from \"./accounts\";\nimport type { PolkadotAccount, PolkadotWallet } from \"./types\";\nimport { getPolkadotWallets$ } from \"./wallets\";\n\nconst DEFAULT_ACCOUNT_TYPES: PolkadotAccountType[] = [\n\t\"sr25519\",\n\t\"ed25519\",\n\t\"ecdsa\",\n];\n\nconst VALID_ACCOUNT_TYPES = new Set<string>([\n\t\"sr25519\",\n\t\"ed25519\",\n\t\"ecdsa\",\n\t\"ethereum\",\n]);\n\nexport type PolkadotPluginOptions = {\n\t/**\n\t * Allowed Polkadot account key types. Accounts with other key types are\n\t * filtered out from kheopskit state.\n\t *\n\t * @default [\"sr25519\", \"ed25519\", \"ecdsa\"]\n\t */\n\taccountTypes?: PolkadotAccountType[];\n};\n\n/**\n * Polkadot platform plugin. Pass to `getKheopskit$({ platforms: [polkadot()] })`.\n *\n * @example\n * ```ts\n * import { polkadot } from \"@kheopskit/core/polkadot\";\n * polkadot({ accountTypes: [\"sr25519\", \"ed25519\", \"ecdsa\"] });\n * ```\n */\nexport const polkadot = (\n\toptions: PolkadotPluginOptions = {},\n): KheopskitPlatform<\"polkadot\", PolkadotWallet, PolkadotAccount> => {\n\tconst accountTypes = options.accountTypes ?? DEFAULT_ACCOUNT_TYPES;\n\n\tconst invalid = accountTypes.filter((t) => !VALID_ACCOUNT_TYPES.has(t));\n\tif (invalid.length > 0) {\n\t\tconsole.warn(\n\t\t\t`[kheopskit] Unknown polkadot accountTypes: ${JSON.stringify(invalid)}. Valid values: \"sr25519\", \"ed25519\", \"ecdsa\", \"ethereum\".`,\n\t\t);\n\t}\n\n\treturn {\n\t\tplatform: \"polkadot\",\n\t\tgetWallets$: (ctx: PlatformContext) => getPolkadotWallets$(ctx.store),\n\t\tgetAccounts$: (wallets$) => getPolkadotAccounts$(wallets$, accountTypes),\n\t\tacceptsCachedAccount: (cached) =>\n\t\t\taccountTypes.includes(cached.polkadotAccountType ?? \"sr25519\"),\n\t};\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"polkadot.mjs","names":[],"sources":["../src/api/polkadot/accounts.ts","../src/api/polkadot/wallets.ts","../src/api/polkadot/plugin.ts"],"sourcesContent":["import type {\n\tInjectedExtension,\n\tInjectedPolkadotAccount,\n\tSignPayload,\n\tSignRaw,\n} from \"polkadot-api/pjs-signer\";\nimport * as pjs from \"polkadot-api/pjs-signer\";\nimport { Observable, of } from \"rxjs\";\nimport { getWalletAccountId } from \"../../utils\";\nimport { KheopskitError } from \"../errors\";\nimport {\n\tcreatePlatformAccounts$,\n\tgetCaip10Addresses,\n\tgetSessionCaip10s,\n\tgetWalletConnectSessionAccounts$,\n} from \"../platformAccounts\";\nimport type {\n\tAppKitInstance,\n\tPolkadotAccountType,\n\tWalletConnectWallet,\n} from \"../types\";\nimport type {\n\tPolkadotAccount,\n\tPolkadotInjectedWallet,\n\tPolkadotWallet,\n} from \"./types\";\n\nconst getInjectedWalletAccounts$ = (\n\twallet: PolkadotInjectedWallet,\n): Observable<PolkadotAccount[]> => {\n\tif (!wallet.isConnected) return of([]);\n\n\treturn new Observable<PolkadotAccount[]>((subscriber) => {\n\t\tconst getAccount = (account: InjectedPolkadotAccount): PolkadotAccount => ({\n\t\t\tid: getWalletAccountId(wallet.id, account.address),\n\t\t\t...account,\n\t\t\ttype: account.type ?? \"sr25519\",\n\t\t\tplatform: \"polkadot\",\n\t\t\twalletName: wallet.name,\n\t\t\twalletId: wallet.id,\n\t\t});\n\n\t\tconst extension = wallet.extension as InjectedExtension;\n\n\t\t// subscribe to changes\n\t\tconst unsubscribe = extension.subscribe((accounts) => {\n\t\t\tsubscriber.next(accounts.map(getAccount));\n\t\t});\n\n\t\t// initial value\n\t\tsubscriber.next(extension.getAccounts().map(getAccount));\n\n\t\treturn () => {\n\t\t\treturn unsubscribe();\n\t\t};\n\t});\n};\n\ntype PjsSignerFactory = (\n\taddress: string,\n\tsignPayload: SignPayload,\n\tsignRaw: SignRaw,\n) => unknown;\n\ntype PjsSignerModule = {\n\tgetTxCreatorFromPjs?: PjsSignerFactory;\n\tgetPolkadotSignerFromPjs?: PjsSignerFactory;\n};\n\n/**\n * polkadot-api v3 replaced `polkadotSigner` (PolkadotSigner) with `txCreator`\n * (TxCreator). Which one the app's installed version provides is detected at\n * runtime so a single @kheopskit/core release supports both.\n */\nconst getPjsSignerField = (): {\n\tfield: \"txCreator\" | \"polkadotSigner\";\n\tfactory: PjsSignerFactory;\n} => {\n\tconst { getTxCreatorFromPjs, getPolkadotSignerFromPjs } =\n\t\tpjs as PjsSignerModule;\n\tif (getTxCreatorFromPjs)\n\t\treturn { field: \"txCreator\", factory: getTxCreatorFromPjs };\n\tif (getPolkadotSignerFromPjs)\n\t\treturn { field: \"polkadotSigner\", factory: getPolkadotSignerFromPjs };\n\tthrow new KheopskitError(\n\t\t\"UNSUPPORTED_VERSION\",\n\t\t\"Unsupported polkadot-api/pjs-signer version\",\n\t);\n};\n\nconst getAppKitPolkadotSigner = (appKit: AppKitInstance, address: string) => {\n\tconst provider = appKit.getProvider(\"polkadot\");\n\tif (!provider) throw new KheopskitError(\"NO_PROVIDER\", \"No provider found\");\n\tif (!provider.session)\n\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\n\tconst { field, factory } = getPjsSignerField();\n\n\tconst signer = factory(\n\t\taddress,\n\t\t(transactionPayload) => {\n\t\t\tif (!provider.session)\n\t\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\n\t\t\treturn provider.client.request({\n\t\t\t\ttopic: provider.session.topic,\n\t\t\t\tchainId: `polkadot:${transactionPayload.genesisHash.substring(2, 34)}`,\n\t\t\t\trequest: {\n\t\t\t\t\tmethod: \"polkadot_signTransaction\",\n\t\t\t\t\tparams: {\n\t\t\t\t\t\taddress,\n\t\t\t\t\t\ttransactionPayload,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t\tasync ({ address, data }) => {\n\t\t\tif (!provider.session)\n\t\t\t\tthrow new KheopskitError(\"NO_SESSION\", \"No session found\");\n\t\t\tconst networks = appKit.getCaipNetworks(\"polkadot\");\n\t\t\tconst chainId = networks[0]?.caipNetworkId;\n\t\t\tif (!chainId)\n\t\t\t\tthrow new KheopskitError(\n\t\t\t\t\t\"NO_SESSION\",\n\t\t\t\t\t\"No CAIP network available for polkadot\",\n\t\t\t\t);\n\n\t\t\treturn provider.client.request({\n\t\t\t\ttopic: provider.session.topic,\n\t\t\t\tchainId,\n\t\t\t\trequest: {\n\t\t\t\t\tmethod: \"polkadot_signMessage\",\n\t\t\t\t\tparams: {\n\t\t\t\t\t\taddress,\n\t\t\t\t\t\tmessage: data,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t);\n\n\treturn { [field]: signer };\n};\n\nconst getWalletConnectAccounts$ = (\n\twallet: WalletConnectWallet,\n): Observable<PolkadotAccount[]> =>\n\tgetWalletConnectSessionAccounts$({\n\t\twallet,\n\t\tplatform: \"polkadot\",\n\t\tnamespace: \"polkadot\",\n\t\tcacheKey: `accounts:${wallet.id}:polkadot:`,\n\t\tbuildAccounts: (provider) => {\n\t\t\tconst session = provider.session;\n\t\t\tif (!session) return [];\n\n\t\t\tconst addresses = getCaip10Addresses(\n\t\t\t\tgetSessionCaip10s(session, \"polkadot\"),\n\t\t\t);\n\n\t\t\treturn addresses.map(\n\t\t\t\t(address) =>\n\t\t\t\t\t({\n\t\t\t\t\t\tid: getWalletAccountId(wallet.id, address),\n\t\t\t\t\t\tplatform: \"polkadot\",\n\t\t\t\t\t\twalletName: wallet.name,\n\t\t\t\t\t\twalletId: wallet.id,\n\t\t\t\t\t\taddress,\n\t\t\t\t\t\t...getAppKitPolkadotSigner(wallet.appKit, address),\n\t\t\t\t\t\tgenesisHash: null,\n\t\t\t\t\t\tname: `${wallet.name} Polkadot`,\n\t\t\t\t\t\t// WalletConnect (Reown AppKit) doesn't expose account key type;\n\t\t\t\t\t\t// default to sr25519, which is the most common Polkadot key type.\n\t\t\t\t\t\ttype: \"sr25519\",\n\t\t\t\t\t}) as PolkadotAccount,\n\t\t\t);\n\t\t},\n\t});\n\nexport const getPolkadotAccounts$ = (\n\tpolkadotWallets$: Observable<(PolkadotWallet | WalletConnectWallet)[]>,\n\tpolkadotAccountTypes: PolkadotAccountType[],\n) => {\n\tif (polkadotAccountTypes.length === 0) {\n\t\tconsole.warn(\n\t\t\t\"[kheopskit] config.polkadotAccountTypes is empty; all Polkadot accounts will be filtered out.\",\n\t\t);\n\t}\n\n\treturn createPlatformAccounts$({\n\t\twallets$: polkadotWallets$,\n\t\tgetInjectedAccounts$: getInjectedWalletAccounts$,\n\t\tgetWalletConnectAccounts$,\n\t\tmapAccounts: (accounts) =>\n\t\t\taccounts.filter((account) => polkadotAccountTypes.includes(account.type)),\n\t});\n};\n","import { isEqual } from \"lodash-es\";\nimport {\n\tconnectInjectedExtension,\n\tgetInjectedExtensions,\n\ttype InjectedExtension,\n} from \"polkadot-api/pjs-signer\";\nimport { distinctUntilChanged, Observable, shareReplay } from \"rxjs\";\nimport { POLKADOT_EXTENSIONS } from \"../../utils/polkadotExtensions\";\nimport {\n\tgetWalletId,\n\tparseWalletId,\n\ttype WalletId,\n} from \"../../utils/WalletId\";\nimport { createInjectedWallets$ } from \"../injectedWallets\";\nimport type { KheopskitStore } from \"../store\";\nimport type { PolkadotInjectedWallet } from \"./types\";\n\nconst getInjectedWalletsIds = () =>\n\ttypeof window === \"undefined\"\n\t\t? []\n\t\t: getInjectedExtensions().map((name) => getWalletId(\"polkadot\", name));\n\n// Create a polling observable that starts immediately and polls at intervals\nconst createWalletIdsPoller$ = () => {\n\treturn new Observable<WalletId[]>((subscriber) => {\n\t\t// Emit immediately on subscribe\n\t\tsubscriber.next(getInjectedWalletsIds());\n\n\t\t// Poll at shorter intervals initially, then slow down\n\t\tconst intervals = [100, 200, 300, 500];\n\t\tlet index = 0;\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\n\t\tconst poll = () => {\n\t\t\tsubscriber.next(getInjectedWalletsIds());\n\t\t\tif (index < intervals.length) {\n\t\t\t\tconst delay = intervals[index++];\n\t\t\t\ttimer = setTimeout(poll, delay);\n\t\t\t}\n\t\t};\n\n\t\t// Start polling after first immediate emission\n\t\tif (intervals.length > 0) {\n\t\t\ttimer = setTimeout(poll, intervals[index++] ?? 100);\n\t\t}\n\n\t\treturn () => {\n\t\t\t// Cancel any pending poll so it can't fire after unsubscribe.\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t};\n\t}).pipe(\n\t\tdistinctUntilChanged<WalletId[]>(isEqual),\n\t\tshareReplay({ refCount: true, bufferSize: 1 }),\n\t);\n};\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 getPolkadotWallets$ = (store: KheopskitStore) =>\n\tcreateInjectedWallets$<WalletId, PolkadotInjectedWallet, InjectedExtension>(\n\t\tstore,\n\t\t{\n\t\t\tsources$: createWalletIdsPoller$(),\n\t\t\tgetWalletId: (walletId) => walletId,\n\t\t\tconnect: (walletId) => {\n\t\t\t\tconst { identifier } = parseWalletId(walletId);\n\t\t\t\treturn connectInjectedExtension(identifier);\n\t\t\t},\n\t\t\tbuildWallet: ({ walletId, handle, isConnected, connect, disconnect }) => {\n\t\t\t\tconst { identifier } = parseWalletId(walletId);\n\t\t\t\tconst extInfo = POLKADOT_EXTENSIONS[identifier];\n\n\t\t\t\treturn {\n\t\t\t\t\tid: walletId,\n\t\t\t\t\ttype: \"injected\",\n\t\t\t\t\tplatform: \"polkadot\",\n\t\t\t\t\tname: extInfo?.name ?? identifier,\n\t\t\t\t\ticon: extInfo?.icon ?? \"\",\n\t\t\t\t\tsourceId: identifier,\n\t\t\t\t\textension: handle,\n\t\t\t\t\tisConnected,\n\t\t\t\t\tconnect,\n\t\t\t\t\tdisconnect,\n\t\t\t\t};\n\t\t\t},\n\t\t},\n\t);\n","import type {\n\tKheopskitPlatform,\n\tPlatformContext,\n\tPolkadotAccountType,\n} from \"../types\";\nimport { getPolkadotAccounts$ } from \"./accounts\";\nimport type { PolkadotAccount, PolkadotWallet } from \"./types\";\nimport { getPolkadotWallets$ } from \"./wallets\";\n\nconst DEFAULT_ACCOUNT_TYPES: PolkadotAccountType[] = [\n\t\"sr25519\",\n\t\"ed25519\",\n\t\"ecdsa\",\n];\n\nconst VALID_ACCOUNT_TYPES = new Set<string>([\n\t\"sr25519\",\n\t\"ed25519\",\n\t\"ecdsa\",\n\t\"ethereum\",\n]);\n\nexport type PolkadotPluginOptions = {\n\t/**\n\t * Allowed Polkadot account key types. Accounts with other key types are\n\t * filtered out from kheopskit state.\n\t *\n\t * @default [\"sr25519\", \"ed25519\", \"ecdsa\"]\n\t */\n\taccountTypes?: PolkadotAccountType[];\n};\n\n/**\n * Polkadot platform plugin. Pass to `getKheopskit$({ platforms: [polkadot()] })`.\n *\n * @example\n * ```ts\n * import { polkadot } from \"@kheopskit/core/polkadot\";\n * polkadot({ accountTypes: [\"sr25519\", \"ed25519\", \"ecdsa\"] });\n * ```\n */\nexport const polkadot = (\n\toptions: PolkadotPluginOptions = {},\n): KheopskitPlatform<\"polkadot\", PolkadotWallet, PolkadotAccount> => {\n\tconst accountTypes = options.accountTypes ?? DEFAULT_ACCOUNT_TYPES;\n\n\tconst invalid = accountTypes.filter((t) => !VALID_ACCOUNT_TYPES.has(t));\n\tif (invalid.length > 0) {\n\t\tconsole.warn(\n\t\t\t`[kheopskit] Unknown polkadot accountTypes: ${JSON.stringify(invalid)}. Valid values: \"sr25519\", \"ed25519\", \"ecdsa\", \"ethereum\".`,\n\t\t);\n\t}\n\n\treturn {\n\t\tplatform: \"polkadot\",\n\t\tgetWallets$: (ctx: PlatformContext) => getPolkadotWallets$(ctx.store),\n\t\tgetAccounts$: (wallets$) => getPolkadotAccounts$(wallets$, accountTypes),\n\t\tacceptsCachedAccount: (cached) =>\n\t\t\taccountTypes.includes(cached.polkadotAccountType ?? \"sr25519\"),\n\t};\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kheopskit/core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"private": false,
|
|
6
6
|
"sideEffects": false,
|
|
@@ -122,9 +122,9 @@
|
|
|
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": "^
|
|
125
|
+
"polkadot-api": "^3.1.0",
|
|
126
126
|
"rxjs": "^7.8.2",
|
|
127
|
-
"viem": "^2.55.
|
|
127
|
+
"viem": "^2.55.10"
|
|
128
128
|
},
|
|
129
129
|
"tsdown": {
|
|
130
130
|
"entry": [
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"iconCache-BSa42Sui.mjs","names":[],"sources":["../src/utils/hydrateState.ts","../src/utils/storage.ts","../src/utils/iconCache.ts"],"sourcesContent":["import {\n\ttype BaseWallet,\n\ttype BaseWalletAccount,\n\ttype CachedAccount,\n\ttype CachedWallet,\n\tisWalletConnectWallet,\n\ttype PolkadotAccountType,\n\ttype WalletConnectWallet,\n} from \"../api/types\";\nimport { POLKADOT_EXTENSIONS } from \"./polkadotExtensions\";\nimport type { WalletAccountId } from \"./WalletAccountId\";\nimport { parseWalletId, type WalletId } from \"./WalletId\";\n\n/**\n * Looks up the icon for a wallet from known Polkadot extensions only.\n * Ethereum icons will be populated from the localStorage icon cache via the merge function.\n *\n * Note: We DON'T use localStorage icon cache here because hydrateWallet is called\n * during SSR (server) and client hydration. localStorage isn't available on server,\n * so using it would cause a hydration mismatch. Icons for Ethereum wallets will be\n * populated when the hydration buffer merges cached wallets with live wallets.\n */\nconst lookupWalletIcon = (platform: string, identifier: string): string => {\n\t// Only Polkadot extensions have hardcoded icons that are safe for SSR\n\tif (platform === \"polkadot\") {\n\t\treturn POLKADOT_EXTENSIONS[identifier]?.icon ?? \"\";\n\t}\n\t// Ethereum icons come from localStorage or live wallets - not here\n\treturn \"\";\n};\n\n/**\n * Error thrown when trying to use a placeholder wallet that hasn't fully loaded yet.\n */\nclass PendingWalletError extends Error {\n\tconstructor(walletId: string) {\n\t\tsuper(\n\t\t\t`Wallet ${walletId} is still loading. Wait for isHydrating to be false before calling connect/disconnect.`,\n\t\t);\n\t\tthis.name = \"PendingWalletError\";\n\t}\n}\n\n/**\n * Converts a CachedWallet to a placeholder wallet for SSR hydration display.\n *\n * The placeholder carries only the SDK-free {@link BaseWallet} fields; the real\n * wallet (with its injected provider/extension/standard-wallet handle) replaces\n * it once it loads. connect/disconnect throw until then.\n */\nexport const hydrateWallet = (\n\tcached: CachedWallet,\n): BaseWallet | WalletConnectWallet => {\n\tconst throwPending = () => {\n\t\tthrow new PendingWalletError(cached.id);\n\t};\n\n\t// The platform-less WalletConnect connector. `appKit`/`platforms` are SDK\n\t// state absent until the live connector loads (cast like other placeholder\n\t// SDK handles); icon is filled from the localStorage cache by the caller.\n\tif (cached.type === \"walletconnect\") {\n\t\treturn {\n\t\t\tid: cached.id,\n\t\t\ttype: \"walletconnect\",\n\t\t\tplatforms: [],\n\t\t\tname: cached.name,\n\t\t\ticon: \"\",\n\t\t\tisConnected: cached.isConnected,\n\t\t\tconnect: throwPending,\n\t\t\tdisconnect: throwPending,\n\t\t} as unknown as WalletConnectWallet;\n\t}\n\n\tconst { platform, identifier } = parseWalletId(cached.id);\n\n\treturn {\n\t\tid: cached.id,\n\t\tplatform: cached.platform as BaseWallet[\"platform\"],\n\t\ttype: cached.type,\n\t\tname: cached.name,\n\t\ticon: lookupWalletIcon(platform, identifier),\n\t\tisConnected: cached.isConnected,\n\t\tconnect: throwPending,\n\t\tdisconnect: throwPending,\n\t};\n};\n\n/**\n * Converts a CachedAccount to a placeholder account for SSR hydration display.\n *\n * The placeholder carries the SDK-free {@link BaseWalletAccount} fields plus the\n * plain, serializable platform data that lives in the cache — Ethereum `chainId`\n * and the Polkadot key `type`. Those render immediately on reload (no blank →\n * value flicker) and match what the live account will report. Only the SDK\n * handles (`client`/`signer`/`polkadotSigner`) are absent until the real account\n * replaces this placeholder; signing stays gated on `isHydrating` until then.\n */\nexport const hydrateAccount = (cached: CachedAccount): BaseWalletAccount => ({\n\tid: cached.id as WalletAccountId,\n\tplatform: cached.platform,\n\taddress: cached.address,\n\tname: cached.name,\n\twalletId: cached.walletId,\n\twalletName: cached.walletName,\n\t// Spread (not direct keys) so the extra platform fields don't trip the\n\t// excess-property check against BaseWalletAccount; they're read back via the\n\t// platform-specific account types once narrowed by `platform`.\n\t...(cached.platform === \"ethereum\" && { chainId: cached.chainId }),\n\t...(cached.platform === \"polkadot\" && {\n\t\ttype: cached.polkadotAccountType,\n\t}),\n});\n\n/**\n * Converts a wallet to a CachedWallet for storage.\n * Only extracts the serializable properties needed for hydration.\n */\nexport const serializeWallet = (\n\twallet: BaseWallet | WalletConnectWallet,\n): CachedWallet => ({\n\tid: wallet.id,\n\t// The WalletConnect connector has no platform.\n\tplatform: isWalletConnectWallet(wallet) ? undefined : wallet.platform,\n\ttype: wallet.type,\n\tname: wallet.name,\n\t// Note: icon is NOT stored to save cookie space\n\tisConnected: wallet.isConnected,\n});\n\n/**\n * Converts an account to a CachedAccount for storage.\n * Only extracts the serializable properties needed for hydration. Platform-only\n * fields (Ethereum chainId, Polkadot key type) are read defensively so this\n * stays SDK-free.\n */\nexport const serializeAccount = (\n\taccount: BaseWalletAccount,\n): CachedAccount => ({\n\tid: account.id,\n\tplatform: account.platform,\n\taddress: account.address,\n\tname: account.name,\n\tchainId:\n\t\taccount.platform === \"ethereum\"\n\t\t\t? (account as { chainId?: number }).chainId\n\t\t\t: undefined,\n\tpolkadotAccountType:\n\t\taccount.platform === \"polkadot\"\n\t\t\t? (account as { type?: PolkadotAccountType }).type\n\t\t\t: undefined,\n\twalletId: account.walletId as WalletId,\n\twalletName: account.walletName,\n});\n","export type Storage = {\n\tgetItem: (key: string) => string | null;\n\tsetItem: (key: string, value: string) => void;\n\tremoveItem: (key: string) => void;\n};\n\n/**\n * Extended storage interface with cross-tab sync support.\n */\nexport type SyncableStorage = Storage & {\n\t/**\n\t * Subscribe to storage changes from other tabs.\n\t * Returns an unsubscribe function.\n\t */\n\tsubscribe?: (\n\t\tkey: string,\n\t\tcallback: (value: string | null) => void,\n\t) => () => void;\n};\n\n/**\n * A no-op storage implementation that does nothing.\n * Useful for testing or SSR environments where no storage is needed.\n */\nexport const noopStorage: SyncableStorage = {\n\tgetItem: () => null,\n\tsetItem: () => {},\n\tremoveItem: () => {},\n};\n\n/**\n * Cached localStorage wrapper instance.\n * Lazily initialized on first access to avoid SSR issues.\n */\nlet _safeLocalStorage: SyncableStorage | null = null;\n\n/**\n * Creates the localStorage wrapper, testing for availability.\n * Returns noopStorage if localStorage is unavailable (SSR, private browsing, etc.)\n */\nconst createSafeLocalStorage = (): SyncableStorage => {\n\tif (typeof window === \"undefined\") return noopStorage;\n\n\ttry {\n\t\t// Test that localStorage is accessible (may throw in private browsing)\n\t\tconst testKey = \"__kheopskit_test__\";\n\t\twindow.localStorage.setItem(testKey, testKey);\n\t\twindow.localStorage.removeItem(testKey);\n\n\t\treturn {\n\t\t\tgetItem: (key: string) => window.localStorage.getItem(key),\n\t\t\tsetItem: (key: string, value: string) =>\n\t\t\t\twindow.localStorage.setItem(key, value),\n\t\t\tremoveItem: (key: string) => window.localStorage.removeItem(key),\n\t\t\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\t\t\tconst handler = (event: StorageEvent) => {\n\t\t\t\t\tif (event.key === key) {\n\t\t\t\t\t\tcallback(event.newValue);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\twindow.addEventListener(\"storage\", handler);\n\t\t\t\treturn () => window.removeEventListener(\"storage\", handler);\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn noopStorage;\n\t}\n};\n\n/**\n * A safe localStorage wrapper that falls back to noopStorage\n * when localStorage is not available (e.g., during SSR).\n * Includes cross-tab sync via the native 'storage' event.\n *\n * Lazily initialized on first access to be SSR-safe.\n */\nexport const getSafeLocalStorage = (): SyncableStorage => {\n\tif (_safeLocalStorage === null) {\n\t\t_safeLocalStorage = createSafeLocalStorage();\n\t}\n\treturn _safeLocalStorage;\n};\n\n/**\n * @deprecated Use getSafeLocalStorage() instead. This is kept for backward compatibility.\n * Returns a proxy that lazily initializes on first method call.\n */\nexport const safeLocalStorage: SyncableStorage = {\n\tgetItem: (key: string) => getSafeLocalStorage().getItem(key),\n\tsetItem: (key: string, value: string) =>\n\t\tgetSafeLocalStorage().setItem(key, value),\n\tremoveItem: (key: string) => getSafeLocalStorage().removeItem(key),\n\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\tconst storage = getSafeLocalStorage();\n\t\treturn storage.subscribe?.(key, callback) ?? (() => {});\n\t},\n};\n\n/**\n * Parse a cookie string to extract the value for a specific key.\n * @param cookieString - The full cookie header string (e.g., document.cookie or req.headers.cookie)\n * @param key - The cookie key to find\n * @returns The cookie value or null if not found\n */\nexport const parseCookie = (\n\tcookieString: string | undefined,\n\tkey: string,\n): string | null => {\n\tif (!cookieString) return null;\n\n\tfor (const cookie of cookieString.split(\";\")) {\n\t\tconst [k, ...v] = cookie.split(\"=\");\n\t\tconst cookieKey = k?.trim();\n\t\tif (cookieKey === key) {\n\t\t\ttry {\n\t\t\t\treturn decodeURIComponent(v.join(\"=\").trim());\n\t\t\t} catch {\n\t\t\t\treturn null; // Malformed cookie value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n};\n\n/**\n * Maximum recommended size for cookie storage (3KB to stay well under 4KB limit).\n *\n * @remarks\n * Cookie storage is subject to browser limits (typically 4KB per cookie).\n * When users connect many wallets, the auto-reconnect list may exceed this limit.\n * If this happens:\n * - A console warning will be logged\n * - Some browsers may silently reject the cookie\n * - Consider using fewer simultaneous wallet connections\n *\n * The stored data includes wallet IDs in format `platform:identifier`\n * (e.g., `polkadot:talisman`, `ethereum:io.metamask`).\n */\nexport const COOKIE_MAX_SIZE = 3 * 1024;\n\n/**\n * BroadcastChannel name for cross-tab cookie sync.\n */\nconst BROADCAST_CHANNEL_NAME = \"kheopskit-storage-sync\";\n\n/**\n * Singleton BroadcastChannel for cross-tab cookie sync.\n * Created once and shared across all cookieStorage instances.\n */\nlet sharedBroadcastChannel: BroadcastChannel | null = null;\n\nconst getBroadcastChannel = (): BroadcastChannel | null => {\n\tif (sharedBroadcastChannel) return sharedBroadcastChannel;\n\tif (typeof BroadcastChannel === \"undefined\") return null;\n\n\ttry {\n\t\tsharedBroadcastChannel = new BroadcastChannel(BROADCAST_CHANNEL_NAME);\n\t} catch {\n\t\t// BroadcastChannel not supported or failed\n\t}\n\treturn sharedBroadcastChannel;\n};\n\n/**\n * Check if the current connection is secure (HTTPS).\n * Must be called at runtime (inside methods) to work correctly after SSR hydration.\n */\nconst isSecureConnection = (): boolean =>\n\ttypeof window !== \"undefined\" && window.location.protocol === \"https:\";\n\n/**\n * A cookie-based storage implementation for SSR environments.\n * Reads cookies from an optional initial cookie string (for SSR hydration),\n * writes to document.cookie on the client.\n *\n * Features:\n * - Secure flag automatically added for HTTPS connections\n * - Cross-tab synchronization via BroadcastChannel API\n * - Size limit warning when data exceeds recommended limits\n *\n * @param initialCookies - Optional cookie string for server-side hydration\n */\nexport const cookieStorage = (initialCookies?: string): SyncableStorage => {\n\treturn {\n\t\tgetItem: (key: string) => {\n\t\t\t// On server, use initialCookies. On client, read from document.cookie\n\t\t\tconst cookieString =\n\t\t\t\ttypeof document !== \"undefined\" ? document.cookie : initialCookies;\n\t\t\treturn parseCookie(cookieString, key);\n\t\t},\n\t\tsetItem: (key: string, value: string) => {\n\t\t\tif (typeof document === \"undefined\") return;\n\n\t\t\t// Warn if value exceeds recommended size\n\t\t\tconst encodedValue = encodeURIComponent(value);\n\t\t\tif (encodedValue.length > COOKIE_MAX_SIZE) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[kheopskit] Cookie value for \"${key}\" exceeds recommended size limit (${encodedValue.length} > ${COOKIE_MAX_SIZE} bytes). ` +\n\t\t\t\t\t\t\"This may cause issues with cookie storage. Consider reducing the number of connected wallets.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Set cookie with 1 year expiry\n\t\t\tconst expires = new Date();\n\t\t\texpires.setFullYear(expires.getFullYear() + 1);\n\n\t\t\t// Build cookie string with security attributes\n\t\t\tlet cookieStr = `${key}=${encodedValue};expires=${expires.toUTCString()};path=/;SameSite=Lax`;\n\t\t\tif (isSecureConnection()) {\n\t\t\t\tcookieStr += \";Secure\";\n\t\t\t}\n\n\t\t\t// biome-ignore lint: necessary for cookie storage - direct cookie assignment is the standard API\n\t\t\tdocument.cookie = cookieStr;\n\n\t\t\t// Broadcast change to other tabs\n\t\t\tgetBroadcastChannel()?.postMessage({ type: \"set\", key, value });\n\t\t},\n\t\tremoveItem: (key: string) => {\n\t\t\tif (typeof document === \"undefined\") return;\n\n\t\t\t// Build delete cookie string\n\t\t\tlet cookieStr = `${key}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/;SameSite=Lax`;\n\t\t\tif (isSecureConnection()) {\n\t\t\t\tcookieStr += \";Secure\";\n\t\t\t}\n\n\t\t\t// biome-ignore lint: necessary for cookie storage - direct cookie assignment is the standard API\n\t\t\tdocument.cookie = cookieStr;\n\n\t\t\t// Broadcast change to other tabs\n\t\t\tgetBroadcastChannel()?.postMessage({ type: \"remove\", key });\n\t\t},\n\t\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\t\tconst channel = getBroadcastChannel();\n\t\t\tif (!channel) return () => {};\n\n\t\t\tconst handler = (event: MessageEvent) => {\n\t\t\t\tconst data = event.data as {\n\t\t\t\t\ttype: string;\n\t\t\t\t\tkey: string;\n\t\t\t\t\tvalue?: string;\n\t\t\t\t};\n\t\t\t\tif (data.key === key) {\n\t\t\t\t\tif (data.type === \"set\") {\n\t\t\t\t\t\tcallback(data.value ?? null);\n\t\t\t\t\t} else if (data.type === \"remove\") {\n\t\t\t\t\t\tcallback(null);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tchannel.addEventListener(\"message\", handler);\n\t\t\treturn () => {\n\t\t\t\tchannel.removeEventListener(\"message\", handler);\n\t\t\t};\n\t\t},\n\t};\n};\n\n/**\n * Cleanup the shared BroadcastChannel used for cross-tab cookie sync.\n * Call this when you're done using cookie storage (e.g., in tests or when unmounting).\n *\n * @remarks\n * In normal browser usage, you typically don't need to call this -\n * the channel will be cleaned up when the page is closed.\n * This is primarily useful for testing environments where multiple\n * test runs may accumulate channels.\n */\nexport const cleanupBroadcastChannel = (): void => {\n\tif (sharedBroadcastChannel) {\n\t\tsharedBroadcastChannel.close();\n\t\tsharedBroadcastChannel = null;\n\t}\n};\n","import { safeLocalStorage } from \"./storage\";\n\n/**\n * Storage key for the icon cache in localStorage.\n */\nconst ICON_CACHE_KEY = \"kheopskit-icons\";\n\n/**\n * Icon cache type: a map of wallet ID to icon data URI or URL.\n */\ntype IconCache = Record<string, string>;\n\n/**\n * In-memory cache to avoid repeated localStorage reads.\n */\nlet memoryCache: IconCache | null = null;\n\n/**\n * Loads the icon cache from localStorage.\n */\nconst loadCache = (): IconCache => {\n\tif (memoryCache !== null) return memoryCache;\n\n\ttry {\n\t\tconst stored = safeLocalStorage.getItem(ICON_CACHE_KEY);\n\t\tmemoryCache = stored ? (JSON.parse(stored) as IconCache) : {};\n\t} catch {\n\t\tmemoryCache = {};\n\t}\n\treturn memoryCache;\n};\n\n/**\n * Saves the icon cache to localStorage.\n */\nconst saveCache = (cache: IconCache): void => {\n\ttry {\n\t\tsafeLocalStorage.setItem(ICON_CACHE_KEY, JSON.stringify(cache));\n\t\tmemoryCache = cache;\n\t} catch {\n\t\t// localStorage may be full or unavailable\n\t}\n};\n\n/**\n * Gets a cached icon for a wallet.\n * @param walletId - The wallet ID (e.g., \"ethereum:io.talisman\")\n * @returns The cached icon data URI, or undefined if not cached\n */\nexport const getCachedIcon = (walletId: string): string | undefined => {\n\tconst cache = loadCache();\n\treturn cache[walletId] || undefined;\n};\n\n/**\n * Sets multiple cached icons at once.\n * More efficient than calling setCachedIcon multiple times.\n * @param icons - Map of wallet ID to icon\n */\nexport const setCachedIcons = (icons: Record<string, string>): void => {\n\tconst cache = loadCache();\n\tlet changed = false;\n\n\tfor (const [walletId, icon] of Object.entries(icons)) {\n\t\tif (icon && cache[walletId] !== icon) {\n\t\t\tcache[walletId] = icon;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\tif (changed) {\n\t\tsaveCache(cache);\n\t}\n};\n"],"mappings":";;;;;;;;;;;;AAsBA,MAAM,oBAAoB,UAAkB,eAA+B;CAE1E,IAAI,aAAa,YAChB,OAAO,oBAAoB,WAAW,EAAE,QAAQ;CAGjD,OAAO;AACR;;;;AAKA,IAAM,qBAAN,cAAiC,MAAM;CACtC,YAAY,UAAkB;EAC7B,MACC,UAAU,SAAS,uFACpB;EACA,KAAK,OAAO;CACb;AACD;;;;;;;;AASA,MAAa,iBACZ,WACsC;CACtC,MAAM,qBAAqB;EAC1B,MAAM,IAAI,mBAAmB,OAAO,EAAE;CACvC;CAKA,IAAI,OAAO,SAAS,iBACnB,OAAO;EACN,IAAI,OAAO;EACX,MAAM;EACN,WAAW,CAAC;EACZ,MAAM,OAAO;EACb,MAAM;EACN,aAAa,OAAO;EACpB,SAAS;EACT,YAAY;CACb;CAGD,MAAM,EAAE,UAAU,eAAe,cAAc,OAAO,EAAE;CAExD,OAAO;EACN,IAAI,OAAO;EACX,UAAU,OAAO;EACjB,MAAM,OAAO;EACb,MAAM,OAAO;EACb,MAAM,iBAAiB,UAAU,UAAU;EAC3C,aAAa,OAAO;EACpB,SAAS;EACT,YAAY;CACb;AACD;;;;;;;;;;;AAYA,MAAa,kBAAkB,YAA8C;CAC5E,IAAI,OAAO;CACX,UAAU,OAAO;CACjB,SAAS,OAAO;CAChB,MAAM,OAAO;CACb,UAAU,OAAO;CACjB,YAAY,OAAO;CAInB,GAAI,OAAO,aAAa,cAAc,EAAE,SAAS,OAAO,QAAQ;CAChE,GAAI,OAAO,aAAa,cAAc,EACrC,MAAM,OAAO,oBACd;AACD;;;;;AAMA,MAAa,mBACZ,YACmB;CACnB,IAAI,OAAO;CAEX,UAAU,sBAAsB,MAAM,IAAI,KAAA,IAAY,OAAO;CAC7D,MAAM,OAAO;CACb,MAAM,OAAO;CAEb,aAAa,OAAO;AACrB;;;;;;;AAQA,MAAa,oBACZ,aACoB;CACpB,IAAI,QAAQ;CACZ,UAAU,QAAQ;CAClB,SAAS,QAAQ;CACjB,MAAM,QAAQ;CACd,SACC,QAAQ,aAAa,aACjB,QAAiC,UAClC,KAAA;CACJ,qBACC,QAAQ,aAAa,aACjB,QAA2C,OAC5C,KAAA;CACJ,UAAU,QAAQ;CAClB,YAAY,QAAQ;AACrB;;;;;;;AChIA,MAAa,cAA+B;CAC3C,eAAe;CACf,eAAe,CAAC;CAChB,kBAAkB,CAAC;AACpB;;;;;AAMA,IAAI,oBAA4C;;;;;AAMhD,MAAM,+BAAgD;CACrD,IAAI,OAAO,WAAW,aAAa,OAAO;CAE1C,IAAI;EAEH,MAAM,UAAU;EAChB,OAAO,aAAa,QAAQ,SAAS,OAAO;EAC5C,OAAO,aAAa,WAAW,OAAO;EAEtC,OAAO;GACN,UAAU,QAAgB,OAAO,aAAa,QAAQ,GAAG;GACzD,UAAU,KAAa,UACtB,OAAO,aAAa,QAAQ,KAAK,KAAK;GACvC,aAAa,QAAgB,OAAO,aAAa,WAAW,GAAG;GAC/D,YAAY,KAAa,aAA6C;IACrE,MAAM,WAAW,UAAwB;KACxC,IAAI,MAAM,QAAQ,KACjB,SAAS,MAAM,QAAQ;IAEzB;IACA,OAAO,iBAAiB,WAAW,OAAO;IAC1C,aAAa,OAAO,oBAAoB,WAAW,OAAO;GAC3D;EACD;CACD,QAAQ;EACP,OAAO;CACR;AACD;;;;;;;;AASA,MAAa,4BAA6C;CACzD,IAAI,sBAAsB,MACzB,oBAAoB,uBAAuB;CAE5C,OAAO;AACR;;;;;AAMA,MAAa,mBAAoC;CAChD,UAAU,QAAgB,oBAAoB,CAAC,CAAC,QAAQ,GAAG;CAC3D,UAAU,KAAa,UACtB,oBAAoB,CAAC,CAAC,QAAQ,KAAK,KAAK;CACzC,aAAa,QAAgB,oBAAoB,CAAC,CAAC,WAAW,GAAG;CACjE,YAAY,KAAa,aAA6C;EAErE,OADgB,oBACH,CAAC,CAAC,YAAY,KAAK,QAAQ,YAAY,CAAC;CACtD;AACD;;;;;;;AAQA,MAAa,eACZ,cACA,QACmB;CACnB,IAAI,CAAC,cAAc,OAAO;CAE1B,KAAK,MAAM,UAAU,aAAa,MAAM,GAAG,GAAG;EAC7C,MAAM,CAAC,GAAG,GAAG,KAAK,OAAO,MAAM,GAAG;EAElC,IADkB,GAAG,KAAK,MACR,KACjB,IAAI;GACH,OAAO,mBAAmB,EAAE,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;EAC7C,QAAQ;GACP,OAAO;EACR;CAEF;CAEA,OAAO;AACR;;;;;;;;;;;;;;;AAgBA,MAAa,kBAAkB,IAAI;;;;AAKnC,MAAM,yBAAyB;;;;;AAM/B,IAAI,yBAAkD;AAEtD,MAAM,4BAAqD;CAC1D,IAAI,wBAAwB,OAAO;CACnC,IAAI,OAAO,qBAAqB,aAAa,OAAO;CAEpD,IAAI;EACH,yBAAyB,IAAI,iBAAiB,sBAAsB;CACrE,QAAQ,CAER;CACA,OAAO;AACR;;;;;AAMA,MAAM,2BACL,OAAO,WAAW,eAAe,OAAO,SAAS,aAAa;;;;;;;;;;;;;AAc/D,MAAa,iBAAiB,mBAA6C;CAC1E,OAAO;EACN,UAAU,QAAgB;GAEzB,MAAM,eACL,OAAO,aAAa,cAAc,SAAS,SAAS;GACrD,OAAO,YAAY,cAAc,GAAG;EACrC;EACA,UAAU,KAAa,UAAkB;GACxC,IAAI,OAAO,aAAa,aAAa;GAGrC,MAAM,eAAe,mBAAmB,KAAK;GAC7C,IAAI,aAAa,SAAA,MAChB,QAAQ,KACP,iCAAiC,IAAI,oCAAoC,aAAa,OAAO,KAAK,gBAAgB,uGAEnH;GAID,MAAM,0BAAU,IAAI,KAAK;GACzB,QAAQ,YAAY,QAAQ,YAAY,IAAI,CAAC;GAG7C,IAAI,YAAY,GAAG,IAAI,GAAG,aAAa,WAAW,QAAQ,YAAY,EAAE;GACxE,IAAI,mBAAmB,GACtB,aAAa;GAId,SAAS,SAAS;GAGlB,oBAAoB,CAAC,EAAE,YAAY;IAAE,MAAM;IAAO;IAAK;GAAM,CAAC;EAC/D;EACA,aAAa,QAAgB;GAC5B,IAAI,OAAO,aAAa,aAAa;GAGrC,IAAI,YAAY,GAAG,IAAI;GACvB,IAAI,mBAAmB,GACtB,aAAa;GAId,SAAS,SAAS;GAGlB,oBAAoB,CAAC,EAAE,YAAY;IAAE,MAAM;IAAU;GAAI,CAAC;EAC3D;EACA,YAAY,KAAa,aAA6C;GACrE,MAAM,UAAU,oBAAoB;GACpC,IAAI,CAAC,SAAS,aAAa,CAAC;GAE5B,MAAM,WAAW,UAAwB;IACxC,MAAM,OAAO,MAAM;IAKnB,IAAI,KAAK,QAAQ,KACZ;SAAA,KAAK,SAAS,OACjB,SAAS,KAAK,SAAS,IAAI;UACrB,IAAI,KAAK,SAAS,UACxB,SAAS,IAAI;IAAA;GAGhB;GAEA,QAAQ,iBAAiB,WAAW,OAAO;GAC3C,aAAa;IACZ,QAAQ,oBAAoB,WAAW,OAAO;GAC/C;EACD;CACD;AACD;;;;;;AC9PA,MAAM,iBAAiB;;;;AAUvB,IAAI,cAAgC;;;;AAKpC,MAAM,kBAA6B;CAClC,IAAI,gBAAgB,MAAM,OAAO;CAEjC,IAAI;EACH,MAAM,SAAS,iBAAiB,QAAQ,cAAc;EACtD,cAAc,SAAU,KAAK,MAAM,MAAM,IAAkB,CAAC;CAC7D,QAAQ;EACP,cAAc,CAAC;CAChB;CACA,OAAO;AACR;;;;AAKA,MAAM,aAAa,UAA2B;CAC7C,IAAI;EACH,iBAAiB,QAAQ,gBAAgB,KAAK,UAAU,KAAK,CAAC;EAC9D,cAAc;CACf,QAAQ,CAER;AACD;;;;;;AAOA,MAAa,iBAAiB,aAAyC;CAEtE,OADc,UACH,CAAC,CAAC,aAAa,KAAA;AAC3B;;;;;;AAOA,MAAa,kBAAkB,UAAwC;CACtE,MAAM,QAAQ,UAAU;CACxB,IAAI,UAAU;CAEd,KAAK,MAAM,CAAC,UAAU,SAAS,OAAO,QAAQ,KAAK,GAClD,IAAI,QAAQ,MAAM,cAAc,MAAM;EACrC,MAAM,YAAY;EAClB,UAAU;CACX;CAGD,IAAI,SACH,UAAU,KAAK;AAEjB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"iconCache-DS4zNiP1.js","names":["POLKADOT_EXTENSIONS","parseWalletId","isWalletConnectWallet"],"sources":["../src/utils/hydrateState.ts","../src/utils/storage.ts","../src/utils/iconCache.ts"],"sourcesContent":["import {\n\ttype BaseWallet,\n\ttype BaseWalletAccount,\n\ttype CachedAccount,\n\ttype CachedWallet,\n\tisWalletConnectWallet,\n\ttype PolkadotAccountType,\n\ttype WalletConnectWallet,\n} from \"../api/types\";\nimport { POLKADOT_EXTENSIONS } from \"./polkadotExtensions\";\nimport type { WalletAccountId } from \"./WalletAccountId\";\nimport { parseWalletId, type WalletId } from \"./WalletId\";\n\n/**\n * Looks up the icon for a wallet from known Polkadot extensions only.\n * Ethereum icons will be populated from the localStorage icon cache via the merge function.\n *\n * Note: We DON'T use localStorage icon cache here because hydrateWallet is called\n * during SSR (server) and client hydration. localStorage isn't available on server,\n * so using it would cause a hydration mismatch. Icons for Ethereum wallets will be\n * populated when the hydration buffer merges cached wallets with live wallets.\n */\nconst lookupWalletIcon = (platform: string, identifier: string): string => {\n\t// Only Polkadot extensions have hardcoded icons that are safe for SSR\n\tif (platform === \"polkadot\") {\n\t\treturn POLKADOT_EXTENSIONS[identifier]?.icon ?? \"\";\n\t}\n\t// Ethereum icons come from localStorage or live wallets - not here\n\treturn \"\";\n};\n\n/**\n * Error thrown when trying to use a placeholder wallet that hasn't fully loaded yet.\n */\nclass PendingWalletError extends Error {\n\tconstructor(walletId: string) {\n\t\tsuper(\n\t\t\t`Wallet ${walletId} is still loading. Wait for isHydrating to be false before calling connect/disconnect.`,\n\t\t);\n\t\tthis.name = \"PendingWalletError\";\n\t}\n}\n\n/**\n * Converts a CachedWallet to a placeholder wallet for SSR hydration display.\n *\n * The placeholder carries only the SDK-free {@link BaseWallet} fields; the real\n * wallet (with its injected provider/extension/standard-wallet handle) replaces\n * it once it loads. connect/disconnect throw until then.\n */\nexport const hydrateWallet = (\n\tcached: CachedWallet,\n): BaseWallet | WalletConnectWallet => {\n\tconst throwPending = () => {\n\t\tthrow new PendingWalletError(cached.id);\n\t};\n\n\t// The platform-less WalletConnect connector. `appKit`/`platforms` are SDK\n\t// state absent until the live connector loads (cast like other placeholder\n\t// SDK handles); icon is filled from the localStorage cache by the caller.\n\tif (cached.type === \"walletconnect\") {\n\t\treturn {\n\t\t\tid: cached.id,\n\t\t\ttype: \"walletconnect\",\n\t\t\tplatforms: [],\n\t\t\tname: cached.name,\n\t\t\ticon: \"\",\n\t\t\tisConnected: cached.isConnected,\n\t\t\tconnect: throwPending,\n\t\t\tdisconnect: throwPending,\n\t\t} as unknown as WalletConnectWallet;\n\t}\n\n\tconst { platform, identifier } = parseWalletId(cached.id);\n\n\treturn {\n\t\tid: cached.id,\n\t\tplatform: cached.platform as BaseWallet[\"platform\"],\n\t\ttype: cached.type,\n\t\tname: cached.name,\n\t\ticon: lookupWalletIcon(platform, identifier),\n\t\tisConnected: cached.isConnected,\n\t\tconnect: throwPending,\n\t\tdisconnect: throwPending,\n\t};\n};\n\n/**\n * Converts a CachedAccount to a placeholder account for SSR hydration display.\n *\n * The placeholder carries the SDK-free {@link BaseWalletAccount} fields plus the\n * plain, serializable platform data that lives in the cache — Ethereum `chainId`\n * and the Polkadot key `type`. Those render immediately on reload (no blank →\n * value flicker) and match what the live account will report. Only the SDK\n * handles (`client`/`signer`/`polkadotSigner`) are absent until the real account\n * replaces this placeholder; signing stays gated on `isHydrating` until then.\n */\nexport const hydrateAccount = (cached: CachedAccount): BaseWalletAccount => ({\n\tid: cached.id as WalletAccountId,\n\tplatform: cached.platform,\n\taddress: cached.address,\n\tname: cached.name,\n\twalletId: cached.walletId,\n\twalletName: cached.walletName,\n\t// Spread (not direct keys) so the extra platform fields don't trip the\n\t// excess-property check against BaseWalletAccount; they're read back via the\n\t// platform-specific account types once narrowed by `platform`.\n\t...(cached.platform === \"ethereum\" && { chainId: cached.chainId }),\n\t...(cached.platform === \"polkadot\" && {\n\t\ttype: cached.polkadotAccountType,\n\t}),\n});\n\n/**\n * Converts a wallet to a CachedWallet for storage.\n * Only extracts the serializable properties needed for hydration.\n */\nexport const serializeWallet = (\n\twallet: BaseWallet | WalletConnectWallet,\n): CachedWallet => ({\n\tid: wallet.id,\n\t// The WalletConnect connector has no platform.\n\tplatform: isWalletConnectWallet(wallet) ? undefined : wallet.platform,\n\ttype: wallet.type,\n\tname: wallet.name,\n\t// Note: icon is NOT stored to save cookie space\n\tisConnected: wallet.isConnected,\n});\n\n/**\n * Converts an account to a CachedAccount for storage.\n * Only extracts the serializable properties needed for hydration. Platform-only\n * fields (Ethereum chainId, Polkadot key type) are read defensively so this\n * stays SDK-free.\n */\nexport const serializeAccount = (\n\taccount: BaseWalletAccount,\n): CachedAccount => ({\n\tid: account.id,\n\tplatform: account.platform,\n\taddress: account.address,\n\tname: account.name,\n\tchainId:\n\t\taccount.platform === \"ethereum\"\n\t\t\t? (account as { chainId?: number }).chainId\n\t\t\t: undefined,\n\tpolkadotAccountType:\n\t\taccount.platform === \"polkadot\"\n\t\t\t? (account as { type?: PolkadotAccountType }).type\n\t\t\t: undefined,\n\twalletId: account.walletId as WalletId,\n\twalletName: account.walletName,\n});\n","export type Storage = {\n\tgetItem: (key: string) => string | null;\n\tsetItem: (key: string, value: string) => void;\n\tremoveItem: (key: string) => void;\n};\n\n/**\n * Extended storage interface with cross-tab sync support.\n */\nexport type SyncableStorage = Storage & {\n\t/**\n\t * Subscribe to storage changes from other tabs.\n\t * Returns an unsubscribe function.\n\t */\n\tsubscribe?: (\n\t\tkey: string,\n\t\tcallback: (value: string | null) => void,\n\t) => () => void;\n};\n\n/**\n * A no-op storage implementation that does nothing.\n * Useful for testing or SSR environments where no storage is needed.\n */\nexport const noopStorage: SyncableStorage = {\n\tgetItem: () => null,\n\tsetItem: () => {},\n\tremoveItem: () => {},\n};\n\n/**\n * Cached localStorage wrapper instance.\n * Lazily initialized on first access to avoid SSR issues.\n */\nlet _safeLocalStorage: SyncableStorage | null = null;\n\n/**\n * Creates the localStorage wrapper, testing for availability.\n * Returns noopStorage if localStorage is unavailable (SSR, private browsing, etc.)\n */\nconst createSafeLocalStorage = (): SyncableStorage => {\n\tif (typeof window === \"undefined\") return noopStorage;\n\n\ttry {\n\t\t// Test that localStorage is accessible (may throw in private browsing)\n\t\tconst testKey = \"__kheopskit_test__\";\n\t\twindow.localStorage.setItem(testKey, testKey);\n\t\twindow.localStorage.removeItem(testKey);\n\n\t\treturn {\n\t\t\tgetItem: (key: string) => window.localStorage.getItem(key),\n\t\t\tsetItem: (key: string, value: string) =>\n\t\t\t\twindow.localStorage.setItem(key, value),\n\t\t\tremoveItem: (key: string) => window.localStorage.removeItem(key),\n\t\t\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\t\t\tconst handler = (event: StorageEvent) => {\n\t\t\t\t\tif (event.key === key) {\n\t\t\t\t\t\tcallback(event.newValue);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\twindow.addEventListener(\"storage\", handler);\n\t\t\t\treturn () => window.removeEventListener(\"storage\", handler);\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn noopStorage;\n\t}\n};\n\n/**\n * A safe localStorage wrapper that falls back to noopStorage\n * when localStorage is not available (e.g., during SSR).\n * Includes cross-tab sync via the native 'storage' event.\n *\n * Lazily initialized on first access to be SSR-safe.\n */\nexport const getSafeLocalStorage = (): SyncableStorage => {\n\tif (_safeLocalStorage === null) {\n\t\t_safeLocalStorage = createSafeLocalStorage();\n\t}\n\treturn _safeLocalStorage;\n};\n\n/**\n * @deprecated Use getSafeLocalStorage() instead. This is kept for backward compatibility.\n * Returns a proxy that lazily initializes on first method call.\n */\nexport const safeLocalStorage: SyncableStorage = {\n\tgetItem: (key: string) => getSafeLocalStorage().getItem(key),\n\tsetItem: (key: string, value: string) =>\n\t\tgetSafeLocalStorage().setItem(key, value),\n\tremoveItem: (key: string) => getSafeLocalStorage().removeItem(key),\n\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\tconst storage = getSafeLocalStorage();\n\t\treturn storage.subscribe?.(key, callback) ?? (() => {});\n\t},\n};\n\n/**\n * Parse a cookie string to extract the value for a specific key.\n * @param cookieString - The full cookie header string (e.g., document.cookie or req.headers.cookie)\n * @param key - The cookie key to find\n * @returns The cookie value or null if not found\n */\nexport const parseCookie = (\n\tcookieString: string | undefined,\n\tkey: string,\n): string | null => {\n\tif (!cookieString) return null;\n\n\tfor (const cookie of cookieString.split(\";\")) {\n\t\tconst [k, ...v] = cookie.split(\"=\");\n\t\tconst cookieKey = k?.trim();\n\t\tif (cookieKey === key) {\n\t\t\ttry {\n\t\t\t\treturn decodeURIComponent(v.join(\"=\").trim());\n\t\t\t} catch {\n\t\t\t\treturn null; // Malformed cookie value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n};\n\n/**\n * Maximum recommended size for cookie storage (3KB to stay well under 4KB limit).\n *\n * @remarks\n * Cookie storage is subject to browser limits (typically 4KB per cookie).\n * When users connect many wallets, the auto-reconnect list may exceed this limit.\n * If this happens:\n * - A console warning will be logged\n * - Some browsers may silently reject the cookie\n * - Consider using fewer simultaneous wallet connections\n *\n * The stored data includes wallet IDs in format `platform:identifier`\n * (e.g., `polkadot:talisman`, `ethereum:io.metamask`).\n */\nexport const COOKIE_MAX_SIZE = 3 * 1024;\n\n/**\n * BroadcastChannel name for cross-tab cookie sync.\n */\nconst BROADCAST_CHANNEL_NAME = \"kheopskit-storage-sync\";\n\n/**\n * Singleton BroadcastChannel for cross-tab cookie sync.\n * Created once and shared across all cookieStorage instances.\n */\nlet sharedBroadcastChannel: BroadcastChannel | null = null;\n\nconst getBroadcastChannel = (): BroadcastChannel | null => {\n\tif (sharedBroadcastChannel) return sharedBroadcastChannel;\n\tif (typeof BroadcastChannel === \"undefined\") return null;\n\n\ttry {\n\t\tsharedBroadcastChannel = new BroadcastChannel(BROADCAST_CHANNEL_NAME);\n\t} catch {\n\t\t// BroadcastChannel not supported or failed\n\t}\n\treturn sharedBroadcastChannel;\n};\n\n/**\n * Check if the current connection is secure (HTTPS).\n * Must be called at runtime (inside methods) to work correctly after SSR hydration.\n */\nconst isSecureConnection = (): boolean =>\n\ttypeof window !== \"undefined\" && window.location.protocol === \"https:\";\n\n/**\n * A cookie-based storage implementation for SSR environments.\n * Reads cookies from an optional initial cookie string (for SSR hydration),\n * writes to document.cookie on the client.\n *\n * Features:\n * - Secure flag automatically added for HTTPS connections\n * - Cross-tab synchronization via BroadcastChannel API\n * - Size limit warning when data exceeds recommended limits\n *\n * @param initialCookies - Optional cookie string for server-side hydration\n */\nexport const cookieStorage = (initialCookies?: string): SyncableStorage => {\n\treturn {\n\t\tgetItem: (key: string) => {\n\t\t\t// On server, use initialCookies. On client, read from document.cookie\n\t\t\tconst cookieString =\n\t\t\t\ttypeof document !== \"undefined\" ? document.cookie : initialCookies;\n\t\t\treturn parseCookie(cookieString, key);\n\t\t},\n\t\tsetItem: (key: string, value: string) => {\n\t\t\tif (typeof document === \"undefined\") return;\n\n\t\t\t// Warn if value exceeds recommended size\n\t\t\tconst encodedValue = encodeURIComponent(value);\n\t\t\tif (encodedValue.length > COOKIE_MAX_SIZE) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`[kheopskit] Cookie value for \"${key}\" exceeds recommended size limit (${encodedValue.length} > ${COOKIE_MAX_SIZE} bytes). ` +\n\t\t\t\t\t\t\"This may cause issues with cookie storage. Consider reducing the number of connected wallets.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Set cookie with 1 year expiry\n\t\t\tconst expires = new Date();\n\t\t\texpires.setFullYear(expires.getFullYear() + 1);\n\n\t\t\t// Build cookie string with security attributes\n\t\t\tlet cookieStr = `${key}=${encodedValue};expires=${expires.toUTCString()};path=/;SameSite=Lax`;\n\t\t\tif (isSecureConnection()) {\n\t\t\t\tcookieStr += \";Secure\";\n\t\t\t}\n\n\t\t\t// biome-ignore lint: necessary for cookie storage - direct cookie assignment is the standard API\n\t\t\tdocument.cookie = cookieStr;\n\n\t\t\t// Broadcast change to other tabs\n\t\t\tgetBroadcastChannel()?.postMessage({ type: \"set\", key, value });\n\t\t},\n\t\tremoveItem: (key: string) => {\n\t\t\tif (typeof document === \"undefined\") return;\n\n\t\t\t// Build delete cookie string\n\t\t\tlet cookieStr = `${key}=;expires=Thu, 01 Jan 1970 00:00:01 GMT;path=/;SameSite=Lax`;\n\t\t\tif (isSecureConnection()) {\n\t\t\t\tcookieStr += \";Secure\";\n\t\t\t}\n\n\t\t\t// biome-ignore lint: necessary for cookie storage - direct cookie assignment is the standard API\n\t\t\tdocument.cookie = cookieStr;\n\n\t\t\t// Broadcast change to other tabs\n\t\t\tgetBroadcastChannel()?.postMessage({ type: \"remove\", key });\n\t\t},\n\t\tsubscribe: (key: string, callback: (value: string | null) => void) => {\n\t\t\tconst channel = getBroadcastChannel();\n\t\t\tif (!channel) return () => {};\n\n\t\t\tconst handler = (event: MessageEvent) => {\n\t\t\t\tconst data = event.data as {\n\t\t\t\t\ttype: string;\n\t\t\t\t\tkey: string;\n\t\t\t\t\tvalue?: string;\n\t\t\t\t};\n\t\t\t\tif (data.key === key) {\n\t\t\t\t\tif (data.type === \"set\") {\n\t\t\t\t\t\tcallback(data.value ?? null);\n\t\t\t\t\t} else if (data.type === \"remove\") {\n\t\t\t\t\t\tcallback(null);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tchannel.addEventListener(\"message\", handler);\n\t\t\treturn () => {\n\t\t\t\tchannel.removeEventListener(\"message\", handler);\n\t\t\t};\n\t\t},\n\t};\n};\n\n/**\n * Cleanup the shared BroadcastChannel used for cross-tab cookie sync.\n * Call this when you're done using cookie storage (e.g., in tests or when unmounting).\n *\n * @remarks\n * In normal browser usage, you typically don't need to call this -\n * the channel will be cleaned up when the page is closed.\n * This is primarily useful for testing environments where multiple\n * test runs may accumulate channels.\n */\nexport const cleanupBroadcastChannel = (): void => {\n\tif (sharedBroadcastChannel) {\n\t\tsharedBroadcastChannel.close();\n\t\tsharedBroadcastChannel = null;\n\t}\n};\n","import { safeLocalStorage } from \"./storage\";\n\n/**\n * Storage key for the icon cache in localStorage.\n */\nconst ICON_CACHE_KEY = \"kheopskit-icons\";\n\n/**\n * Icon cache type: a map of wallet ID to icon data URI or URL.\n */\ntype IconCache = Record<string, string>;\n\n/**\n * In-memory cache to avoid repeated localStorage reads.\n */\nlet memoryCache: IconCache | null = null;\n\n/**\n * Loads the icon cache from localStorage.\n */\nconst loadCache = (): IconCache => {\n\tif (memoryCache !== null) return memoryCache;\n\n\ttry {\n\t\tconst stored = safeLocalStorage.getItem(ICON_CACHE_KEY);\n\t\tmemoryCache = stored ? (JSON.parse(stored) as IconCache) : {};\n\t} catch {\n\t\tmemoryCache = {};\n\t}\n\treturn memoryCache;\n};\n\n/**\n * Saves the icon cache to localStorage.\n */\nconst saveCache = (cache: IconCache): void => {\n\ttry {\n\t\tsafeLocalStorage.setItem(ICON_CACHE_KEY, JSON.stringify(cache));\n\t\tmemoryCache = cache;\n\t} catch {\n\t\t// localStorage may be full or unavailable\n\t}\n};\n\n/**\n * Gets a cached icon for a wallet.\n * @param walletId - The wallet ID (e.g., \"ethereum:io.talisman\")\n * @returns The cached icon data URI, or undefined if not cached\n */\nexport const getCachedIcon = (walletId: string): string | undefined => {\n\tconst cache = loadCache();\n\treturn cache[walletId] || undefined;\n};\n\n/**\n * Sets multiple cached icons at once.\n * More efficient than calling setCachedIcon multiple times.\n * @param icons - Map of wallet ID to icon\n */\nexport const setCachedIcons = (icons: Record<string, string>): void => {\n\tconst cache = loadCache();\n\tlet changed = false;\n\n\tfor (const [walletId, icon] of Object.entries(icons)) {\n\t\tif (icon && cache[walletId] !== icon) {\n\t\t\tcache[walletId] = icon;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\tif (changed) {\n\t\tsaveCache(cache);\n\t}\n};\n"],"mappings":"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"}
|