w3pk 0.10.4 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +47 -95
  2. package/dist/chainlist/index.d.mts +2 -2
  3. package/dist/chainlist/index.d.ts +2 -2
  4. package/dist/chainlist/index.js.map +1 -1
  5. package/dist/chainlist/index.mjs.map +1 -1
  6. package/dist/index.d.mts +940 -892
  7. package/dist/index.d.ts +940 -892
  8. package/dist/index.js +1135 -470
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +1135 -470
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/zk/index.d.mts +177 -4
  13. package/dist/zk/index.d.ts +177 -4
  14. package/dist/zk/index.js +5 -5
  15. package/dist/zk/index.js.map +1 -1
  16. package/dist/zk/index.mjs +5 -5
  17. package/dist/zk/index.mjs.map +1 -1
  18. package/dist/zk/prove-worker.mjs.map +1 -0
  19. package/dist/zk/utils.js +3 -3
  20. package/dist/zk/utils.js.map +1 -1
  21. package/dist/zk/utils.mjs +3 -3
  22. package/dist/zk/utils.mjs.map +1 -1
  23. package/docs/API_REFERENCE.md +517 -843
  24. package/docs/ARCHITECTURE.md +86 -106
  25. package/docs/BROWSER_COMPATIBILITY.md +15 -2
  26. package/docs/BUILD_VERIFICATION.md +35 -8
  27. package/docs/EIP-7951.md +1 -8
  28. package/docs/EIP_7702.md +35 -395
  29. package/docs/INTEGRATION_GUIDELINES.md +69 -818
  30. package/docs/JUNE_9_2026_AUDIT.md +207 -0
  31. package/docs/PORTABILITY.md +41 -186
  32. package/docs/POST_QUANTUM.md +61 -39
  33. package/docs/RECOVERY.md +165 -173
  34. package/docs/SECURITY.md +301 -891
  35. package/docs/ZK.md +250 -0
  36. package/package.json +32 -54
  37. package/dist/chainlist/index.js +0 -2
  38. package/dist/chainlist/index.mjs +0 -2
  39. package/dist/inspect/browser.d.mts +0 -106
  40. package/dist/inspect/browser.d.ts +0 -106
  41. package/dist/inspect/browser.js +0 -194
  42. package/dist/inspect/browser.js.map +0 -1
  43. package/dist/inspect/browser.mjs +0 -173
  44. package/dist/inspect/browser.mjs.map +0 -1
  45. package/dist/inspect/index.d.mts +0 -1
  46. package/dist/inspect/index.d.ts +0 -1
  47. package/dist/inspect/index.js +0 -196
  48. package/dist/inspect/index.js.map +0 -1
  49. package/dist/inspect/index.mjs +0 -173
  50. package/dist/inspect/index.mjs.map +0 -1
  51. package/dist/inspect/node.d.mts +0 -112
  52. package/dist/inspect/node.d.ts +0 -112
  53. package/dist/inspect/node.js +0 -287
  54. package/dist/inspect/node.js.map +0 -1
  55. package/dist/inspect/node.mjs +0 -251
  56. package/dist/inspect/node.mjs.map +0 -1
  57. package/docs/notes/IFRAME_IMPLEMENTATION_PLAN.md +0 -197
  58. package/docs/notes/JULY_13_ROADMAP.md +0 -29
  59. package/docs/notes/NOTES.md +0 -333
  60. package/docs/notes/SIWE_IMPLEMENTATION.md +0 -129
  61. package/docs/notes/SYNCING_ACROSS_DEVICES.md +0 -127
  62. package/docs/notes/ethereum-post-quantum-roadmap.md +0 -213
  63. package/docs/notes/wulong-building-finding.md +0 -109
package/README.md CHANGED
@@ -51,34 +51,29 @@ const endpoints = await w3pk.getEndpoints(1)
51
51
  - On-chain transaction sending with automatic RPC resolution (`sendTransaction`)
52
52
  - EIP-1193 provider for ethers, viem, wagmi, RainbowKit (`getEIP1193Provider`)
53
53
  - ERC-5564 stealth addresses (opt-in)
54
- - ZK primitives (zero-knowledge proof generation and verification)
55
- - Post-quantum encryption (ML-KEM-1024/Kyber NIST FIPS 203)
54
+ - ZK primitives (zero-knowledge proof generation and verification, Baby Jubjub keys, exponential ElGamal and circuit artifact verification against onchain pins in `w3pk/zk`, passkey-bound Semaphore identities with `getSemaphoreIdentity()`, and proofs over a passkey-bound secret the app never sees with `zkProve()`)
55
+ - Hybrid post-quantum encryption (HPKE over ML-KEM-1024 + X25519)
56
56
  - Chainlist support (2390+ networks)
57
57
  - EIP-7702 network detection (329+ networks)
58
- - External wallet integration (delegate MetaMask/Ledger to w3pk via EIP-7702)
59
58
  - EIP-7951 PRIMARY mode (P-256 passkey signing)
60
59
  - Build verification (IPFS CID hashing + DAO-maintained onchain registry)
61
60
  - Three-layer backup & recovery (passkey sync, encrypted backups, social recovery)
62
- - AI-powered host app inspection
63
61
 
64
62
  ## API
65
63
 
66
64
  ### Authentication
67
65
 
68
66
  ```typescript
69
- // Check for existing wallet
70
- const hasWallet = await w3pk.hasExistingCredential()
67
+ // List all wallets on device
68
+ const wallets = await w3pk.listExistingCredentials()
71
69
 
72
70
  // Register or login
73
- if (hasWallet) {
71
+ if (wallets.length > 0) {
74
72
  await w3pk.login()
75
73
  } else {
76
74
  const { address, username } = await w3pk.register({ username: 'alice' })
77
75
  }
78
76
 
79
- // List all wallets on device
80
- const wallets = await w3pk.listExistingCredentials()
81
-
82
77
  // Logout
83
78
  await w3pk.logout()
84
79
  ```
