w3pk 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +165 -49
- package/dist/chainlist/index.d.mts +96 -0
- package/dist/chainlist/index.d.ts +96 -0
- package/dist/chainlist/index.js +2 -0
- package/dist/chainlist/index.js.map +1 -0
- package/dist/chainlist/index.mjs +2 -0
- package/dist/chainlist/index.mjs.map +1 -0
- package/dist/index.d.mts +313 -134
- package/dist/index.d.ts +313 -134
- package/dist/index.js +5 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -9
- package/dist/index.mjs.map +1 -1
- package/docs/BROWSER_COMPATIBILITY.md +300 -0
- package/docs/BUNDLE_SIZES.md +154 -0
- package/docs/CHAINLIST.md +293 -0
- package/docs/ERC5564_FLOW_DIAGRAM.md +525 -0
- package/docs/ERC5564_STEALTH_ADDRESSES.md +763 -0
- package/docs/MIGRATION.md +234 -129
- package/docs/QUICK_START.md +35 -13
- package/docs/SECURITY.md +1027 -0
- package/docs/index.html +399 -0
- package/package.json +54 -40
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
Passwordless Web3 authentication SDK with encrypted wallets and privacy features.
|
|
7
7
|
|
|
8
|
-
**Demo
|
|
8
|
+
**Demo: [w3pk.w3hc.org](https://w3pk.w3hc.org)**
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
```bash
|
|
@@ -16,35 +16,38 @@ npm install w3pk ethers
|
|
|
16
16
|
```typescript
|
|
17
17
|
import { createWeb3Passkey } from 'w3pk'
|
|
18
18
|
|
|
19
|
-
const w3pk = createWeb3Passkey(
|
|
20
|
-
apiBaseUrl: 'https://webauthn.w3hc.org'
|
|
21
|
-
})
|
|
19
|
+
const w3pk = createWeb3Passkey()
|
|
22
20
|
|
|
23
|
-
// Register
|
|
24
|
-
await w3pk.register({
|
|
25
|
-
|
|
26
|
-
ethereumAddress: '0x...'
|
|
27
|
-
})
|
|
21
|
+
// Register (auto-generates wallet and stores it securely)
|
|
22
|
+
const { mnemonic } = await w3pk.register({ username: 'alice' })
|
|
23
|
+
console.log('⚠️ Save this recovery phrase:', mnemonic)
|
|
28
24
|
|
|
29
|
-
// Login
|
|
25
|
+
// Login (for subsequent sessions)
|
|
30
26
|
await w3pk.login()
|
|
31
27
|
|
|
32
28
|
// Sign message
|
|
33
29
|
const signature = await w3pk.signMessage('Hello World')
|
|
34
30
|
|
|
35
31
|
// Derive addresses
|
|
36
|
-
const
|
|
37
|
-
const
|
|
32
|
+
const wallet0 = await w3pk.deriveWallet(0)
|
|
33
|
+
const wallet1 = await w3pk.deriveWallet(1)
|
|
34
|
+
|
|
35
|
+
// Get RPC endpoints for any chain
|
|
36
|
+
const endpoints = await w3pk.getEndpoints(1) // Ethereum
|
|
37
|
+
const rpcUrl = endpoints[0]
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
## Features
|
|
41
41
|
|
|
42
42
|
**Core (Included)**
|
|
43
43
|
- 🔐 Passwordless authentication (WebAuthn/FIDO2)
|
|
44
|
-
-
|
|
44
|
+
- 🔒 Client-only biometric-gated wallet encryption (AES-GCM-256)
|
|
45
|
+
- ⏱️ Session management (configurable duration, prevents repeated prompts)
|
|
45
46
|
- 🌱 HD wallet generation (BIP39/BIP44)
|
|
46
47
|
- 🔢 Multi-address derivation
|
|
47
|
-
- 🥷
|
|
48
|
+
- 🥷 ERC-5564 stealth addresses (privacy-preserving transactions with view tags)
|
|
49
|
+
- 🔗 Chainlist support (2390+ networks, auto-filtered RPC endpoints)
|
|
50
|
+
- ⚡ EIP-7702 network detection (329+ supported networks)
|
|
48
51
|
|
|
49
52
|
**Optional: Zero-Knowledge Proofs**
|
|
50
53
|
|
|
@@ -53,39 +56,41 @@ Requires additional dependencies (~70MB):
|
|
|
53
56
|
npm install snarkjs circomlibjs
|
|
54
57
|
```
|
|
55
58
|
|
|
56
|
-
See [ZK Integration Guide](./docs/ZK_INTEGRATION_GUIDE.md)
|
|
57
|
-
- Anonymous membership proofs
|
|
58
|
-
- Private balance verification
|
|
59
|
-
- Range proofs without revealing values
|
|
60
|
-
- NFT ownership proofs
|
|
61
|
-
|
|
62
|
-
[Bundle size comparison →](./docs/BUNDLE_SIZES.md)
|
|
59
|
+
See [ZK Integration Guide](./docs/ZK_INTEGRATION_GUIDE.md) to get started.
|
|
63
60
|
|
|
64
61
|
## API
|
|
65
62
|
|
|
66
|
-
### Authentication
|
|
63
|
+
### Authentication Flow
|
|
64
|
+
|
|
67
65
|
```typescript
|
|
68
|
-
// Register
|
|
69
|
-
await w3pk.register({ username
|
|
66
|
+
// Register (auto-stores wallet)
|
|
67
|
+
const { mnemonic } = await w3pk.register({ username: 'alice' })
|
|
68
|
+
// Returns: { mnemonic } - SAVE THIS!
|
|
70
69
|
|
|
71
|
-
//
|
|
70
|
+
// Subsequent sessions: just login
|
|
72
71
|
await w3pk.login()
|
|
73
72
|
|
|
74
73
|
// Logout
|
|
75
74
|
await w3pk.logout()
|
|
76
75
|
|
|
77
|
-
//
|
|
76
|
+
// Status
|
|
78
77
|
w3pk.isAuthenticated
|
|
79
78
|
w3pk.user
|
|
80
79
|
```
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
**Advanced: Pre-generate wallet (optional)**
|
|
83
82
|
```typescript
|
|
84
|
-
//
|
|
85
|
-
const
|
|
83
|
+
// If you want to see the wallet before registering:
|
|
84
|
+
const { mnemonic } = await w3pk.generateWallet()
|
|
85
|
+
const { mnemonic } = await w3pk.register({ username: 'alice' })
|
|
86
|
+
// register() will use the pre-generated wallet
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Wallet Operations
|
|
86
90
|
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
```typescript
|
|
92
|
+
// Derive addresses
|
|
93
|
+
const wallet0 = await w3pk.deriveWallet(0)
|
|
89
94
|
// Returns: { address, privateKey }
|
|
90
95
|
|
|
91
96
|
// Export mnemonic
|
|
@@ -95,35 +100,146 @@ const mnemonic = await w3pk.exportMnemonic()
|
|
|
95
100
|
const signature = await w3pk.signMessage(message)
|
|
96
101
|
```
|
|
97
102
|
|
|
98
|
-
###
|
|
103
|
+
### Session Management
|
|
104
|
+
|
|
105
|
+
By default, after authentication, operations work for 1 hour without repeated biometric prompts:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Configure session duration
|
|
109
|
+
const w3pk = createWeb3Passkey({
|
|
110
|
+
sessionDuration: 2 // 2 hours (default: 1)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
// After login, mnemonic is cached in memory
|
|
114
|
+
await w3pk.login()
|
|
115
|
+
|
|
116
|
+
// These operations use the cached session
|
|
117
|
+
await w3pk.deriveWallet(0)
|
|
118
|
+
await w3pk.exportMnemonic()
|
|
119
|
+
await w3pk.signMessage('Hello')
|
|
120
|
+
await w3pk.stealth.getKeys()
|
|
121
|
+
|
|
122
|
+
// Check session status
|
|
123
|
+
w3pk.hasActiveSession() // true
|
|
124
|
+
w3pk.getSessionRemainingTime() // 3540 seconds
|
|
125
|
+
|
|
126
|
+
// Extend session
|
|
127
|
+
w3pk.extendSession() // Adds 2 more hours
|
|
128
|
+
|
|
129
|
+
// Clear session manually (force re-authentication)
|
|
130
|
+
w3pk.clearSession()
|
|
131
|
+
|
|
132
|
+
// Disable sessions (most secure - prompt every time)
|
|
133
|
+
const w3pk = createWeb3Passkey({ sessionDuration: 0 })
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Force Authentication for Sensitive Operations
|
|
137
|
+
|
|
138
|
+
Even with an active session, you can require fresh biometric authentication for specific operations:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
// Session is active, but force authentication anyway
|
|
142
|
+
await w3pk.exportMnemonic({ requireAuth: true })
|
|
143
|
+
await w3pk.signMessage('Transfer $1000', { requireAuth: true })
|
|
144
|
+
await w3pk.deriveWallet(5, { requireAuth: true })
|
|
145
|
+
await w3pk.stealth.getKeys({ requireAuth: true })
|
|
146
|
+
|
|
147
|
+
// Example: Require auth for high-value transactions
|
|
148
|
+
async function transferFunds(amount: number, recipient: string) {
|
|
149
|
+
// For transfers above $100, require fresh authentication
|
|
150
|
+
const requireAuth = amount > 100
|
|
151
|
+
|
|
152
|
+
const signature = await w3pk.signMessage(
|
|
153
|
+
`Transfer ${amount} to ${recipient}`,
|
|
154
|
+
{ requireAuth }
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
// ... submit transaction
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### RPC Endpoints
|
|
162
|
+
```typescript
|
|
163
|
+
// Get public RPC endpoints
|
|
164
|
+
const endpoints = await w3pk.getEndpoints(1) // Ethereum
|
|
165
|
+
const rpcUrl = endpoints[0]
|
|
166
|
+
|
|
167
|
+
// Other chains
|
|
168
|
+
await w3pk.getEndpoints(10) // Optimism
|
|
169
|
+
await w3pk.getEndpoints(42161) // Arbitrum
|
|
170
|
+
await w3pk.getEndpoints(8453) // Base
|
|
171
|
+
|
|
172
|
+
// Use with ethers.js
|
|
173
|
+
import { ethers } from 'ethers'
|
|
174
|
+
|
|
175
|
+
const endpoints = await w3pk.getEndpoints(137)
|
|
176
|
+
const provider = new ethers.JsonRpcProvider(endpoints[0])
|
|
177
|
+
const blockNumber = await provider.getBlockNumber()
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### EIP-7702 Support
|
|
181
|
+
```typescript
|
|
182
|
+
// Check network support
|
|
183
|
+
const supported = await w3pk.supportsEIP7702(1) // true
|
|
184
|
+
|
|
185
|
+
// Configure RPC testing
|
|
186
|
+
await w3pk.supportsEIP7702(999, {
|
|
187
|
+
maxEndpoints: 5,
|
|
188
|
+
timeout: 5000
|
|
189
|
+
})
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### ERC-5564 Stealth Addresses
|
|
193
|
+
|
|
99
194
|
```typescript
|
|
100
195
|
const w3pk = createWeb3Passkey({
|
|
101
|
-
apiBaseUrl: 'https://webauthn.w3hc.org',
|
|
102
196
|
stealthAddresses: {}
|
|
103
197
|
})
|
|
104
198
|
|
|
105
|
-
//
|
|
106
|
-
const
|
|
107
|
-
|
|
199
|
+
// Get stealth meta-address
|
|
200
|
+
const metaAddress = await w3pk.stealth?.getStealthMetaAddress()
|
|
201
|
+
|
|
202
|
+
// Generate stealth address
|
|
203
|
+
const announcement = await w3pk.stealth?.generateStealthAddress()
|
|
204
|
+
|
|
205
|
+
// Parse announcement
|
|
206
|
+
const result = await w3pk.stealth?.parseAnnouncement({
|
|
207
|
+
stealthAddress: announcement.stealthAddress,
|
|
208
|
+
ephemeralPublicKey: announcement.ephemeralPublicKey,
|
|
209
|
+
viewTag: announcement.viewTag
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
if (result.isForUser) {
|
|
213
|
+
// Use private key to spend funds
|
|
214
|
+
console.log('Private key:', result.stealthPrivateKey)
|
|
215
|
+
}
|
|
108
216
|
|
|
109
|
-
//
|
|
110
|
-
const
|
|
111
|
-
// Returns: { metaAddress, viewingKey, spendingKey }
|
|
217
|
+
// Scan announcements
|
|
218
|
+
const myPayments = await w3pk.stealth?.scanAnnouncements(announcements)
|
|
112
219
|
```
|
|
113
220
|
|
|
114
|
-
##
|
|
221
|
+
## Browser Compatibility
|
|
222
|
+
|
|
223
|
+
**Supported (95%+ of users):**
|
|
224
|
+
- Chrome 67+ (May 2018), Edge 18+ (Nov 2018), Firefox 60+ (May 2018), Safari 14+ (Sep 2020)
|
|
225
|
+
- iOS 14.5+ (April 2021), Android 9+ (August 2018)
|
|
226
|
+
- Windows Hello, Touch ID, Face ID, platform authenticators
|
|
115
227
|
|
|
116
|
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
228
|
+
**Not Supported:**
|
|
229
|
+
- Safari < 14, Chrome/Firefox < 2018, IE11, Android < 9, iOS < 14.5
|
|
230
|
+
- Private/Incognito mode (credentials don't persist)
|
|
231
|
+
- WebView/embedded browsers (often disabled)
|
|
119
232
|
|
|
120
|
-
##
|
|
233
|
+
## Documentation
|
|
121
234
|
|
|
122
|
-
- [
|
|
123
|
-
- [
|
|
124
|
-
- [
|
|
125
|
-
- [
|
|
126
|
-
- [
|
|
235
|
+
- [Quick Start Guide](./docs/QUICK_START.md) - Get started in 5 minutes
|
|
236
|
+
- [Browser Compatibility](./docs/BROWSER_COMPATIBILITY.md) - Supported browsers, devices, and OS versions
|
|
237
|
+
- [Security Architecture](./docs/SECURITY.md) - Integration best practices
|
|
238
|
+
- [ERC-5564 Stealth Addresses](./docs/ERC5564_STEALTH_ADDRESSES.md) - Complete guide with examples
|
|
239
|
+
- [ERC-5564 Flow Diagrams](./docs/ERC5564_FLOW_DIAGRAM.md) - Visual explanations of how stealth addresses work
|
|
240
|
+
- [RPC Endpoints](./docs/CHAINLIST.md) - Chainlist integration guide
|
|
241
|
+
- [ZK Integration Guide](./docs/ZK_INTEGRATION_GUIDE.md) - Zero-knowledge proofs (optional)
|
|
242
|
+
- [Bundle Size Comparison](./docs/BUNDLE_SIZES.md) - Core vs ZK bundle sizes
|
|
127
243
|
|
|
128
244
|
## Contributing
|
|
129
245
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chainlist types
|
|
3
|
+
*/
|
|
4
|
+
interface Chain {
|
|
5
|
+
name: string;
|
|
6
|
+
chain: string;
|
|
7
|
+
icon?: string;
|
|
8
|
+
rpc: string[];
|
|
9
|
+
features?: Array<{
|
|
10
|
+
name: string;
|
|
11
|
+
}>;
|
|
12
|
+
faucets: string[];
|
|
13
|
+
nativeCurrency: {
|
|
14
|
+
name: string;
|
|
15
|
+
symbol: string;
|
|
16
|
+
decimals: number;
|
|
17
|
+
};
|
|
18
|
+
infoURL: string;
|
|
19
|
+
shortName: string;
|
|
20
|
+
chainId: number;
|
|
21
|
+
networkId: number;
|
|
22
|
+
slip44?: number;
|
|
23
|
+
ens?: {
|
|
24
|
+
registry: string;
|
|
25
|
+
};
|
|
26
|
+
explorers?: Array<{
|
|
27
|
+
name: string;
|
|
28
|
+
url: string;
|
|
29
|
+
icon?: string;
|
|
30
|
+
standard: string;
|
|
31
|
+
}>;
|
|
32
|
+
title?: string;
|
|
33
|
+
status?: string;
|
|
34
|
+
redFlags?: string[];
|
|
35
|
+
}
|
|
36
|
+
interface ChainlistOptions {
|
|
37
|
+
/**
|
|
38
|
+
* Custom URL for chains.json data
|
|
39
|
+
* @default 'https://chainid.network/chains.json'
|
|
40
|
+
*/
|
|
41
|
+
chainsJsonUrl?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Cache duration in milliseconds
|
|
44
|
+
* @default 3600000 (1 hour)
|
|
45
|
+
*/
|
|
46
|
+
cacheDuration?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Chainlist module for fetching RPC endpoints
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get RPC endpoints for a specific chain ID, excluding those that require API keys
|
|
55
|
+
*
|
|
56
|
+
* @param chainId - The chain ID to get endpoints for
|
|
57
|
+
* @param options - Optional configuration
|
|
58
|
+
* @returns Array of RPC URLs that don't require API keys
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import { getEndpoints } from 'w3pk/chainlist'
|
|
63
|
+
*
|
|
64
|
+
* // Get Ethereum mainnet RPCs
|
|
65
|
+
* const endpoints = await getEndpoints(1)
|
|
66
|
+
* console.log(endpoints)
|
|
67
|
+
* // [
|
|
68
|
+
* // "https://api.mycryptoapi.com/eth",
|
|
69
|
+
* // "https://cloudflare-eth.com",
|
|
70
|
+
* // "https://ethereum-rpc.publicnode.com",
|
|
71
|
+
* // ...
|
|
72
|
+
* // ]
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare function getEndpoints(chainId: number, options?: ChainlistOptions): Promise<string[]>;
|
|
76
|
+
/**
|
|
77
|
+
* Get all available chains
|
|
78
|
+
*
|
|
79
|
+
* @param options - Optional configuration
|
|
80
|
+
* @returns Array of all chains
|
|
81
|
+
*/
|
|
82
|
+
declare function getAllChains(options?: ChainlistOptions): Promise<Chain[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Get chain information by chain ID
|
|
85
|
+
*
|
|
86
|
+
* @param chainId - The chain ID to get information for
|
|
87
|
+
* @param options - Optional configuration
|
|
88
|
+
* @returns Chain information or undefined if not found
|
|
89
|
+
*/
|
|
90
|
+
declare function getChainById(chainId: number, options?: ChainlistOptions): Promise<Chain | undefined>;
|
|
91
|
+
/**
|
|
92
|
+
* Clear the chains data cache
|
|
93
|
+
*/
|
|
94
|
+
declare function clearCache(): void;
|
|
95
|
+
|
|
96
|
+
export { type Chain, type ChainlistOptions, clearCache, getAllChains, getChainById, getEndpoints };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chainlist types
|
|
3
|
+
*/
|
|
4
|
+
interface Chain {
|
|
5
|
+
name: string;
|
|
6
|
+
chain: string;
|
|
7
|
+
icon?: string;
|
|
8
|
+
rpc: string[];
|
|
9
|
+
features?: Array<{
|
|
10
|
+
name: string;
|
|
11
|
+
}>;
|
|
12
|
+
faucets: string[];
|
|
13
|
+
nativeCurrency: {
|
|
14
|
+
name: string;
|
|
15
|
+
symbol: string;
|
|
16
|
+
decimals: number;
|
|
17
|
+
};
|
|
18
|
+
infoURL: string;
|
|
19
|
+
shortName: string;
|
|
20
|
+
chainId: number;
|
|
21
|
+
networkId: number;
|
|
22
|
+
slip44?: number;
|
|
23
|
+
ens?: {
|
|
24
|
+
registry: string;
|
|
25
|
+
};
|
|
26
|
+
explorers?: Array<{
|
|
27
|
+
name: string;
|
|
28
|
+
url: string;
|
|
29
|
+
icon?: string;
|
|
30
|
+
standard: string;
|
|
31
|
+
}>;
|
|
32
|
+
title?: string;
|
|
33
|
+
status?: string;
|
|
34
|
+
redFlags?: string[];
|
|
35
|
+
}
|
|
36
|
+
interface ChainlistOptions {
|
|
37
|
+
/**
|
|
38
|
+
* Custom URL for chains.json data
|
|
39
|
+
* @default 'https://chainid.network/chains.json'
|
|
40
|
+
*/
|
|
41
|
+
chainsJsonUrl?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Cache duration in milliseconds
|
|
44
|
+
* @default 3600000 (1 hour)
|
|
45
|
+
*/
|
|
46
|
+
cacheDuration?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Chainlist module for fetching RPC endpoints
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get RPC endpoints for a specific chain ID, excluding those that require API keys
|
|
55
|
+
*
|
|
56
|
+
* @param chainId - The chain ID to get endpoints for
|
|
57
|
+
* @param options - Optional configuration
|
|
58
|
+
* @returns Array of RPC URLs that don't require API keys
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* import { getEndpoints } from 'w3pk/chainlist'
|
|
63
|
+
*
|
|
64
|
+
* // Get Ethereum mainnet RPCs
|
|
65
|
+
* const endpoints = await getEndpoints(1)
|
|
66
|
+
* console.log(endpoints)
|
|
67
|
+
* // [
|
|
68
|
+
* // "https://api.mycryptoapi.com/eth",
|
|
69
|
+
* // "https://cloudflare-eth.com",
|
|
70
|
+
* // "https://ethereum-rpc.publicnode.com",
|
|
71
|
+
* // ...
|
|
72
|
+
* // ]
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare function getEndpoints(chainId: number, options?: ChainlistOptions): Promise<string[]>;
|
|
76
|
+
/**
|
|
77
|
+
* Get all available chains
|
|
78
|
+
*
|
|
79
|
+
* @param options - Optional configuration
|
|
80
|
+
* @returns Array of all chains
|
|
81
|
+
*/
|
|
82
|
+
declare function getAllChains(options?: ChainlistOptions): Promise<Chain[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Get chain information by chain ID
|
|
85
|
+
*
|
|
86
|
+
* @param chainId - The chain ID to get information for
|
|
87
|
+
* @param options - Optional configuration
|
|
88
|
+
* @returns Chain information or undefined if not found
|
|
89
|
+
*/
|
|
90
|
+
declare function getChainById(chainId: number, options?: ChainlistOptions): Promise<Chain | undefined>;
|
|
91
|
+
/**
|
|
92
|
+
* Clear the chains data cache
|
|
93
|
+
*/
|
|
94
|
+
declare function clearCache(): void;
|
|
95
|
+
|
|
96
|
+
export { type Chain, type ChainlistOptions, clearCache, getAllChains, getChainById, getEndpoints };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var o=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var p=(t,n)=>{for(var s in n)o(t,s,{get:n[s],enumerable:!0})},f=(t,n,s,a)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of u(n))!C.call(t,i)&&i!==s&&o(t,i,{get:()=>n[i],enumerable:!(a=h(n,i))||a.enumerable});return t};var l=t=>f(o({},"__esModule",{value:!0}),t);var I={};p(I,{clearCache:()=>y,getAllChains:()=>w,getChainById:()=>A,getEndpoints:()=>d});module.exports=l(I);var c="https://chainid.network/chains.json";var e=null,m=[/\$\{[\w_]+\}/i,/\{[\w_]+\}/i,/<[\w_]+>/i,/YOUR[-_]?API[-_]?KEY/i,/INSERT[-_]?API[-_]?KEY/i,/API[-_]?KEY[-_]?HERE/i];function E(t){return m.some(n=>n.test(t))}async function _(t=c){let n=await fetch(t);if(!n.ok)throw new Error(`Failed to fetch chains data: ${n.status} ${n.statusText}`);return await n.json()}async function r(t){let n=t?.chainsJsonUrl??c,s=t?.cacheDuration??36e5,a=Date.now();if(e&&a-e.timestamp<s)return e.data;let i=await _(n);return e={data:i,timestamp:a},i}async function d(t,n){let a=(await r(n)).find(i=>i.chainId===t);return a?a.rpc.filter(i=>!E(i)&&!i.startsWith("wss://")&&!i.startsWith("ws://")):[]}async function w(t){return r(t)}async function A(t,n){return(await r(n)).find(a=>a.chainId===t)}function y(){e=null}
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var r="https://chainid.network/chains.json";var s=null,c=[/\$\{[\w_]+\}/i,/\{[\w_]+\}/i,/<[\w_]+>/i,/YOUR[-_]?API[-_]?KEY/i,/INSERT[-_]?API[-_]?KEY/i,/API[-_]?KEY[-_]?HERE/i];function h(n){return c.some(t=>t.test(n))}async function u(n=r){let t=await fetch(n);if(!t.ok)throw new Error(`Failed to fetch chains data: ${t.status} ${t.statusText}`);return await t.json()}async function o(n){let t=n?.chainsJsonUrl??r,e=n?.cacheDuration??36e5,a=Date.now();if(s&&a-s.timestamp<e)return s.data;let i=await u(t);return s={data:i,timestamp:a},i}async function C(n,t){let a=(await o(t)).find(i=>i.chainId===n);return a?a.rpc.filter(i=>!h(i)&&!i.startsWith("wss://")&&!i.startsWith("ws://")):[]}async function p(n){return o(n)}async function f(n,t){return(await o(t)).find(a=>a.chainId===n)}function l(){s=null}export{l as clearCache,p as getAllChains,f as getChainById,C as getEndpoints};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +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"]}
|