@ar.io/wayfinder-core 1.7.0 → 1.7.1-alpha.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 CHANGED
@@ -19,10 +19,13 @@ yarn add @ar.io/wayfinder-core
19
19
  ```javascript
20
20
  import { createWayfinderClient } from '@ar.io/wayfinder-core';
21
21
 
22
- // Uses trusted peers gateway provider by default
22
+ // Creates a Wayfinder client with sensible defaults:
23
+ // - Trusted peers gateway provider with caching (5 minute TTL)
24
+ // - Random routing strategy
25
+ // - Verification disabled
23
26
  const wayfinder = createWayfinderClient();
24
27
 
25
- // Use Wayfinder to fetch and verify data using ar:// protocol
28
+ // Use Wayfinder to fetch data using ar:// protocol
26
29
  const response = await wayfinder.request('ar://example-name');
27
30
  ```
28
31
 
@@ -44,122 +47,65 @@ const gatewaysProvider = new NetworkGatewaysProvider({
44
47
  });
45
48
 
46
49
  const wayfinder = createWayfinderClient({
47
- routingStrategy: new FastestPingRoutingStrategy({ gatewaysProvider }),
50
+ routingSettings: {
51
+ strategy: new FastestPingRoutingStrategy({ gatewaysProvider }),
52
+ },
48
53
  });
49
54
  ```
50
55
 
51
- ### Custom Trusted Gateway
56
+ ### Enable Verification
52
57
 
53
58
  ```javascript
54
59
  import {
55
60
  createWayfinderClient,
56
- FastestPingRoutingStrategy,
57
61
  HashVerificationStrategy,
58
62
  } from '@ar.io/wayfinder-core';
59
63
 
60
- const trustedGateways = [new URL('https://permagate.io')];
61
-
62
64
  const wayfinder = createWayfinderClient({
63
- routingStrategy: new FastestPingRoutingStrategy(),
64
- verificationStrategy: new HashVerificationStrategy({
65
- trustedGateways,
66
- }),
65
+ verificationSettings: {
66
+ enabled: true,
67
+ strategy: new HashVerificationStrategy({
68
+ trustedGateways: [new URL('https://permagate.io')],
69
+ }),
70
+ strict: true, // Fail requests on verification errors
71
+ },
67
72
  });
68
73
  ```
69
74
 
70
- > [!NOTE]
71
- > The legacy `trustedGateways` option on `createWayfinderClient` is deprecated.
72
- > Configure trusted gateways on the verification strategy instead, as shown
73
- > above.
74
-
75
- ### Configuration Options
76
-
77
- > [!IMPORTANT]
78
- > `createWayfinderClient` only honors the `cache`, `routingStrategy`,
79
- > `verificationStrategy`, and `telemetry` options. All other legacy options are
80
- > deprecated and ignored. Supply concrete strategy instances or instantiate
81
- > `Wayfinder` directly for advanced customization.
82
-
83
- By default the helper constructs a
84
- `TrustedPeersGatewaysProvider('https://permagate.io')`, applies a
85
- `RandomRoutingStrategy`, and disables verification.
86
-
87
- ```javascript
88
- import {
89
- createWayfinderClient,
90
- FastestPingRoutingStrategy,
91
- HashVerificationStrategy,
92
- } from '@ar.io/wayfinder-core';
75
+ Wayfinder Core provides helper functions to construct routing and verification strategies:
93
76
 
94
- const wayfinder = createWayfinderClient({
95
- cache: { ttlSeconds: 600 },
96
- routingStrategy: new FastestPingRoutingStrategy(),
97
- verificationStrategy: new HashVerificationStrategy({
98
- trustedGateways: [new URL('https://permagate.io')],
99
- }),
100
- });
101
- ```
77
+ ### createRoutingStrategy
102
78
 
103
- For custom gateway providers or bespoke routing logic, instantiate `Wayfinder`
104
- directly:
79
+ Create routing strategies with a simple string identifier:
105
80
 
106
81
  ```javascript
107
- import {
108
- FastestPingRoutingStrategy,
109
- HashVerificationStrategy,
110
- NetworkGatewaysProvider,
111
- Wayfinder,
112
- } from '@ar.io/wayfinder-core';
113
- import { ARIO } from '@ar.io/sdk';
82
+ import { createRoutingStrategy } from '@ar.io/wayfinder-core';
114
83
 