@@ -112,7 +107,7 @@ const strictWallet = await w3pk.deriveWallet('STRICT', 'SECURE')
112
107
  console.log(mainWallet.address !== gamingWallet.address) // true
113
108
  ```
114
109
 
115
- **Security:** Master mnemonic is never exposed. Applications cannot access `exportMnemonic()`.
110
+ **Security:** Master mnemonic is never exposed. No method returns it, and restores (`restoreFromBackupFile()`, `syncWalletWithPasskey()`, `recoverFromGuardians()`) return only the address.
116
111
 
117
112
  ### Message Signing
118
113
 
@@ -134,7 +129,7 @@ const eip712Sig = await w3pk.signMessage(JSON.stringify(typedData), {
134
129
  eip712PrimaryType: 'Transfer'
135
130
  })
136
131
 
137
- // Raw hash
132
+ // Raw hash (always prompts for the passkey)
138
133
  const rawSig = await w3pk.signMessage(hash, {
139
134
  signingMethod: 'rawHash'
140
135
  })
@@ -218,7 +213,7 @@ const hash = await client.sendTransaction({ to: '0x...', value: parseEther('1')
218
213
  | `eth_chainId` | Returns active chain as hex |
219
214
  | `eth_sendTransaction` | Delegates to `sendTransaction()` |
220
215
  | `personal_sign` / `eth_sign` | EIP-191 message signing |
221
- | `eth_signTypedData_v4` | EIP-712 typed data signing |
216
+ | `eth_signTypedData_v4` | EIP-712 typed data signing, bound to the active chain |
222
217
  | `wallet_switchEthereumChain` | Updates active chainId, emits `chainChanged` |
223
218
 
224
219
  ### Session Management
@@ -257,7 +252,7 @@ await w3pk.clearSession()
257
252
 
258
253
  **Note:** STRICT mode never allows persistent sessions.
259
254
 
260
- **PRF-keyed persistence:** persistent sessions are encrypted under a key derived from the WebAuthn PRF extension (an authenticator-held secret, released only during a biometric/PIN-verified assertion) and re-keyed at every real login. Authenticators without PRF support get in-memory sessions only — there is no weaker at-rest fallback. See [Security Architecture](./docs/SECURITY.md) for details.
255
+ **PRF-keyed storage:** the wallet stored on the device and persistent sessions are encrypted under keys derived from the WebAuthn PRF extension (an authenticator-held secret, released only during a biometric/PIN-verified assertion), so storage alone can't decrypt them. Authenticators without PRF support keep no wallet on the device and get in-memory sessions only: the wallet comes back from a backup on the next visit. There is no weaker at-rest fallback. See [Security Architecture](./docs/SECURITY.md) for details.
261
256
 
262
257
  ### RPC Endpoints
263
258
 
@@ -292,13 +287,6 @@ const authorization = await w3pk.signAuthorization({
292
287
  nonce: 0n
293
288
  })
294
289
  // Returns: { chainId, address, nonce, yParity, r, s }
295
-
296
- // Delegate external wallet (MetaMask, Ledger, etc.) to w3pk account
297
- const auth = await w3pk.requestExternalWalletDelegation({
298
- chainId: 1,
299
- nonce: 0n
300
- })
301
- // User's external wallet account now controlled by w3pk WebAuthn
302
290
  ```
303
291
 
304
292
  ### EIP-7951 PRIMARY Mode
@@ -333,17 +321,30 @@ const result = await w3pk.stealth?.parseAnnouncement({
333
321
  })
334
322
 
335
323
  if (result.isForUser) {
336
- console.log('Private key:', result.stealthPrivateKey)
324
+ console.log('Payment received at:', result.stealthAddress)
337
325
  }
338
326
 
339
327
  // Scan multiple announcements
340
328
  const myPayments = await w3pk.stealth?.scanAnnouncements(announcements)
329
+
330
+ // Sign a transaction from a stealth address (broadcast it with your own RPC)
331
+ const signedTx = await w3pk.stealth?.signTransaction(announcement, {
332
+ to: '0x...',
333
+ value: 1000000000000000n,
334
+ chainId: 11155111,
335
+ nonce: 0,
336
+ gasLimit: 21000n,
337
+ maxFeePerGas: 2000000000n,
338
+ maxPriorityFeePerGas: 1000000000n
339
+ })
341
340
  ```
342
341
 
343
- ### ML-KEM encryption
342
+ Stealth keys are shared across origins, and w3pk never returns the spending private key or a stealth private key: it signs from stealth addresses itself.
343
+
344
+ ### Post-quantum encryption
344
345
 
345
346
  ```typescript
346
- // Encrypt with post-quantum security (NIST FIPS 203)
347
+ // Hybrid ML-KEM-1024 + X25519 (HPKE, payload v3)
347
348
  const pubKey = await w3pk.deriveMLKemPublicKey()
348
349
  const encrypted = await w3pk.mlkemEncrypt('secret', [pubKey])
349
350
  const plaintext = await w3pk.mlkemDecrypt(encrypted)
@@ -355,48 +356,47 @@ const plaintext = await w3pk.mlkemDecrypt(encrypted)
355
356
  import { isStrongPassword } from 'w3pk'
356
357
 
357
358
  // Validate password strength
358
- const password = 'MyS3cur3!Password@2042'
359
+ const password = 'violet lantern under seven bridges'
359
360
  if (!isStrongPassword(password)) {
360
- throw new Error('Password must be 12+ chars with uppercase, lowercase, number, special char')
361
+ throw new Error('Password must be 15+ characters and not a common password')
361
362
  }
362
363
 
363
364
  // Get backup status
364
365
  const status = await w3pk.getBackupStatus()
365
- console.log('Security Score:', status.securityScore.total) // 0-100
366
+ console.log('Security Score:', status.securityScore.total) // 0-70
367
+ console.log('Next backup:', status.recommendedMode) // 'password', then 'prf'
366
368
 
