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.
- package/README.md +47 -95
- package/dist/chainlist/index.d.mts +2 -2
- package/dist/chainlist/index.d.ts +2 -2
- package/dist/chainlist/index.js.map +1 -1
- package/dist/chainlist/index.mjs.map +1 -1
- package/dist/index.d.mts +940 -892
- package/dist/index.d.ts +940 -892
- package/dist/index.js +1135 -470
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1135 -470
- package/dist/index.mjs.map +1 -1
- package/dist/zk/index.d.mts +177 -4
- package/dist/zk/index.d.ts +177 -4
- package/dist/zk/index.js +5 -5
- package/dist/zk/index.js.map +1 -1
- package/dist/zk/index.mjs +5 -5
- package/dist/zk/index.mjs.map +1 -1
- package/dist/zk/prove-worker.mjs.map +1 -0
- package/dist/zk/utils.js +3 -3
- package/dist/zk/utils.js.map +1 -1
- package/dist/zk/utils.mjs +3 -3
- package/dist/zk/utils.mjs.map +1 -1
- package/docs/API_REFERENCE.md +517 -843
- package/docs/ARCHITECTURE.md +86 -106
- package/docs/BROWSER_COMPATIBILITY.md +15 -2
- package/docs/BUILD_VERIFICATION.md +35 -8
- package/docs/EIP-7951.md +1 -8
- package/docs/EIP_7702.md +35 -395
- package/docs/INTEGRATION_GUIDELINES.md +69 -818
- package/docs/JUNE_9_2026_AUDIT.md +207 -0
- package/docs/PORTABILITY.md +41 -186
- package/docs/POST_QUANTUM.md +61 -39
- package/docs/RECOVERY.md +165 -173
- package/docs/SECURITY.md +301 -891
- package/docs/ZK.md +250 -0
- package/package.json +32 -54
- package/dist/chainlist/index.js +0 -2
- package/dist/chainlist/index.mjs +0 -2
- package/dist/inspect/browser.d.mts +0 -106
- package/dist/inspect/browser.d.ts +0 -106
- package/dist/inspect/browser.js +0 -194
- package/dist/inspect/browser.js.map +0 -1
- package/dist/inspect/browser.mjs +0 -173
- package/dist/inspect/browser.mjs.map +0 -1
- package/dist/inspect/index.d.mts +0 -1
- package/dist/inspect/index.d.ts +0 -1
- package/dist/inspect/index.js +0 -196
- package/dist/inspect/index.js.map +0 -1
- package/dist/inspect/index.mjs +0 -173
- package/dist/inspect/index.mjs.map +0 -1
- package/dist/inspect/node.d.mts +0 -112
- package/dist/inspect/node.d.ts +0 -112
- package/dist/inspect/node.js +0 -287
- package/dist/inspect/node.js.map +0 -1
- package/dist/inspect/node.mjs +0 -251
- package/dist/inspect/node.mjs.map +0 -1
- package/docs/notes/IFRAME_IMPLEMENTATION_PLAN.md +0 -197
- package/docs/notes/JULY_13_ROADMAP.md +0 -29
- package/docs/notes/NOTES.md +0 -333
- package/docs/notes/SIWE_IMPLEMENTATION.md +0 -129
- package/docs/notes/SYNCING_ACROSS_DEVICES.md +0 -127
- package/docs/notes/ethereum-post-quantum-roadmap.md +0 -213
- 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
|
-
-
|
|
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
|
-
//
|
|
70
|
-
const
|
|
67
|
+
// List all wallets on device
|
|
68
|
+
const wallets = await w3pk.listExistingCredentials()
|
|
71
69
|
|
|
72
70
|
// Register or login
|
|
73
|
-
if (
|
|
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.
|
|
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
|
|
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('
|
|
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
|
-
|
|
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
|
-
//
|
|
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 = '
|
|
359
|
+
const password = 'violet lantern under seven bridges'
|
|
359
360
|
if (!isStrongPassword(password)) {
|
|
360
|
-
throw new Error('Password must be
|
|
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-
|
|
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(
|
|
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
|
-
|
|
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'
|
|
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
|
|
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
|
|
389
|
-
|
|
390
|
-
await w3pk.
|
|
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
|
-
|
|
397
|
-
|
|
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
|
|
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
|
|
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"]}
|