115
- const gatewaysProvider = new NetworkGatewaysProvider({
116
- ario: ARIO.mainnet(),
117
- sortBy: 'operatorStake',
118
- sortOrder: 'desc',
119
- limit: 10,
84
+ // Create a random routing strategy
85
+ const randomStrategy = createRoutingStrategy({
86
+ strategy: 'random',
87
+ gatewaysProvider: myGatewaysProvider,
88
+ logger: myLogger,
120
89
  });
121
90
 
122
- const trustedGateways = [
123
- new URL('https://arweave.net'),
124
- new URL('https://permagate.io'),
125
- ];
126
-
127
- const wayfinder = new Wayfinder({
128
- gatewaysProvider,
129
- routingSettings: {
130
- strategy: new FastestPingRoutingStrategy({ gatewaysProvider }),
131
- },
132
- verificationSettings: {
133
- strategy: new HashVerificationStrategy({
134
- trustedGateways,
135
- }),
136
- },
137
- telemetrySettings: { enabled: true },
138
- });
91
+ // Available strategies: 'random', 'fastest', 'balanced', 'preferred'
139
92
  ```
140
93
 
141
- ### Gateway Selection Options (with AR.IO Network)
94
+ ### createVerificationStrategy
142
95
 
143
- When using the AR.IO Network provider, you can specify how gateways are selected:
96
+ Create verification strategies with a simple string identifier:
144
97
 
145
98
  ```javascript
146
- import {
147
- createWayfinderClient,
148
- NetworkGatewaysProvider,
149
- RandomRoutingStrategy,
150
- } from '@ar.io/wayfinder-core';
151
- import { ARIO } from '@ar.io/sdk';
99
+ import { createVerificationStrategy } from '@ar.io/wayfinder-core';
152
100
 
153
- const gatewaysProvider = new NetworkGatewaysProvider({
154
- ario: ARIO.mainnet(),
155
- sortBy: 'weights.normalizedCompositeWeight',
156
- sortOrder: 'desc',
157
- limit: 10,
101
+ // Create a hash verification strategy
102
+ const hashStrategy = createVerificationStrategy({
103
+ strategy: 'hash',
104
+ trustedGateways: [new URL('https://permagate.io')],
105
+ logger: myLogger,
158
106
  });
159
107
 
160
- const wayfinder = createWayfinderClient({
161
- routingStrategy: new RandomRoutingStrategy({ gatewaysProvider }),
162
- });
108
+ // Available strategies: 'hash', 'data-root', 'remote', 'disabled'
163
109
  ```
164
110
 
165
111
  ## ar:// Protocol
@@ -167,14 +113,14 @@ const wayfinder = createWayfinderClient({
167
113
  Wayfinder supports several ar:// URL formats:
168
114
 
169
115
  ```bash
170
- ar://TRANSACTION_ID // Direct transaction ID
171
- ar://NAME // ArNS name (paths supported)
172
- ar:///info // Gateway endpoint (/info)
116
+ ar://TRANSACTION_ID # Direct transaction ID
117
+ ar://NAME # ArNS name (paths supported)
118
+ ar:///info # Gateway endpoint (/info)
173
119
  ```
174
120
 
175
121
  ## Dynamic Routing
176
122
 
177
- Wayfinder supports a `resolveUrl` method which generates dynamic redirect URLs to a target gateway based on the provided routing strategy. This function can be used to directly replace any hard-coded gateway URLs, and instead use Wayfinder's routing logic to select a gateway for the request.
123
+ Wayfinder supports a `resolveUrl` method which generates dynamic redirect URLs to a target gateway based on the provided routing strategy. This function can be used to directly replace any hard-coded gateway URLs, and instead use Wayfinder's routing logic to select a gateway for the request.
178
124
 
179
125
  #### ArNS names
180
126
 
@@ -198,7 +144,7 @@ const redirectUrl = await wayfinder.resolveUrl({
198
144
  // results in https://<selected-gateway>/example-tx-id
199
145
  ```
200
146
 
201
- #### Legacy arweave.net or arweave.dev URLs
147
+ #### Legacy URLs
202
148
 
203
149
  Given a legacy arweave.net or arweave.dev URL, the redirect URL will be the same as the original URL, but with the gateway selected by Wayfinder's routing strategy.
204
150
 
@@ -222,35 +168,34 @@ const redirectUrl = await wayfinder.resolveUrl({
222
168
 
223
169
  ## Gateway Providers
224
170
 
225
- Gateway providers are responsible for providing a list of gateways to Wayfinder to choose from when routing requests. By default, Wayfinder will use the `TrustedPeersGatewaysProvider` to fetch available gateways from a trusted gateway's peer list.
171
+ Gateway providers supply the list of gateways for routing. **By default, `createWayfinderClient` uses a cached `TrustedPeersGatewaysProvider`**.
226
172
 
227
173
  | Provider | Description | Use Case |
228
174
  | ------------------------------ | ---------------------------------------------- | --------------------------------------- |
229
- | `NetworkGatewaysProvider` | Returns gateways from AR.IO Network based on on-chain metrics | Leverage AR.IO Network with quality filtering |
230
- | `TrustedPeersGatewaysProvider` | Fetches gateway list from a trusted gateway's `/ar-io/peers` endpoint | Dynamic gateway discovery from network peers |
231
- | `StaticGatewaysProvider` | Returns a static list of gateways you provide | Testing or when specific gateways are required |
232
- | `SimpleCacheGatewaysProvider` | Wraps another provider with in-memory caching | Reduce API calls and improve performance |
233
- | `LocalStorageGatewaysProvider` | Wraps another provider with browser localStorage caching | Persistent caching across page reloads |
175
+ | `NetworkGatewaysProvider` | Returns gateways from AR.IO Network | Leverage AR.IO Network with quality filtering |
176
+ | `TrustedPeersGatewaysProvider` | Fetches from trusted gateway's peers | Dynamic gateway discovery (default) |
177
+ | `StaticGatewaysProvider` | Returns a static list of gateways | Testing or specific gateways |
178
+ | `SimpleCacheGatewaysProvider` | In-memory caching wrapper | Reduce API calls (used by default) |
179
+ | `LocalStorageGatewaysProvider` | Browser localStorage caching | Persistent caching (used by default in browsers) |
234
180
 
235
- ### NetworkGatewaysProvider
181
+ #### NetworkGatewaysProvider
236
182
 
237
- Returns a list of gateways from the ARIO Network based on on-chain metrics. You can specify on-chain metrics for gateways to prioritize the highest quality gateways. This requires installing the `@ar.io/sdk` package and importing the `ARIO` object. *It is recommended to use this provider for most use cases to leverage the AR.IO Network.*
183
+ Returns a list of gateways from the ARIO Network based on on-chain [Gateway Address Registry](https://docs.ar.io/learn/gateways/gateway-registry). You can specify on-chain metrics for gateways to prioritize the highest quality gateways. This requires installing the `@ar.io/sdk` package and importing the `ARIO` object.
238
184
 
239
185
  ```javascript
240
- // requests will be routed to one of the top 10 gateways by operator stake
186
+ import { NetworkGatewaysProvider } from '@ar.io/wayfinder-core';
187
+ import { ARIO } from '@ar.io/sdk';
188
+
241
189
  const gatewayProvider = new NetworkGatewaysProvider({
242
190
  ario: ARIO.mainnet(),
243
- sortBy: 'operatorStake', // sort by 'operatorStake' | 'totalDelegatedStake'
244
- sortOrder: 'desc', // 'asc'
245
- limit: 10, // number of gateways to use
246
- filter: (gateway) => {
247
- // use only active gateways that did not fail in the last epoch
248
- return gateway.status === 'joined' && gateway.stats.failedConsecutiveEpochs === 0;
249
- },
191
+ sortBy: 'operatorStake',
192
+ sortOrder: 'desc',
193
+ limit: 10,
194
+ filter: (gateway) => gateway.status === 'joined',
250
195
  });
251
196
  ```
252
197
 
253
- ### TrustedPeersGatewaysProvider
198
+ #### TrustedPeersGatewaysProvider
254
199
 
255
200
  Fetches a dynamic list of trusted peer gateways from an AR.IO gateway's `/ar-io/peers` endpoint. This provider is useful for discovering available gateways from a trusted source.
256
201
 
@@ -258,22 +203,7 @@ Fetches a dynamic list of trusted peer gateways from an AR.IO gateway's `/ar-io/
258
203
  import { TrustedPeersGatewaysProvider } from '@ar.io/wayfinder-core';
259
204
 
260
205
  const gatewayProvider = new TrustedPeersGatewaysProvider({
261
- trustedGateway: 'https://arweave.net', // Gateway to fetch peers from
262
- });
263
-
264
- // The provider will fetch the peer list from https://arweave.net/ar-io/peers
265
- // and return an array of gateway URLs from the response
266
- ```
267
-
268
- ### StaticGatewaysProvider
269
-
270
- The static gateway provider returns a list of gateways that you provide. This is useful for testing or for users who want to use a specific gateway for all requests.
271
-
272
- ```javascript
273
- import { StaticGatewaysProvider } from '@ar.io/wayfinder-core';
274
-
275
- const gatewayProvider = new StaticGatewaysProvider({
276
- gateways: ['https://arweave.net'],
206
+ trustedGateway: 'https://arweave.net',
277
207
  });
278
208
  ```
279
209
 
@@ -290,109 +220,32 @@ Wayfinder supports multiple routing strategies to select target gateways for you
290
220
  | `PreferredWithFallbackRoutingStrategy` | Uses a preferred gateway, with a fallback strategy if the preferred gateway is not available | Good for performance and resilience. Ideal for builders who run their own gateways. |
291
221
  | `CompositeRoutingStrategy` | Chains multiple routing strategies together, trying each sequentially until one succeeds | Good for complex fallback scenarios and maximum resilience |
292
222
 
293
- ### RandomRoutingStrategy
223
+ #### RandomRoutingStrategy
294
224
 
295
225
  Selects a random gateway from a list of gateways.
296
226
 
297
227
  ```javascript
298
- import { RandomRoutingStrategy, NetworkGatewaysProvider } from '@ar.io/wayfinder-core';
299
- import { ARIO } from '@ar.io/sdk';
300
-
301
- // Option 1: Use with static gateways (override gatewaysProvider if provided)
302
- const routingStrategy = new RandomRoutingStrategy();
303
- const gateway = await routingStrategy.selectGateway({
304
- gateways: [new URL('https://arweave.net'), new URL('https://permagate.io')],
305
- });
306
-
307
- // Option 2: Use with gatewaysProvider (fetches dynamically)
308
- const routingStrategy2 = new RandomRoutingStrategy({
309
- gatewaysProvider: new NetworkGatewaysProvider({
310
- ario: ARIO.mainnet(),
311
- sortBy: 'operatorStake',
312
- limit: 10,
313
- }),
314
- });
315
- const gateway2 = await routingStrategy2.selectGateway(); // uses gatewaysProvider
316
-
317
- // Option 3: Override gatewaysProvider with static gateways
318
- const gateway3 = await routingStrategy2.selectGateway({
319
- gateways: [new URL('https://custom-gateway.net')], // overrides gatewaysProvider
320
- });
321
- ```
322
-
323
- ### StaticRoutingStrategy
324
-
325
- ```javascript
326
- import { StaticRoutingStrategy } from '@ar.io/wayfinder-core';
327
-
328
- const routingStrategy = new StaticRoutingStrategy({
329
- gateway: 'https://arweave.net',
330
- });
331
-
332
- const gateway = await routingStrategy.selectGateway(); // always returns the same gateway
333
- ```
334
-
335
- ### RoundRobinRoutingStrategy
336
-
337
- Selects gateways in round-robin order. The gateway list is stored in memory and is not persisted across instances. You must provide either `gateways` OR `gatewaysProvider` (not both).
338
-
339
- ```javascript
340
- import { RoundRobinRoutingStrategy, NetworkGatewaysProvider } from '@ar.io/wayfinder-core';
341
- import { ARIO } from '@ar.io/sdk';
228
+ import { RandomRoutingStrategy } from '@ar.io/wayfinder-core';
342
229
 
343
- // use with a static list of gateways
344
- const routingStrategy = new RoundRobinRoutingStrategy({
345
- gateways: [new URL('https://arweave.net'), new URL('https://permagate.io')],
230
+ const strategy = new RandomRoutingStrategy({
231
+ gatewaysProvider: myGatewaysProvider,
346
232
  });
347
-
348
- // use with gatewaysProvider (loaded once and memoized)
349
- const routingStrategy2 = new RoundRobinRoutingStrategy({
350
- gatewaysProvider: new NetworkGatewaysProvider({
351
- ario: ARIO.mainnet(),
352
- sortBy: 'operatorStake',
353
- sortOrder: 'desc',
354
- limit: 10,
355
- }),
356
- });
357
-
358
- const gateway = await routingStrategy.selectGateway(); // returns the next gateway in round-robin order
359
233
  ```
360
234
 
361
- ### FastestPingRoutingStrategy
235
+ #### FastestPingRoutingStrategy
362
236
 
363
- Selects the fastest gateway based on simple HEAD request to the specified route.
237
+ Selects the fastest gateway based on ping time. This strategy pings all available gateways and selects the one with the lowest latency.
364
238
 
365
239
  ```javascript
366
- import { FastestPingRoutingStrategy, NetworkGatewaysProvider } from '@ar.io/wayfinder-core';
367
- import { ARIO } from '@ar.io/sdk';
368
-
369
- // use with static gateways (override gatewaysProvider if provided)
370
- const routingStrategy = new FastestPingRoutingStrategy({
371
- timeoutMs: 1000,
372
- });
373
- const gateway = await routingStrategy.selectGateway({
374
- gateways: [new URL('https://slow.net'), new URL('https://medium.net'), new URL('https://fast.net')],
375
- });
240
+ import { FastestPingRoutingStrategy } from '@ar.io/wayfinder-core';
376
241
 
377
- // use with gatewaysProvider (fetches dynamically)
378
- const routingStrategy2 = new FastestPingRoutingStrategy({
242
+ const strategy = new FastestPingRoutingStrategy({
379
243
  timeoutMs: 1000,
380
- gatewaysProvider: new NetworkGatewaysProvider({
381
- ario: ARIO.mainnet(),
382
- sortBy: 'operatorStake',
383
- limit: 20,
384
- }),
385
- });
386
- const gateway2 = await routingStrategy2.selectGateway({ path: '/ar-io/info' }); // uses gatewaysProvider
387
-
388
- // override the gatewaysProvider with a static list of gateways
389
- const gateway3 = await routingStrategy2.selectGateway({
390
- gateways: [new URL('https://priority-gateway.net')], // overrides gatewaysProvider
391
- path: '/ar-io/info'
244
+ gatewaysProvider: myGatewaysProvider,
392
245
  });
393
246
  ```
394
247
 
395
- ### PreferredWithFallbackRoutingStrategy
248
+ #### PreferredWithFallbackRoutingStrategy
396
249
 
397
250
  Uses a preferred gateway, with a fallback strategy if the preferred gateway is not available. This is useful for builders who run their own gateways and want to use their own gateway as the preferred gateway, but also want to have a fallback strategy in case their gateway is not available.
398
251
 
@@ -402,17 +255,28 @@ Uses a preferred gateway, with a fallback strategy if the preferred gateway is n
402
255
  ```javascript
403
256
  import { PreferredWithFallbackRoutingStrategy, FastestPingRoutingStrategy } from '@ar.io/wayfinder-core';
404
257
 
405
- const routingStrategy = new PreferredWithFallbackRoutingStrategy({
406
- preferredGateway: 'https://permagate.io',
407
- fallbackStrategy: new FastestPingRoutingStrategy({
408
- timeoutMs: 500,
409
- }),
258
+ const strategy = new PreferredWithFallbackRoutingStrategy({
259
+ preferredGateway: 'https://my-gateway.com',
260
+ fallbackStrategy: new FastestPingRoutingStrategy({ timeoutMs: 500 }),
410
261
  });
411
262
  ```
412
263
 
413
- ### CompositeRoutingStrategy
264
+ #### CompositeRoutingStrategy
265
+
266
+ The `CompositeRoutingStrategy` allows you to chain multiple routing strategies together, providing maximum resilience by trying each strategy in sequence until one succeeds. This is ideal for complex fallback scenarios where you want to combine different routing approaches.
267
+
268
+ **How it works:**
269
+
270
+ 1. Tries each strategy in the order they're provided
271
+ 2. If a strategy successfully returns a gateway, that gateway is used (remaining strategies are skipped)
272
+ 3. If a strategy throws an error, moves to the next strategy
273
+ 4. If all strategies fail, throws an error
274
+
275
+ **Common use cases:**
414
276
 
415
- Chains multiple routing strategies together, trying each sequentially until one succeeds. This strategy provides maximum resilience by allowing complex fallback scenarios where you can combine different routing approaches.
277
+ - **Performance + Resilience**: Try fastest ping first, fallback to random if ping fails
278
+ - **Preferred + Network**: Use your own gateway first, fallback to AR.IO network selection
279
+ - **Multi-tier Fallback**: Try premium gateways, then standard gateways, then any available gateway
416
280
 
417
281
  ```javascript
418
282
  import {
@@ -424,9 +288,10 @@ import {
424
288
  } from '@ar.io/wayfinder-core';
425
289
  import { ARIO } from '@ar.io/sdk';
426
290
 
427
- // Example 1: Try fastest ping first, fallback to random selection
428
- const strategy = new CompositeRoutingStrategy({
291
+ // Example 1: Performance-first with resilience fallback
292
+ const performanceStrategy = new CompositeRoutingStrategy({
429
293
  strategies: [
294
+ // Try fastest ping first (high performance, but may fail if all gateways are slow)
430
295
  new FastestPingRoutingStrategy({
431
296
  timeoutMs: 500,
432
297
  gatewaysProvider: new NetworkGatewaysProvider({
@@ -435,224 +300,48 @@ const strategy = new CompositeRoutingStrategy({
435
300
  limit: 10,
436
301
  }),
437
302
  }),
438
- new RandomRoutingStrategy(), // fallback if ping strategy fails
303
+ // Fallback to random selection (guaranteed to work if gateways exist)
304
+ new RandomRoutingStrategy({
305
+ gatewaysProvider: new NetworkGatewaysProvider({
306
+ ario: ARIO.mainnet(),
307
+ sortBy: 'operatorStake',
308
+ limit: 20, // Use more gateways for fallback
309
+ }),
310
+ }),
439
311
  ],
440
312
  });
441
313
 
442
- // Example 2: Try preferred gateway, then fastest ping, then any random gateway
443
- const complexStrategy = new CompositeRoutingStrategy({
314
+ // Example 2: Preferred gateway with multi-tier fallback
315
+ const preferredStrategy = new CompositeRoutingStrategy({
444
316
  strategies: [
445
- new StaticRoutingStrategy({ gateway: 'https://my-preferred-gateway.com' }),
446
- new FastestPingRoutingStrategy({ timeoutMs: 1000 }),
447
- new RandomRoutingStrategy(), // final fallback
448
- ],
449
- });
450
-
451
- const gateway = await strategy.selectGateway({
452
- gateways: [new URL('https://gateway1.com'), new URL('https://gateway2.com')],
453
- });
454
- ```
455
-
456
- **How it works:**
457
- 1. The composite strategy tries each routing strategy in order
458
- 2. If a strategy successfully returns a gateway, that gateway is used
459
- 3. If a strategy throws an error, the next strategy is tried
460
- 4. If all strategies fail, an error is thrown
461
- 5. The first successful strategy short-circuits the process (remaining strategies are not tried)
462
-
463
- **Common Use Cases:**
464
- - **Performance + Resilience**: Try fastest ping first, fallback to random if ping fails
465
- - **Preferred + Network**: Use your own gateway first, fallback to AR.IO network selection
466
- - **Multi-tier Fallback**: Try premium gateways, then standard gateways, then any available gateway
467
- - **Development + Production**: Use local gateway in development, fallback to production gateways
468
-
469
- ### Strategy Composition Examples
470
-
471
- Here are a few “lego-style” examples showing how existing routing strategies can
472
- be composed to suit different use cases. Each strategy implements
473
- `RoutingStrategy`, so they can be wrapped and combined freely.
474
-
475
- #### Random + Ping health checks
476
-
477
- Pick a random gateway, then verify it responds with a `HEAD` request before
478
- returning it.
479
-
480
- ```ts
481
- import {
482
- RandomRoutingStrategy,
483
- PingRoutingStrategy,
484
- } from "@ar.io/wayfinder-core";
485
-
486
- const strategy = new PingRoutingStrategy({
487
- routingStrategy: new RandomRoutingStrategy(),
488
- retries: 2,
489
- timeoutMs: 500,
490
- });
491
- ```
492
-
493
- #### Fastest ping wrapped with a simple cache
494
-
495
- Find the lowest-latency gateway and cache the result for five minutes to avoid
496
- constant pings.
497
-
498
- ```ts
499
- import {
500
- FastestPingRoutingStrategy,
501
- SimpleCacheRoutingStrategy,
502
- } from "@ar.io/wayfinder-core";
503
-
504
- const strategy = new SimpleCacheRoutingStrategy({
505
- routingStrategy: new FastestPingRoutingStrategy({ timeoutMs: 500 }),
506
- ttlSeconds: 300,
507
- });
508
- ```
509
-
510
- #### Preferred gateway + network fallback strategy
511
-
512
- Attempt to use a favorite gateway, but fallback to a fastest pinging strategy using the ARIO Network if it fails.
513
-
514
- ```ts
515
- import {
516
- PreferredWithFallbackRoutingStrategy,
517
- RandomRoutingStrategy,
518
- PingRoutingStrategy,
519
- NetworkGatewaysProvider,
520
- } from "@ar.io/wayfinder-core";
521
- import { ARIO } from '@ar.io/sdk';
522
-
523
- // these will be our fallback gateways
524
- const gatewayProvider = new NetworkGatewaysProvider({
525
- ario: ARIO.mainnet(),
526
- sortBy: 'operatorStake',
527
- limit: 5,
528
- });
529
-
530
- // this is our fallback strategy if our preferred gateway fails
531
- const fastestPingStrategy = new FastestPingRoutingStrategy({
532
- timeoutMs: 500,
533
- gatewaysProvider: gatewayProvider,
534
- });
535
-
536
- // compose the strategies together, the preferred gateway will be used first, and if it fails, the fallback strategy will be used.
537
- const strategy = new PreferredWithFallbackRoutingStrategy({
538
- preferredGateway: "https://my-gateway.example",
539
- fallbackStrategy: fastestPingStrategy,
540
- });
541
- ```
542
-
543
- #### Round-robin + ping verification
544
-
545
- Cycle through gateways sequentially, checking each one’s health before use.
546
-
547
- ```ts
548
- import {
549
- RoundRobinRoutingStrategy,
550
- PingRoutingStrategy,
551
- NetworkGatewaysProvider,
552
- } from "@ar.io/wayfinder-core";
553
- import { ARIO } from '@ar.io/sdk';
554
-
555
- // use static gateways
556
- const strategy = new PingRoutingStrategy({
557
- routingStrategy: new RoundRobinRoutingStrategy({
558
- gateways: [new URL("https://gw1"), new URL("https://gw2")],
559
- }),
560
- });
561
-
562
- // use a dynamic list of gateways from the ARIO Network
563
- const strategy2 = new PingRoutingStrategy({
564
- routingStrategy: new RoundRobinRoutingStrategy({
565
- gatewaysProvider: new NetworkGatewaysProvider({
566
- ario: ARIO.mainnet(),
567
- sortBy: 'operatorStake',
568
- limit: 5,
317
+ // First, try your preferred gateway
318
+ new StaticRoutingStrategy({
319
+ gateway: 'https://my-preferred-gateway.com'
569
320
  }),
570
- }),
571
- });
572
- ```
573
-
574
- #### Cache around any composed strategy
575
-
576
- Because `SimpleCacheRoutingStrategy` accepts any `RoutingStrategy`, you can
577
- cache more complex compositions too.
578
-
579
- ```ts
580
- import {
581
- RandomRoutingStrategy,
582
- PingRoutingStrategy,
583
- SimpleCacheRoutingStrategy,
584
- NetworkGatewaysProvider,
585
- } from "@ar.io/wayfinder-core";
586
- import { ARIO } from '@ar.io/sdk';
587
-
588
- // use a dynamic list of gateways from the ARIO Network
589
- const randomStrategy = new RandomRoutingStrategy({
590
- gatewaysProvider: new NetworkGatewaysProvider({
591
- ario: ARIO.mainnet(),
592
- sortBy: 'operatorStake',
593
- limit: 20,
594
- }),
595
- });
596
-
597
- // wrap the random strategy with a ping strategy
598
- const pingRandom = new PingRoutingStrategy({
599
- routingStrategy: randomStrategy,
600
- });
601
-
602
- // wrap the ping random strategy with a cache strategy, caching the selected gateway for 10 minutes
603
- const cachedStrategy = new SimpleCacheRoutingStrategy({
604
- routingStrategy: pingRandom,
605
- ttlSeconds: 600,
606
- });
607
- ```
608
-
609
- #### Complex multi-strategy fallback with CompositeRoutingStrategy
610
-
611
- Chain multiple strategies together for maximum resilience - try fastest ping first, then fall back to random selection if ping fails.
612
-
613
- ```ts
614
- import {
615
- CompositeRoutingStrategy,
616
- FastestPingRoutingStrategy,
617
- RandomRoutingStrategy,
618
- NetworkGatewaysProvider,
619
- } from "@ar.io/wayfinder-core";
620
- import { ARIO } from '@ar.io/sdk';
621
-
622
- // Define gateway provider for both strategies
623
- const gatewayProvider = new NetworkGatewaysProvider({
624
- ario: ARIO.mainnet(),
625
- sortBy: 'operatorStake',
626
- limit: 15,
627
- });
628
-
629
- // Create a composite strategy that tries fastest ping first, then random
630
- const strategy = new CompositeRoutingStrategy({
631
- strategies: [
632
- // Try fastest ping first (high performance, but may fail if all gateways are slow)
321
+ // If that fails, try fastest ping from top-tier gateways
633
322
  new FastestPingRoutingStrategy({
634
- timeoutMs: 500,
635
- gatewaysProvider: gatewayProvider,
323
+ timeoutMs: 1000,
324
+ gatewaysProvider: new NetworkGatewaysProvider({
325
+ ario: ARIO.mainnet(),
326
+ sortBy: 'operatorStake',
327
+ limit: 5, // Only top 5 gateways
328
+ }),
636
329
  }),
637
- // Fallback to random selection (guaranteed to work if gateways exist)
330
+ // Final fallback: any random gateway from a larger pool
638
331
  new RandomRoutingStrategy({
639
- gatewaysProvider: gatewayProvider,
332
+ gatewaysProvider: new NetworkGatewaysProvider({
333
+ ario: ARIO.mainnet(),
334
+ limit: 50, // Larger pool for maximum availability
335
+ }),
640
336
  }),
641
337
  ],
642
338
  });
643
- ```
644
-
645
- In all cases, you can supply the composed strategy to `Wayfinder` (or whatever
646
- router factory you use) and pass in a gateways provider:
647
339
 
648
- ```ts
649
- import { Wayfinder, StaticGatewaysProvider } from "@ar.io/wayfinder-core";
650
-
651
- const router = new Wayfinder({
652
- gatewaysProvider: new StaticGatewaysProvider({
653
- gateways: [new URL("https://gw1"), new URL("https://gw2")],
654
- }),
655
- routingStrategy: strategy, // any of the compositions above
340
+ // Use with createWayfinderClient
341
+ const wayfinder = createWayfinderClient({
342
+ routingSettings: {
343
+ strategy: performanceStrategy,
344
+ },
656
345
  });
657
346
  ```
658
347
 
@@ -667,7 +356,7 @@ Wayfinder includes verification mechanisms to ensure the integrity of retrieved
667
356
  | `DataRootVerificationStrategy` | Medium | Medium | Low | Computes the data root for the transaction (most useful for L1 transactions) and compares it to the data root provided by a **trusted gateway**. |
668
357
  | `SignatureVerificationStrategy` | Medium | Medium | Medium | - **ANS-104 Data Items**: Fetches signature components (owner, signature type, tags, etc.) from trusted gateways using range requests, then verifies signatures against the data payload using deep hash calculations following the ANS-104 standard.<br/>- **L1 Transactions**: Retrieves transaction metadata from gateway /tx/<tx-id> endpoints, computes the data root from the provided data stream, and verifies the signature using Arweave's cryptographic verification. |
669
358
 
670
- ### RemoteVerificationStrategy
359
+ #### RemoteVerificationStrategy
671
360
 
672
361
  This strategy is used to verify data by checking the `x-ar-io-verified` header from the gateway that returned the data. If the header is set to `true`, the data is considered verified and trusted.
673
362
 
@@ -686,7 +375,7 @@ const wayfinder = new Wayfinder({
686
375
  });
687
376
  ```
688
377
 
689
- ### HashVerificationStrategy
378
+ #### HashVerificationStrategy
690
379
 
691
380
  Verifies data integrity using SHA-256 hash comparison. This is the default verification strategy and is recommended for most users looking for a balance between security and performance.
692
381
 
@@ -703,7 +392,7 @@ const wayfinder = new Wayfinder({
703
392
  });
704
393
  ```
705
394
 
706
- ### DataRootVerificationStrategy
395
+ #### DataRootVerificationStrategy
707
396
 
708
397
  Verifies data integrity using Arweave by computing the data root for the transaction. This is useful for L1 transactions and is recommended for users who want to ensure the integrity of their data.
709
398
 
@@ -720,7 +409,7 @@ const wayfinder = new Wayfinder({
720
409
  });
721
410
  ```
722
411
 
723
- ### SignatureVerificationStrategy
412
+ #### SignatureVerificationStrategy
724
413
 
725
414
  Verifies signatures of Arweave transactions and data items. Headers are retrieved from trusted gateways for use during verification. For a transaction, its data root is computed while streaming its data and then utilized alongside its headers for verification. For data items, the ANS-104 deep hash method of signature verification is used.
726
415
 
@@ -737,229 +426,89 @@ const wayfinder = new Wayfinder({
737
426
  });
738
427
  ```
739
428
 
740
- ## Monitoring and Events
429
+ ## x402 Payments
741
430
 
742
- ### Global request events
431
+ Wayfinder can be configured to work with the [x402 payment protocol](https://docs.ar.io/learn/gateways/x402-payments#what-is-x402) for paid gateway services and higher rate limits. This allows you to seamlessly make requests that may require payment without having to manually handle payment flows.
743
432
 
744
- Wayfinder emits events during the routing and verification process for all requests, allowing you to monitor its operation. All events are emitted on the `wayfinder.emitter` event emitter, and are updated for each request.
433
+ > [!IMPORTANT]
434
+ > To use x402 payments, you need to install the `@ar.io/wayfinder-x402-fetch` package.
745
435
 
746
436
  ```javascript
747
- // Provide events to the Wayfinder constructor for tracking all requests
748
- const wayfinder = new Wayfinder({
437
+ import { createWayfinderClient } from '@ar.io/wayfinder-core';
438
+ import { createX402Fetch } from '@ar.io/wayfinder-x402-fetch';
439
+ import { privateKeyToAccount } from 'viem/accounts';
440
+
441
+ // Set up your wallet for x402 payments
442
+ const privateKey = process.env.X402_PRIVATE_KEY; // Your private key
443
+ const account = privateKeyToAccount(privateKey);
444
+
445
+ // Create x402-enabled fetch implementation
446
+ const x402Fetch = createX402Fetch({
447
+ walletClient: account,
448
+ });
449
+
450
+ // Create Wayfinder client with x402 fetch
451
+ const wayfinder = createWayfinderClient({
452
+ fetch: x402Fetch,
749
453
  routingSettings: {
750
- events: {
751
- onRoutingStarted: (event) => {
752
- console.log('Routing started!', event);
753
- },
754
- onRoutingSkipped: (event) => {
755
- console.log('Routing skipped!', event);
756
- },
757
- onRoutingSucceeded: (event) => {
758
- console.log('Routing succeeded!', event);
759
- },
760
- },
761
- },
762
- verificationSettings: {
763
- events: {
764
- onVerificationSucceeded: (event) => {
765
- console.log(`Verification passed for transaction: ${event.txId}`);
766
- },
767
- onVerificationFailed: (event) => {
768
- console.error(
769
- `Verification failed for transaction: ${event.txId}`,
770
- event.error,
771
- );
772
- },
773
- onVerificationProgress: (event) => {
774
- const percentage = (event.processedBytes / event.totalBytes) * 100;
775
- console.log(
776
- `Verification progress for ${event.txId}: ${percentage.toFixed(2)}%`,
777
- );
778
- },
779
- },
454
+ // Configure to use x402-enabled gateways
455
+ strategy: new StaticRoutingStrategy({
456
+ gateway: 'https://paid-gateway.example.com',
457
+ }),
780
458
  },
781
459
  });
782
460
 
783
- // listen to the global wayfinder event emitter for all requests
784
- wayfinder.emitter.on('routing-succeeded', (event) => {
785
- console.log(`Request routed to: ${event.targetGateway}`);
786
- });
461
+ // Requests will now automatically handle x402 payments
462
+ const response = await wayfinder.request('ar://transaction-id');
463
+ ```
787
464
 
788
- wayfinder.emitter.on('routing-failed', (event) => {
789
- console.error(`Routing failed: ${event.error.message}`);
790
- });
465
+ **How it works:**
791
466
 
792
- wayfinder.emitter.on('verification-progress', (event) => {
793
- console.log(`Verification progress: ${event.progress}%`);
794
- });
467
+ 1. When a gateway returns a `402 Payment Required` status
468
+ 2. The x402 fetch automatically handles the payment flow
469
+ 3. The request is retried with payment credentials
470
+ 4. You get access to premium gateway services
795
471
 
796
- wayfinder.emitter.on('verification-succeeded', (event) => {
797
- console.log(`Verification succeeded: ${event.txId}`);
798
- });
472
+ **Use cases:**
799
473
 
800
- wayfinder.emitter.on('verification-failed', (event) => {
801
- console.error(`Verification failed: ${event.error.message}`);
802
- });
803
- ```
474
+ - Higher rate limits on data requests
475
+ - Access to premium gateway features
476
+ - Supporting gateway operators through payments
804
477
 
805
- ### Request-specific events
478
+ To learn more about x402 payments, visit the [x402 documentation](https://docs.ar.io/learn/gateways/x402-payments).
806
479
 
807
- You can also provide events to the `request` function to track a single request. These events are called for each request and are not updated for subsequent requests.
480
+ ## Events and Monitoring
808
481
 
809
- > [!INFO]
810
- > Events are still emitted to the global event emitter for all requests. It is recommended to use the global event emitter for tracking all requests, and the request-specific events for tracking a single request.
482
+ #### Global Events
811
483
 
812
484
  ```javascript
813
- // create a wayfinder instance with verification enabled
814
- const wayfinder = new Wayfinder({
815
- verificationSettings: {
816
- enabled: true,
817
- strategy: new HashVerificationStrategy({
818
- trustedGateways: ['https://permagate.io'],
819
- }),
485
+ const wayfinder = createWayfinderClient({
486
+ routingSettings: {
820
487
  events: {
821
- onVerificationProgress: (event) => {
822
- console.log(`Global callback handler called for: ${event.txId}`);
823
- },
824
- onVerificationSucceeded: (event) => {
825
- console.log(`Global callback handler called for: ${event.txId}`);
826
- },
488
+ onRoutingStarted: (event) => console.log('Routing started:', event),
489
+ onRoutingSucceeded: (event) => console.log('Gateway selected:', event),
827
490
  },
828
491
  },
829
- });
830
-
831
- const response = await wayfinder.request('ar://example-name', {
832
492
  verificationSettings: {
833
- // these callbacks will be triggered for this request only, the global callback handlers are still called
834
493
  events: {
835
494
  onVerificationProgress: (event) => {
836
- console.log(`Request-specific callback handler called for: ${event.txId}`);
837
- },
838
- onVerificationSucceeded: (event) => {
839
- console.log(`Request-specific callback handler called for: ${event.txId}`);
495
+ const percentage = (event.processedBytes / event.totalBytes) * 100;
496
+ console.log(`Verification: ${percentage.toFixed(2)}%`);
840
497
  },
498
+ onVerificationSucceeded: (event) => console.log('Verified:', event.txId),
841
499
  },
842
500
  },
843
501
  });
844
502
  ```
845
503
 
846
- ## Installation Notes
847
-
848
- ### Optional Dependencies
849
-
850
- The `@ar.io/sdk` package is an optional peer dependency. To use AR.IO network gateways, instantiate a `NetworkGatewaysProvider` with an `ario` instance and supply it to `Wayfinder` directly:
851
-
852
- **With AR.IO SDK (Recommended):**
853
- ```bash
854
- npm install @ar.io/wayfinder-core @ar.io/sdk
855
- # or
856
- yarn add @ar.io/wayfinder-core @ar.io/sdk
857
- ```
858
- - `new NetworkGatewaysProvider({ ario: ARIO.mainnet() })` exposes AR.IO network gateways
859
- - Supports intelligent gateway selection criteria
860
- - Dynamic gateway discovery and updates
861
-
862
- ### Caching
863
-
864
- Wayfinder supports intelligent caching:
865
-
866
- - **In browsers**: Uses localStorage for persistent caching across page reloads
867
- - **In Node.js**: Uses in-memory caching
868
- - **What's cached**: Gateway lists, routing decisions, and more
869
- - **Cache configuration**:
870
- - `cache: true` - Enable with default 5-minute TTL
871
- - `cache: { ttlSeconds: 3600 }` - Enable with custom TTL (in seconds)
872
- - `cache: false` - Disable caching (default)
873
-
874
- ## Advanced Usage
875
-
876
- ### Custom Providers and Strategies
877
-
878
- For advanced use cases, provide strategy instances explicitly:
504
+ #### Request-Specific Events
879
505
 
880
506
  ```javascript
881
- import {
882
- createWayfinderClient,
883
- FastestPingRoutingStrategy,
884
- HashVerificationStrategy,
885
- } from '@ar.io/wayfinder-core';
886
-
887
- const wayfinder = createWayfinderClient({
888
- // Enable caching with custom TTL
889
- cache: { ttlSeconds: 3600 }, // 1 hour
890
-
891
- // Supply a bespoke routing strategy
892
- routingStrategy: new FastestPingRoutingStrategy({
893
- timeoutMs: 1000,
894
- }),
895
-
896
- // Configure verification explicitly
897
- verificationStrategy: new HashVerificationStrategy({
898
- trustedGateways: [new URL('https://permagate.io')],
899
- }),
900
- });
901
- ```
902
-
903
- ### Direct Constructor Usage
904
-
905
- For complete control, you can use the Wayfinder constructor directly. This is useful when you need fine-grained control over the configuration:
906
-
907
- > _Wayfinder client that caches the top 10 gateways by operator stake from the ARIO Network for 1 hour and uses the fastest pinging routing strategy to select the fastest gateway for requests._
908
-
909
- ```javascript
910
- import { Wayfinder, NetworkGatewaysProvider, SimpleCacheGatewaysProvider, FastestPingRoutingStrategy, HashVerificationStrategy } from '@ar.io/wayfinder-core';
911
- import { ARIO } from '@ar.io/sdk';
912
-
913
- const wayfinder = new Wayfinder({
914
- // cache the top 10 gateways by operator stake from the ARIO Network for 1 hour
915
- gatewaysProvider: new SimpleCacheGatewaysProvider({
916
- ttlSeconds: 60 * 60, // cache the gateways for 1 hour
917
- gatewaysProvider: new NetworkGatewaysProvider({
918
- ario: ARIO.mainnet(),
919
- sortBy: 'operatorStake',
920
- sortOrder: 'desc',
921
- limit: 10,
922
- }),
923
- }),
924
- // routing settings
925
- routingSettings: {
926
- // use the fastest pinging strategy to select the fastest gateway for requests
927
- strategy: new FastestPingRoutingStrategy({
928
- timeoutMs: 1000,
929
- }),
930
- // events
931
- events: {
932
- onRoutingStarted: (event) => {
933
- console.log('Routing started!', event);
934
- },
935
- onRoutingSkipped: (event) => {
936
- console.log('Routing skipped!', event);
937
- },
938
- onRoutingSucceeded: (event) => {
939
- console.log('Routing succeeded!', event);
940
- },
941
- },
942
- },
943
- // verification settings
507
+ const response = await wayfinder.request('ar://example', {
944
508
  verificationSettings: {
945
- // enable verification - if false, verification will be skipped for all requests
946
- enabled: true,
947
- // verify the data using the hash of the data against a list of trusted gateways
948
- strategy: new HashVerificationStrategy({
949
- trustedGateways: [new URL('https://permagate.io')],
950
- }),
951
- // strict verification - if true, verification failures will cause requests to fail
952
- strict: true,
953
- // events
954
509
  events: {
955
510
  onVerificationProgress: (event) => {
956
- console.log('Verification progress!', event);
957
- },
958
- onVerificationSucceeded: (event) => {
959
- console.log('Verification succeeded!', event);
960
- },
961
- onVerificationFailed: (event) => {
962
- console.log('Verification failed!', event);
511
+ console.log(`This request: ${event.txId}`);
963
512
  },
964
513
  },
965
514
  },
@@ -970,26 +519,23 @@ const wayfinder = new Wayfinder({
970
519
 
971
520
  Wayfinder can optionally emit OpenTelemetry spans for every request. **By default, telemetry is disabled**. You can control this behavior with the `telemetry` option.
972
521
 
973
- ```javascript
974
-
522
+ ```typescript
975
523
  import { createWayfinderClient } from '@ar.io/wayfinder-core';
976
524
 
977
525
  const wayfinder = createWayfinderClient({
978
526
  // other settings...
979
- telemetry: {
980
- enabled: true, // disabled by default (must be explicitly enabled)
981
- sampleRate: 0.1, // 10% sample rate by default
982
- exporterUrl: 'https://your-custom-otel-exporter', // optional, defaults to https://api.honeycomb.io/v1/traces
983
- clientName: 'my-custom-client-name', // optional, defaults to wayfinder-core
984
- clientVersion: '1.0.0', // optional, defaults to empty
527
+ telemetrySettings: {
528
+ enabled: true,
529
+ sampleRate: 0.1, // 10% sampling
530
+ exporterUrl: 'https://your-otel-exporter',
531
+ clientName: 'my-app',
532
+ clientVersion: '1.0.0',
985
533
  },
986
534
  });
987
535
  ```
988
536
 
989
537
  ## Request Flow
990
538
 
991
- The following sequence diagram illustrates how Wayfinder processes requests:
992
-
993
539
  ```mermaid
994
540
  sequenceDiagram
995
541
  participant Client
@@ -1006,27 +552,19 @@ sequenceDiagram
1006
552
  Wayfinder->>+Gateways Provider: getGateways()
1007
553
  Gateways Provider-->>-Wayfinder: List of gateway URLs
1008
554
 
1009
- Wayfinder->>+Routing Strategy: selectGateway() from list of gateways
1010
- Routing Strategy-->>-Wayfinder: Select gateway for request
1011
-
1012
- Wayfinder->>+Selected Gateway: Send HTTP request to target gateway
1013
- Selected Gateway-->>-Wayfinder: Response with data & txId
1014
-
1015
- activate Verification Strategy
1016
- Wayfinder->>+Verification Strategy: verifyData(responseData, txId)
1017
- Verification Strategy->>Wayfinder: Emit 'verification-progress' events
1018
- Verification Strategy->>Trusted Gateways: Request verification headers
1019
- Trusted Gateways-->>Verification Strategy: Return verification headers
1020
- Verification Strategy->>Verification Strategy: Compare computed vs trusted data
1021
- Verification Strategy-->>-Wayfinder: Return request data with verification result
1022
-
1023
- alt Verification passed
1024
- Wayfinder->>Wayfinder: Emit 'verification-passed' event
1025
- Wayfinder-->>Client: Return verified response
1026
- else Verification failed
1027
- Wayfinder->>Wayfinder: Emit 'verification-failed' event
1028
- Wayfinder-->>Client: Throw verification error
555
+ Wayfinder->>+Routing Strategy: selectGateway()
556
+ Routing Strategy-->>-Wayfinder: Selected gateway
557
+
558
+ Wayfinder->>+Selected Gateway: HTTP request
559
+ Selected Gateway-->>-Wayfinder: Response data
560
+
561
+ opt Verification enabled
562
+ Wayfinder->>+Verification Strategy: verifyData()
563
+ Verification Strategy->>Trusted Gateways: Get verification data
564
+ Trusted Gateways-->>Verification Strategy: Verification headers
565
+ Verification Strategy-->>-Wayfinder: Verification result
1029
566
  end
1030
567
 
568
+ Wayfinder-->>Client: Response or error
1031
569
  deactivate Wayfinder
1032
570
  ```