367
- // Create encrypted backup file
368
- const { blob, filename } = await w3pk.createBackupFile('password', password)
369
+ // Create encrypted backup file (BackupFile v3: Argon2id, no address in the file)
370
+ const { blob, filename } = await w3pk.createBackupFile(password)
369
371
 
370
372
  // Setup social recovery (M-of-N guardians) - guardians store backup file fragments
371
- import { SocialRecoveryManager } from 'w3pk'
372
- const backupFileJson = await blob.text()
373
- const socialRecovery = new SocialRecoveryManager()
374
- const guardians = await socialRecovery.setupSocialRecovery(
375
- backupFileJson,
376
- w3pk.user.ethereumAddress,
373
+ const { guardianShares } = await w3pk.setupSocialRecovery(
377
374
  [
378
375
  { name: 'Alice', email: 'alice@example.com' },
379
- { name: 'Bob', phone: '+1234567890' },
376
+ { name: 'Bob' },
380
377
  { name: 'Charlie' }
381
378
  ],
382
- 2 // threshold
379
+ 2, // threshold
380
+ password // encrypts the backup the shares rebuild
383
381
  )
384
382
 
385
- // Generate guardian invite
386
- const invite = await socialRecovery.generateGuardianInvite(guardians[0])
383
+ // Generate guardian invite (share file, printable document, optional QR code)
384
+ const { downloadBlob, filename, shareDocument } = await w3pk.generateGuardianInvite(guardianShares[0])
387
385
 
388
- // Recover from guardian shares - reconstructs encrypted backup file
389
- const { backupFileJson } = await socialRecovery.recoverFromGuardians([share1, share2])
390
- await w3pk.registerWithBackupFile(backupFileJson, password, 'username')
386
+ // Recover from guardian share files - rebuilds and decrypts the backup
387
+ // (logged out: the wallet stays in memory for register(); logged in: it replaces the stored one)
388
+ const { ethereumAddress } = await w3pk.recoverFromGuardians([share1, share2], password)
391
389
 
392
- // Restore from backup file
390
+ // Restore from backup file (another wallet than the logged-in one needs
391
+ // the user's confirmation: { allowAddressChange: true })
393
392
  await w3pk.restoreFromBackupFile(encryptedData, password)
394
393
 
395
394
  // Simulate recovery scenarios
396
- const result = await w3pk.simulateRecoveryScenario({
397
- type: 'lost-device',
398
- description: 'Device lost with iCloud Keychain enabled'
399
- })
395
+ import { RecoverySimulator } from 'w3pk'
396
+ const result = await new RecoverySimulator().simulateScenario(
397
+ { type: 'lost-device', description: 'Device lost with iCloud Keychain enabled' },
398
+ await w3pk.getBackupStatus()
399
+ )
400
400
  ```
401
401
 
402
402
  ### Build Verification
@@ -428,53 +428,6 @@ console.log('Onchain CID:', onchainCid)
428
428
  console.log('Verified:', isValid ? '✅' : '❌')
429
429
  ```
430
430
 
431
- ### Security Inspection
432
-
433
- > **⚠️ Privacy Notice:** This optional feature sends application source code to an external API (Rukh) for AI analysis. User IP address will be visible to the API server.
434
-
435
- Analyze web3 applications to understand their transaction and signing methods:
436
-
437
- **Browser (analyze current page):**
438
- ```typescript
439
- import { inspect, inspectNow } from 'w3pk'
440
-
441
- // Full inspection with custom options
442
- const result = await inspect({
443
- appUrl: 'https://example.com',
444
- rukhUrl: 'https://rukh.w3hc.org',
445
- model: 'anthropic',
446
- focusMode: 'transactions'
447
- })
448
- console.log(result.report)
449
-
450
- // Quick console inspection
451
- await inspectNow() // Logs report directly to console
452
- ```
453
-
454
- **Note:** Inspection API calls are sponsored by the [W3HC (Web3 Hackers Collective)](https://w3hc.org).
455
-
456
- **Node.js (analyze local files):**
457
- ```typescript
458
- import { inspect, gatherCode } from 'w3pk/inspect/node'
459
-
460
- // Generate security report via Rukh API
461
- const report = await inspect(
462
- '../my-dapp', // App path
463
- 'https://rukh.w3hc.org', // Rukh API URL
464
- 'w3pk', // Context
465
- 'anthropic', // Model
466
- 'transactions' // Focus mode
467
- )
468
-
469
- // Or just gather code for analysis
470
- const result = await gatherCode({
471
- appPath: '../my-dapp',
472
- focusMode: 'transactions',
473
- maxFileSizeKB: 500
474
- })
475
- console.log(`Analyzed ${result.includedFiles.length} files`)
476
- ```
477
-
478
431
  ## Security & Verification
479
432
 
480
433
  ### Onchain Build Registry
@@ -493,7 +446,6 @@ Host applications should verify their installed W3PK build against this registry
493
446
  - [Integration Guidelines](./docs/INTEGRATION_GUIDELINES.md)
494
447
  - [API Reference](./docs/API_REFERENCE.md)
495
448
  - [Build Verification](./docs/BUILD_VERIFICATION.md)
496
- - [Security Inspection](./docs/INSPECTION.md)
497
449
  - [EIP-7951](./docs/EIP-7951.md)
498
450
  - [Security Architecture](./docs/SECURITY.md)
499
451
  - [Post-Quantum Cryptography](./docs/POST_QUANTUM.md) - Quantum-safe migration roadmap
@@ -51,11 +51,11 @@ interface ChainlistOptions {
51
51
  */
52
52
 
53
53
  /**
54
- * Get RPC endpoints for a specific chain ID, excluding those that require API keys
54
+ * Get the HTTPS RPC endpoints for a specific chain ID, excluding those that require API keys
55
55
  *
56
56
  * @param chainId - The chain ID to get endpoints for
57
57
  * @param options - Optional configuration
58
- * @returns Array of RPC URLs that don't require API keys
58
+ * @returns Array of HTTPS RPC URLs that don't require API keys
59
59
  *
60
60
  * @example
61
61
  * ```typescript
@@ -51,11 +51,11 @@ interface ChainlistOptions {
51
51
  */
52
52
 
53
53
  /**
54
- * Get RPC endpoints for a specific chain ID, excluding those that require API keys
54
+ * Get the HTTPS RPC endpoints for a specific chain ID, excluding those that require API keys
55
55
  *
56
56
  * @param chainId - The chain ID to get endpoints for
57
57
  * @param options - Optional configuration
58
- * @returns Array of RPC URLs that don't require API keys
58
+ * @returns Array of HTTPS RPC URLs that don't require API keys
59
59
  *
60
60
  * @example
61
61
  * ```typescript
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/chainlist/index.ts"],"sourcesContent":["/**\n * Chainlist module for fetching RPC endpoints\n */\n\nimport type { Chain, ChainlistOptions } from \"./types\";\n\nconst DEFAULT_CHAINS_URL = \"https://chainid.network/chains.json\";\nconst DEFAULT_CACHE_DURATION = 3600000; // 1 hour\n\ninterface CacheEntry {\n data: Chain[];\n timestamp: number;\n}\n\nlet cache: CacheEntry | null = null;\n\n/**\n * Patterns that indicate an RPC URL requires an API key\n */\nconst API_KEY_PATTERNS = [\n /\\$\\{[\\w_]+\\}/i, // ${INFURA_API_KEY}, ${API_KEY}, etc.\n /\\{[\\w_]+\\}/i, // {API_KEY}, {INFURA_API_KEY}, etc.\n /<[\\w_]+>/i, // <API_KEY>, <INFURA_API_KEY>, etc.\n /YOUR[-_]?API[-_]?KEY/i,\n /INSERT[-_]?API[-_]?KEY/i,\n /API[-_]?KEY[-_]?HERE/i,\n];\n\n/**\n * Check if an RPC URL requires an API key\n */\nfunction requiresApiKey(rpcUrl: string): boolean {\n return API_KEY_PATTERNS.some((pattern) => pattern.test(rpcUrl));\n}\n\n/**\n * Fetch all chains data from chainid.network\n */\nasync function fetchChains(\n chainsJsonUrl: string = DEFAULT_CHAINS_URL\n): Promise<Chain[]> {\n const response = await fetch(chainsJsonUrl);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch chains data: ${response.status} ${response.statusText}`\n );\n }\n\n return await response.json();\n}\n\n/**\n * Get all chains data with caching\n */\nasync function getChainsData(options?: ChainlistOptions): Promise<Chain[]> {\n const chainsJsonUrl = options?.chainsJsonUrl ?? DEFAULT_CHAINS_URL;\n const cacheDuration = options?.cacheDuration ?? DEFAULT_CACHE_DURATION;\n const now = Date.now();\n\n // Check if cache is valid\n if (cache && now - cache.timestamp < cacheDuration) {\n return cache.data;\n }\n\n // Fetch fresh data\n const data = await fetchChains(chainsJsonUrl);\n cache = { data, timestamp: now };\n\n return data;\n}\n\n/**\n * Get RPC endpoints for a specific chain ID, excluding those that require API keys\n *\n * @param chainId - The chain ID to get endpoints for\n * @param options - Optional configuration\n * @returns Array of RPC URLs that don't require API keys\n *\n * @example\n * ```typescript\n * import { getEndpoints } from 'w3pk/chainlist'\n *\n * // Get Ethereum mainnet RPCs\n * const endpoints = await getEndpoints(1)\n * console.log(endpoints)\n * // [\n * // \"https://api.mycryptoapi.com/eth\",\n * // \"https://cloudflare-eth.com\",\n * // \"https://ethereum-rpc.publicnode.com\",\n * // ...\n * // ]\n * ```\n */\nexport async function getEndpoints(\n chainId: number,\n options?: ChainlistOptions\n): Promise<string[]> {\n const chains = await getChainsData(options);\n const chain = chains.find((c) => c.chainId === chainId);\n\n if (!chain) {\n return [];\n }\n\n // Filter out RPC URLs that require API keys and websocket URLs\n return chain.rpc.filter(\n (rpcUrl) =>\n !requiresApiKey(rpcUrl) &&\n !rpcUrl.startsWith(\"wss://\") &&\n !rpcUrl.startsWith(\"ws://\")\n );\n}\n\n/**\n * Get all available chains\n *\n * @param options - Optional configuration\n * @returns Array of all chains\n */\nexport async function getAllChains(\n options?: ChainlistOptions\n): Promise<Chain[]> {\n return getChainsData(options);\n}\n\n/**\n * Get chain information by chain ID\n *\n * @param chainId - The chain ID to get information for\n * @param options - Optional configuration\n * @returns Chain information or undefined if not found\n */\nexport async function getChainById(\n chainId: number,\n options?: ChainlistOptions\n): Promise<Chain | undefined> {\n const chains = await getChainsData(options);\n return chains.find((c) => c.chainId === chainId);\n}\n\n/**\n * Clear the chains data cache\n */\nexport function clearCache(): void {\n cache = null;\n}\n\n// Export types\nexport type { Chain, ChainlistOptions } from \"./types\";\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,gBAAAE,EAAA,iBAAAC,EAAA,iBAAAC,EAAA,iBAAAC,IAAA,eAAAC,EAAAN,GAMA,IAAMO,EAAqB,sCAQ3B,IAAIC,EAA2B,KAKzBC,EAAmB,CACvB,gBACA,cACA,YACA,wBACA,0BACA,uBACF,EAKA,SAASC,EAAeC,EAAyB,CAC/C,OAAOF,EAAiB,KAAMG,GAAYA,EAAQ,KAAKD,CAAM,CAAC,CAChE,CAKA,eAAeE,EACbC,EAAwBC,EACN,CAClB,IAAMC,EAAW,MAAM,MAAMF,CAAa,EAE1C,GAAI,CAACE,EAAS,GACZ,MAAM,IAAI,MACR,gCAAgCA,EAAS,MAAM,IAAIA,EAAS,UAAU,EACxE,EAGF,OAAO,MAAMA,EAAS,KAAK,CAC7B,CAKA,eAAeC,EAAcC,EAA8C,CACzE,IAAMJ,EAAgBI,GAAS,eAAiBH,EAC1CI,EAAgBD,GAAS,eAAiB,KAC1CE,EAAM,KAAK,IAAI,EAGrB,GAAIZ,GAASY,EAAMZ,EAAM,UAAYW,EACnC,OAAOX,EAAM,KAIf,IAAMa,EAAO,MAAMR,EAAYC,CAAa,EAC5C,OAAAN,EAAQ,CAAE,KAAAa,EAAM,UAAWD,CAAI,EAExBC,CACT,CAwBA,eAAsBC,EACpBC,EACAL,EACmB,CAEnB,IAAMM,GADS,MAAMP,EAAcC,CAAO,GACrB,KAAMO,GAAMA,EAAE,UAAYF,CAAO,EAEtD,OAAKC,EAKEA,EAAM,IAAI,OACdb,GACC,CAACD,EAAeC,CAAM,GACtB,CAACA,EAAO,WAAW,QAAQ,GAC3B,CAACA,EAAO,WAAW,OAAO,CAC9B,EATS,CAAC,CAUZ,CAQA,eAAsBe,EACpBR,EACkB,CAClB,OAAOD,EAAcC,CAAO,CAC9B,CASA,eAAsBS,EACpBJ,EACAL,EAC4B,CAE5B,OADe,MAAMD,EAAcC,CAAO,GAC5B,KAAMO,GAAMA,EAAE,UAAYF,CAAO,CACjD,CAKO,SAASK,GAAmB,CACjCpB,EAAQ,IACV","names":["chainlist_exports","__export","clearCache","getAllChains","getChainById","getEndpoints","__toCommonJS","DEFAULT_CHAINS_URL","cache","API_KEY_PATTERNS","requiresApiKey","rpcUrl","pattern","fetchChains","chainsJsonUrl","DEFAULT_CHAINS_URL","response","getChainsData","options","cacheDuration","now","data","getEndpoints","chainId","chain","c","getAllChains","getChainById","clearCache"]}
1
+ {"version":3,"sources":["../../src/chainlist/index.ts"],"sourcesContent":["/**\n * Chainlist module for fetching RPC endpoints\n */\n\nimport type { Chain, ChainlistOptions } from \"./types\";\n\nconst DEFAULT_CHAINS_URL = \"https://chainid.network/chains.json\";\nconst DEFAULT_CACHE_DURATION = 3600000; // 1 hour\n\ninterface CacheEntry {\n data: Chain[];\n timestamp: number;\n}\n\nlet cache: CacheEntry | null = null;\n\n/**\n * Patterns that indicate an RPC URL requires an API key\n */\nconst API_KEY_PATTERNS = [\n /\\$\\{[\\w_]+\\}/i, // ${INFURA_API_KEY}, ${API_KEY}, etc.\n /\\{[\\w_]+\\}/i, // {API_KEY}, {INFURA_API_KEY}, etc.\n /<[\\w_]+>/i, // <API_KEY>, <INFURA_API_KEY>, etc.\n /YOUR[-_]?API[-_]?KEY/i,\n /INSERT[-_]?API[-_]?KEY/i,\n /API[-_]?KEY[-_]?HERE/i,\n];\n\n/**\n * Check if an RPC URL requires an API key\n */\nfunction requiresApiKey(rpcUrl: string): boolean {\n return API_KEY_PATTERNS.some((pattern) => pattern.test(rpcUrl));\n}\n\n/**\n * Fetch all chains data from chainid.network\n */\nasync function fetchChains(\n chainsJsonUrl: string = DEFAULT_CHAINS_URL\n): Promise<Chain[]> {\n const response = await fetch(chainsJsonUrl);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch chains data: ${response.status} ${response.statusText}`\n );\n }\n\n return await response.json();\n}\n\n/**\n * Get all chains data with caching\n */\nasync function getChainsData(options?: ChainlistOptions): Promise<Chain[]> {\n const chainsJsonUrl = options?.chainsJsonUrl ?? DEFAULT_CHAINS_URL;\n const cacheDuration = options?.cacheDuration ?? DEFAULT_CACHE_DURATION;\n const now = Date.now();\n\n // Check if cache is valid\n if (cache && now - cache.timestamp < cacheDuration) {\n return cache.data;\n }\n\n // Fetch fresh data\n const data = await fetchChains(chainsJsonUrl);\n cache = { data, timestamp: now };\n\n return data;\n}\n\n/**\n * Get the HTTPS RPC endpoints for a specific chain ID, excluding those that require API keys\n *\n * @param chainId - The chain ID to get endpoints for\n * @param options - Optional configuration\n * @returns Array of HTTPS RPC URLs that don't require API keys\n *\n * @example\n * ```typescript\n * import { getEndpoints } from 'w3pk/chainlist'\n *\n * // Get Ethereum mainnet RPCs\n * const endpoints = await getEndpoints(1)\n * console.log(endpoints)\n * // [\n * // \"https://api.mycryptoapi.com/eth\",\n * // \"https://cloudflare-eth.com\",\n * // \"https://ethereum-rpc.publicnode.com\",\n * // ...\n * // ]\n * ```\n */\nexport async function getEndpoints(\n chainId: number,\n options?: ChainlistOptions\n): Promise<string[]> {\n const chains = await getChainsData(options);\n const chain = chains.find((c) => c.chainId === chainId);\n\n if (!chain) {\n return [];\n }\n\n return chain.rpc.filter(\n (rpcUrl) => rpcUrl.startsWith(\"https://\") && !requiresApiKey(rpcUrl)\n );\n}\n\n/**\n * Get all available chains\n *\n * @param options - Optional configuration\n * @returns Array of all chains\n */\nexport async function getAllChains(\n options?: ChainlistOptions\n): Promise<Chain[]> {\n return getChainsData(options);\n}\n\n/**\n * Get chain information by chain ID\n *\n * @param chainId - The chain ID to get information for\n * @param options - Optional configuration\n * @returns Chain information or undefined if not found\n */\nexport async function getChainById(\n chainId: number,\n options?: ChainlistOptions\n): Promise<Chain | undefined> {\n const chains = await getChainsData(options);\n return chains.find((c) => c.chainId === chainId);\n}\n\n/**\n * Clear the chains data cache\n */\nexport function clearCache(): void {\n cache = null;\n}\n\n// Export types\nexport type { Chain, ChainlistOptions } from \"./types\";\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,gBAAAE,EAAA,iBAAAC,EAAA,iBAAAC,EAAA,iBAAAC,IAAA,eAAAC,EAAAN,GAMA,IAAMO,EAAqB,sCAQ3B,IAAIC,EAA2B,KAKzBC,EAAmB,CACvB,gBACA,cACA,YACA,wBACA,0BACA,uBACF,EAKA,SAASC,EAAeC,EAAyB,CAC/C,OAAOF,EAAiB,KAAMG,GAAYA,EAAQ,KAAKD,CAAM,CAAC,CAChE,CAKA,eAAeE,EACbC,EAAwBC,EACN,CAClB,IAAMC,EAAW,MAAM,MAAMF,CAAa,EAE1C,GAAI,CAACE,EAAS,GACZ,MAAM,IAAI,MACR,gCAAgCA,EAAS,MAAM,IAAIA,EAAS,UAAU,EACxE,EAGF,OAAO,MAAMA,EAAS,KAAK,CAC7B,CAKA,eAAeC,EAAcC,EAA8C,CACzE,IAAMJ,EAAgBI,GAAS,eAAiBH,EAC1CI,EAAgBD,GAAS,eAAiB,KAC1CE,EAAM,KAAK,IAAI,EAGrB,GAAIZ,GAASY,EAAMZ,EAAM,UAAYW,EACnC,OAAOX,EAAM,KAIf,IAAMa,EAAO,MAAMR,EAAYC,CAAa,EAC5C,OAAAN,EAAQ,CAAE,KAAAa,EAAM,UAAWD,CAAI,EAExBC,CACT,CAwBA,eAAsBC,EACpBC,EACAL,EACmB,CAEnB,IAAMM,GADS,MAAMP,EAAcC,CAAO,GACrB,KAAMO,GAAMA,EAAE,UAAYF,CAAO,EAEtD,OAAKC,EAIEA,EAAM,IAAI,OACdb,GAAWA,EAAO,WAAW,UAAU,GAAK,CAACD,EAAeC,CAAM,CACrE,EALS,CAAC,CAMZ,CAQA,eAAsBe,EACpBR,EACkB,CAClB,OAAOD,EAAcC,CAAO,CAC9B,CASA,eAAsBS,EACpBJ,EACAL,EAC4B,CAE5B,OADe,MAAMD,EAAcC,CAAO,GAC5B,KAAMO,GAAMA,EAAE,UAAYF,CAAO,CACjD,CAKO,SAASK,GAAmB,CACjCpB,EAAQ,IACV","names":["chainlist_exports","__export","clearCache","getAllChains","getChainById","getEndpoints","__toCommonJS","DEFAULT_CHAINS_URL","cache","API_KEY_PATTERNS","requiresApiKey","rpcUrl","pattern","fetchChains","chainsJsonUrl","DEFAULT_CHAINS_URL","response","getChainsData","options","cacheDuration","now","data","getEndpoints","chainId","chain","c","getAllChains","getChainById","clearCache"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/chainlist/index.ts"],"sourcesContent":["/**\n * Chainlist module for fetching RPC endpoints\n */\n\nimport type { Chain, ChainlistOptions } from \"./types\";\n\nconst DEFAULT_CHAINS_URL = \"https://chainid.network/chains.json\";\nconst DEFAULT_CACHE_DURATION = 3600000; // 1 hour\n\ninterface CacheEntry {\n data: Chain[];\n timestamp: number;\n}\n\nlet cache: CacheEntry | null = null;\n\n/**\n * Patterns that indicate an RPC URL requires an API key\n */\nconst API_KEY_PATTERNS = [\n /\\$\\{[\\w_]+\\}/i, // ${INFURA_API_KEY}, ${API_KEY}, etc.\n /\\{[\\w_]+\\}/i, // {API_KEY}, {INFURA_API_KEY}, etc.\n /<[\\w_]+>/i, // <API_KEY>, <INFURA_API_KEY>, etc.\n /YOUR[-_]?API[-_]?KEY/i,\n /INSERT[-_]?API[-_]?KEY/i,\n /API[-_]?KEY[-_]?HERE/i,\n];\n\n/**\n * Check if an RPC URL requires an API key\n */\nfunction requiresApiKey(rpcUrl: string): boolean {\n return API_KEY_PATTERNS.some((pattern) => pattern.test(rpcUrl));\n}\n\n/**\n * Fetch all chains data from chainid.network\n */\nasync function fetchChains(\n chainsJsonUrl: string = DEFAULT_CHAINS_URL\n): Promise<Chain[]> {\n const response = await fetch(chainsJsonUrl);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch chains data: ${response.status} ${response.statusText}`\n );\n }\n\n return await response.json();\n}\n\n/**\n * Get all chains data with caching\n */\nasync function getChainsData(options?: ChainlistOptions): Promise<Chain[]> {\n const chainsJsonUrl = options?.chainsJsonUrl ?? DEFAULT_CHAINS_URL;\n const cacheDuration = options?.cacheDuration ?? DEFAULT_CACHE_DURATION;\n const now = Date.now();\n\n // Check if cache is valid\n if (cache && now - cache.timestamp < cacheDuration) {\n return cache.data;\n }\n\n // Fetch fresh data\n const data = await fetchChains(chainsJsonUrl);\n cache = { data, timestamp: now };\n\n return data;\n}\n\n/**\n * Get RPC endpoints for a specific chain ID, excluding those that require API keys\n *\n * @param chainId - The chain ID to get endpoints for\n * @param options - Optional configuration\n * @returns Array of RPC URLs that don't require API keys\n *\n * @example\n * ```typescript\n * import { getEndpoints } from 'w3pk/chainlist'\n *\n * // Get Ethereum mainnet RPCs\n * const endpoints = await getEndpoints(1)\n * console.log(endpoints)\n * // [\n * // \"https://api.mycryptoapi.com/eth\",\n * // \"https://cloudflare-eth.com\",\n * // \"https://ethereum-rpc.publicnode.com\",\n * // ...\n * // ]\n * ```\n */\nexport async function getEndpoints(\n chainId: number,\n options?: ChainlistOptions\n): Promise<string[]> {\n const chains = await getChainsData(options);\n const chain = chains.find((c) => c.chainId === chainId);\n\n if (!chain) {\n return [];\n }\n\n // Filter out RPC URLs that require API keys and websocket URLs\n return chain.rpc.filter(\n (rpcUrl) =>\n !requiresApiKey(rpcUrl) &&\n !rpcUrl.startsWith(\"wss://\") &&\n !rpcUrl.startsWith(\"ws://\")\n );\n}\n\n/**\n * Get all available chains\n *\n * @param options - Optional configuration\n * @returns Array of all chains\n */\nexport async function getAllChains(\n options?: ChainlistOptions\n): Promise<Chain[]> {\n return getChainsData(options);\n}\n\n/**\n * Get chain information by chain ID\n *\n * @param chainId - The chain ID to get information for\n * @param options - Optional configuration\n * @returns Chain information or undefined if not found\n */\nexport async function getChainById(\n chainId: number,\n options?: ChainlistOptions\n): Promise<Chain | undefined> {\n const chains = await getChainsData(options);\n return chains.find((c) => c.chainId === chainId);\n}\n\n/**\n * Clear the chains data cache\n */\nexport function clearCache(): void {\n cache = null;\n}\n\n// Export types\nexport type { Chain, ChainlistOptions } from \"./types\";\n"],"mappings":"AAMA,IAAMA,EAAqB,sCAQ3B,IAAIC,EAA2B,KAKzBC,EAAmB,CACvB,gBACA,cACA,YACA,wBACA,0BACA,uBACF,EAKA,SAASC,EAAeC,EAAyB,CAC/C,OAAOF,EAAiB,KAAMG,GAAYA,EAAQ,KAAKD,CAAM,CAAC,CAChE,CAKA,eAAeE,EACbC,EAAwBC,EACN,CAClB,IAAMC,EAAW,MAAM,MAAMF,CAAa,EAE1C,GAAI,CAACE,EAAS,GACZ,MAAM,IAAI,MACR,gCAAgCA,EAAS,MAAM,IAAIA,EAAS,UAAU,EACxE,EAGF,OAAO,MAAMA,EAAS,KAAK,CAC7B,CAKA,eAAeC,EAAcC,EAA8C,CACzE,IAAMJ,EAAgBI,GAAS,eAAiBH,EAC1CI,EAAgBD,GAAS,eAAiB,KAC1CE,EAAM,KAAK,IAAI,EAGrB,GAAIZ,GAASY,EAAMZ,EAAM,UAAYW,EACnC,OAAOX,EAAM,KAIf,IAAMa,EAAO,MAAMR,EAAYC,CAAa,EAC5C,OAAAN,EAAQ,CAAE,KAAAa,EAAM,UAAWD,CAAI,EAExBC,CACT,CAwBA,eAAsBC,EACpBC,EACAL,EACmB,CAEnB,IAAMM,GADS,MAAMP,EAAcC,CAAO,GACrB,KAAMO,GAAMA,EAAE,UAAYF,CAAO,EAEtD,OAAKC,EAKEA,EAAM,IAAI,OACdb,GACC,CAACD,EAAeC,CAAM,GACtB,CAACA,EAAO,WAAW,QAAQ,GAC3B,CAACA,EAAO,WAAW,OAAO,CAC9B,EATS,CAAC,CAUZ,CAQA,eAAsBe,EACpBR,EACkB,CAClB,OAAOD,EAAcC,CAAO,CAC9B,CASA,eAAsBS,EACpBJ,EACAL,EAC4B,CAE5B,OADe,MAAMD,EAAcC,CAAO,GAC5B,KAAMO,GAAMA,EAAE,UAAYF,CAAO,CACjD,CAKO,SAASK,GAAmB,CACjCpB,EAAQ,IACV","names":["DEFAULT_CHAINS_URL","cache","API_KEY_PATTERNS","requiresApiKey","rpcUrl","pattern","fetchChains","chainsJsonUrl","DEFAULT_CHAINS_URL","response","getChainsData","options","cacheDuration","now","data","getEndpoints","chainId","chain","c","getAllChains","getChainById","clearCache"]}
1
+ {"version":3,"sources":["../../src/chainlist/index.ts"],"sourcesContent":["/**\n * Chainlist module for fetching RPC endpoints\n */\n\nimport type { Chain, ChainlistOptions } from \"./types\";\n\nconst DEFAULT_CHAINS_URL = \"https://chainid.network/chains.json\";\nconst DEFAULT_CACHE_DURATION = 3600000; // 1 hour\n\ninterface CacheEntry {\n data: Chain[];\n timestamp: number;\n}\n\nlet cache: CacheEntry | null = null;\n\n/**\n * Patterns that indicate an RPC URL requires an API key\n */\nconst API_KEY_PATTERNS = [\n /\\$\\{[\\w_]+\\}/i, // ${INFURA_API_KEY}, ${API_KEY}, etc.\n /\\{[\\w_]+\\}/i, // {API_KEY}, {INFURA_API_KEY}, etc.\n /<[\\w_]+>/i, // <API_KEY>, <INFURA_API_KEY>, etc.\n /YOUR[-_]?API[-_]?KEY/i,\n /INSERT[-_]?API[-_]?KEY/i,\n /API[-_]?KEY[-_]?HERE/i,\n];\n\n/**\n * Check if an RPC URL requires an API key\n */\nfunction requiresApiKey(rpcUrl: string): boolean {\n return API_KEY_PATTERNS.some((pattern) => pattern.test(rpcUrl));\n}\n\n/**\n * Fetch all chains data from chainid.network\n */\nasync function fetchChains(\n chainsJsonUrl: string = DEFAULT_CHAINS_URL\n): Promise<Chain[]> {\n const response = await fetch(chainsJsonUrl);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch chains data: ${response.status} ${response.statusText}`\n );\n }\n\n return await response.json();\n}\n\n/**\n * Get all chains data with caching\n */\nasync function getChainsData(options?: ChainlistOptions): Promise<Chain[]> {\n const chainsJsonUrl = options?.chainsJsonUrl ?? DEFAULT_CHAINS_URL;\n const cacheDuration = options?.cacheDuration ?? DEFAULT_CACHE_DURATION;\n const now = Date.now();\n\n // Check if cache is valid\n if (cache && now - cache.timestamp < cacheDuration) {\n return cache.data;\n }\n\n // Fetch fresh data\n const data = await fetchChains(chainsJsonUrl);\n cache = { data, timestamp: now };\n\n return data;\n}\n\n/**\n * Get the HTTPS RPC endpoints for a specific chain ID, excluding those that require API keys\n *\n * @param chainId - The chain ID to get endpoints for\n * @param options - Optional configuration\n * @returns Array of HTTPS RPC URLs that don't require API keys\n *\n * @example\n * ```typescript\n * import { getEndpoints } from 'w3pk/chainlist'\n *\n * // Get Ethereum mainnet RPCs\n * const endpoints = await getEndpoints(1)\n * console.log(endpoints)\n * // [\n * // \"https://api.mycryptoapi.com/eth\",\n * // \"https://cloudflare-eth.com\",\n * // \"https://ethereum-rpc.publicnode.com\",\n * // ...\n * // ]\n * ```\n */\nexport async function getEndpoints(\n chainId: number,\n options?: ChainlistOptions\n): Promise<string[]> {\n const chains = await getChainsData(options);\n const chain = chains.find((c) => c.chainId === chainId);\n\n if (!chain) {\n return [];\n }\n\n return chain.rpc.filter(\n (rpcUrl) => rpcUrl.startsWith(\"https://\") && !requiresApiKey(rpcUrl)\n );\n}\n\n/**\n * Get all available chains\n *\n * @param options - Optional configuration\n * @returns Array of all chains\n */\nexport async function getAllChains(\n options?: ChainlistOptions\n): Promise<Chain[]> {\n return getChainsData(options);\n}\n\n/**\n * Get chain information by chain ID\n *\n * @param chainId - The chain ID to get information for\n * @param options - Optional configuration\n * @returns Chain information or undefined if not found\n */\nexport async function getChainById(\n chainId: number,\n options?: ChainlistOptions\n): Promise<Chain | undefined> {\n const chains = await getChainsData(options);\n return chains.find((c) => c.chainId === chainId);\n}\n\n/**\n * Clear the chains data cache\n */\nexport function clearCache(): void {\n cache = null;\n}\n\n// Export types\nexport type { Chain, ChainlistOptions } from \"./types\";\n"],"mappings":"AAMA,IAAMA,EAAqB,sCAQ3B,IAAIC,EAA2B,KAKzBC,EAAmB,CACvB,gBACA,cACA,YACA,wBACA,0BACA,uBACF,EAKA,SAASC,EAAeC,EAAyB,CAC/C,OAAOF,EAAiB,KAAMG,GAAYA,EAAQ,KAAKD,CAAM,CAAC,CAChE,CAKA,eAAeE,EACbC,EAAwBC,EACN,CAClB,IAAMC,EAAW,MAAM,MAAMF,CAAa,EAE1C,GAAI,CAACE,EAAS,GACZ,MAAM,IAAI,MACR,gCAAgCA,EAAS,MAAM,IAAIA,EAAS,UAAU,EACxE,EAGF,OAAO,MAAMA,EAAS,KAAK,CAC7B,CAKA,eAAeC,EAAcC,EAA8C,CACzE,IAAMJ,EAAgBI,GAAS,eAAiBH,EAC1CI,EAAgBD,GAAS,eAAiB,KAC1CE,EAAM,KAAK,IAAI,EAGrB,GAAIZ,GAASY,EAAMZ,EAAM,UAAYW,EACnC,OAAOX,EAAM,KAIf,IAAMa,EAAO,MAAMR,EAAYC,CAAa,EAC5C,OAAAN,EAAQ,CAAE,KAAAa,EAAM,UAAWD,CAAI,EAExBC,CACT,CAwBA,eAAsBC,EACpBC,EACAL,EACmB,CAEnB,IAAMM,GADS,MAAMP,EAAcC,CAAO,GACrB,KAAMO,GAAMA,EAAE,UAAYF,CAAO,EAEtD,OAAKC,EAIEA,EAAM,IAAI,OACdb,GAAWA,EAAO,WAAW,UAAU,GAAK,CAACD,EAAeC,CAAM,CACrE,EALS,CAAC,CAMZ,CAQA,eAAsBe,EACpBR,EACkB,CAClB,OAAOD,EAAcC,CAAO,CAC9B,CASA,eAAsBS,EACpBJ,EACAL,EAC4B,CAE5B,OADe,MAAMD,EAAcC,CAAO,GAC5B,KAAMO,GAAMA,EAAE,UAAYF,CAAO,CACjD,CAKO,SAASK,GAAmB,CACjCpB,EAAQ,IACV","names":["DEFAULT_CHAINS_URL","cache","API_KEY_PATTERNS","requiresApiKey","rpcUrl","pattern","fetchChains","chainsJsonUrl","DEFAULT_CHAINS_URL","response","getChainsData","options","cacheDuration","now","data","getEndpoints","chainId","chain","c","getAllChains","getChainById","clearCache"]}