@ar.io/wayfinder-core 1.3.1 → 1.4.0-alpha.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 +197 -20
- package/dist/client.d.ts +89 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +353 -0
- package/dist/gateways/network.d.ts +1 -1
- package/dist/gateways/network.d.ts.map +1 -1
- package/dist/gateways/network.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/routing/ping.d.ts +8 -4
- package/dist/routing/ping.d.ts.map +1 -1
- package/dist/routing/ping.js +23 -13
- package/dist/routing/random.d.ts +9 -19
- package/dist/routing/random.d.ts.map +1 -1
- package/dist/routing/random.js +32 -3
- package/dist/routing/round-robin.d.ts +5 -3
- package/dist/routing/round-robin.d.ts.map +1 -1
- package/dist/routing/round-robin.js +24 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -17,21 +17,96 @@ yarn add @ar.io/wayfinder-core
|
|
|
17
17
|
### Basic Usage
|
|
18
18
|
|
|
19
19
|
```javascript
|
|
20
|
+
import { createWayfinderClient } from '@ar.io/wayfinder-core';
|
|
21
|
+
|
|
22
|
+
// Uses static gateways by default
|
|
23
|
+
const wayfinder = createWayfinderClient();
|
|
24
|
+
|
|
25
|
+
// Use Wayfinder to fetch and verify data using ar:// protocol
|
|
26
|
+
const response = await wayfinder.request('ar://example-name');
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Using with AR.IO Network
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
import { createWayfinderClient } from '@ar.io/wayfinder-core';
|
|
20
33
|
import { ARIO } from '@ar.io/sdk';
|
|
21
|
-
import { Wayfinder } from '@ar.io/wayfinder-core';
|
|
22
34
|
|
|
23
|
-
//
|
|
24
|
-
const wayfinder =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
sortBy: 'operatorStake',
|
|
28
|
-
sortOrder: 'desc',
|
|
29
|
-
limit: 10,
|
|
30
|
-
}),
|
|
35
|
+
// Provide ARIO instance to use AR.IO network gateways
|
|
36
|
+
const wayfinder = createWayfinderClient({
|
|
37
|
+
ario: ARIO.mainnet(),
|
|
38
|
+
gatewaySelection: 'highest-performing', // Selection criteria for AR.IO network
|
|
31
39
|
});
|
|
40
|
+
```
|
|
32
41
|
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
### Static Gateways with Custom Options
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
import { createWayfinderClient } from '@ar.io/wayfinder-core';
|
|
46
|
+
|
|
47
|
+
// Use custom static gateways
|
|
48
|
+
const wayfinder = createWayfinderClient({
|
|
49
|
+
trustedGateways: ['https://permagate.io', 'https://arweave.net'],
|
|
50
|
+
routing: 'fastest',
|
|
51
|
+
verification: 'hash',
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Configuration Options
|
|
56
|
+
|
|
57
|
+
`createWayfinderClient` accepts the following options:
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
const wayfinder = createWayfinderClient({
|
|
61
|
+
// Routing strategy
|
|
62
|
+
routing: 'fastest', // 'random' | 'fastest' | 'round-robin' | 'preferred'
|
|
63
|
+
|
|
64
|
+
// Verification strategy
|
|
65
|
+
verification: 'hash', // 'hash' | 'data-root' | 'remote' | 'disabled' (default: 'disabled')
|
|
66
|
+
|
|
67
|
+
// Gateway selection (only applies when ario instance is provided)
|
|
68
|
+
gatewaySelection: 'highest-performing', // 'highest-performing' | 'longest-tenure' | etc.
|
|
69
|
+
|
|
70
|
+
// Enable caching for routing and gateway providers
|
|
71
|
+
cache: true, // Uses default 5-minute TTL
|
|
72
|
+
// OR specify custom TTL:
|
|
73
|
+
// cache: { ttlSeconds: 3600 }, // 1 hour
|
|
74
|
+
|
|
75
|
+
// List of trusted gateways for verification
|
|
76
|
+
trustedGateways: ['https://arweave.net', 'https://permagate.io'],
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Sync version with static gateways (when no ario instance provided)
|
|
80
|
+
const wayfinderSync = createWayfinderClientSync({
|
|
81
|
+
// Same options as above, but uses static gateways by default
|
|
82
|
+
routing: 'random',
|
|
83
|
+
verification: 'disabled',
|
|
84
|
+
trustedGateways: ['https://permagate.io', 'https://arweave.net'],
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Gateway Selection Options (with AR.IO Network)
|
|
89
|
+
|
|
90
|
+
When using the AR.IO Network provider, you can specify how gateways are selected:
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
import { createWayfinderClient } from '@ar.io/wayfinder-core';
|
|
94
|
+
import { ARIO } from '@ar.io/sdk';
|
|
95
|
+
|
|
96
|
+
const wayfinder = createWayfinderClient({
|
|
97
|
+
ario: ARIO.mainnet(),
|
|
98
|
+
|
|
99
|
+
// Gateway selection (only works with ARIO instance)
|
|
100
|
+
gatewaySelection: 'highest-performing', // Options:
|
|
101
|
+
// 'highest-performing' - Gateways with best performance metrics
|
|
102
|
+
// 'longest-tenure' - Gateways with longest service history
|
|
103
|
+
// 'highest-staked' - Gateways with most stake
|
|
104
|
+
// 'highest-weight' - Gateways with highest composite weight
|
|
105
|
+
// 'longest-streak' - Gateways with longest uptime streak
|
|
106
|
+
|
|
107
|
+
routing: 'random', // How to select from the filtered gateways
|
|
108
|
+
cache: { ttlSeconds: 600 }, // Cache for 10 minutes
|
|
109
|
+
});
|
|
35
110
|
```
|
|
36
111
|
|
|
37
112
|
## ar:// Protocol
|
|
@@ -259,21 +334,34 @@ const strategy = new SimpleCacheRoutingStrategy({
|
|
|
259
334
|
|
|
260
335
|
#### Preferred gateway with fallback to ping-random
|
|
261
336
|
|
|
262
|
-
Attempt to use a favorite gateway, but
|
|
263
|
-
if it fails.
|
|
337
|
+
Attempt to use a favorite gateway, but fallback to a fastest pinging strategy using the ARIO Network if it fails.
|
|
264
338
|
|
|
265
339
|
```ts
|
|
266
340
|
import {
|
|
267
341
|
PreferredWithFallbackRoutingStrategy,
|
|
268
342
|
RandomRoutingStrategy,
|
|
269
343
|
PingRoutingStrategy,
|
|
344
|
+
NetworkGatewaysProvider,
|
|
270
345
|
} from "@ar.io/wayfinder-core";
|
|
346
|
+
import { ARIO } from '@ar.io/sdk';
|
|
347
|
+
|
|
348
|
+
// these will be our fallback gateways
|
|
349
|
+
const gatewayProvider = new NetworkGatewaysProvider({
|
|
350
|
+
ario: ARIO.mainnet(),
|
|
351
|
+
sortBy: 'operatorStake',
|
|
352
|
+
limit: 5,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// this is our fallback strategy if our preferred gateway fails
|
|
356
|
+
const fastestPingStrategy = new FastestPingRoutingStrategy({
|
|
357
|
+
timeoutMs: 500,
|
|
358
|
+
gatewaysProvider: gatewayProvider,
|
|
359
|
+
});
|
|
271
360
|
|
|
361
|
+
// compose the strategies together, the preferred gateway will be used first, and if it fails, the fallback strategy will be used.
|
|
272
362
|
const strategy = new PreferredWithFallbackRoutingStrategy({
|
|
273
363
|
preferredGateway: "https://my-gateway.example",
|
|
274
|
-
fallbackStrategy:
|
|
275
|
-
routingStrategy: new RandomRoutingStrategy(),
|
|
276
|
-
}),
|
|
364
|
+
fallbackStrategy: fastestPingStrategy,
|
|
277
365
|
});
|
|
278
366
|
```
|
|
279
367
|
|
|
@@ -285,13 +373,27 @@ Cycle through gateways sequentially, checking each one’s health before use.
|
|
|
285
373
|
import {
|
|
286
374
|
RoundRobinRoutingStrategy,
|
|
287
375
|
PingRoutingStrategy,
|
|
376
|
+
NetworkGatewaysProvider,
|
|
288
377
|
} from "@ar.io/wayfinder-core";
|
|
378
|
+
import { ARIO } from '@ar.io/sdk';
|
|
289
379
|
|
|
380
|
+
// use static gateways
|
|
290
381
|
const strategy = new PingRoutingStrategy({
|
|
291
382
|
routingStrategy: new RoundRobinRoutingStrategy({
|
|
292
383
|
gateways: [new URL("https://gw1"), new URL("https://gw2")],
|
|
293
384
|
}),
|
|
294
385
|
});
|
|
386
|
+
|
|
387
|
+
// use a dynamic list of gateways from the ARIO Network
|
|
388
|
+
const strategy2 = new PingRoutingStrategy({
|
|
389
|
+
routingStrategy: new RoundRobinRoutingStrategy({
|
|
390
|
+
gatewaysProvider: new NetworkGatewaysProvider({
|
|
391
|
+
ario: ARIO.mainnet(),
|
|
392
|
+
sortBy: 'operatorStake',
|
|
393
|
+
limit: 5,
|
|
394
|
+
}),
|
|
395
|
+
}),
|
|
396
|
+
});
|
|
295
397
|
```
|
|
296
398
|
|
|
297
399
|
#### Cache around any composed strategy
|
|
@@ -300,10 +402,21 @@ Because `SimpleCacheRoutingStrategy` accepts any `RoutingStrategy`, you can
|
|
|
300
402
|
cache more complex compositions too.
|
|
301
403
|
|
|
302
404
|
```ts
|
|
405
|
+
// use a dynamic list of gateways from the ARIO Network
|
|
406
|
+
const randomStrategy = new RandomRoutingStrategy({
|
|
407
|
+
gatewaysProvider: new NetworkGatewaysProvider({
|
|
408
|
+
ario: ARIO.mainnet(),
|
|
409
|
+
sortBy: 'operatorStake',
|
|
410
|
+
limit: 20,
|
|
411
|
+
}),
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// wrap the random strategy with a ping strategy
|
|
303
415
|
const pingRandom = new PingRoutingStrategy({
|
|
304
|
-
routingStrategy:
|
|
416
|
+
routingStrategy: randomStrategy,
|
|
305
417
|
});
|
|
306
418
|
|
|
419
|
+
// wrap the ping random strategy with a cache strategy, caching the selected gateway for 10 minutes
|
|
307
420
|
const cachedStrategy = new SimpleCacheRoutingStrategy({
|
|
308
421
|
routingStrategy: pingRandom,
|
|
309
422
|
ttlSeconds: 600,
|
|
@@ -510,13 +623,77 @@ const response = await wayfinder.request('ar://example-name', {
|
|
|
510
623
|
});
|
|
511
624
|
```
|
|
512
625
|
|
|
626
|
+
## Installation Notes
|
|
627
|
+
|
|
628
|
+
### Optional Dependencies
|
|
629
|
+
|
|
630
|
+
The `@ar.io/sdk` package is an optional peer dependency. To use AR.IO network gateways, you must explicitly provide an `ario` instance:
|
|
631
|
+
|
|
632
|
+
**With AR.IO SDK (Recommended):**
|
|
633
|
+
```bash
|
|
634
|
+
npm install @ar.io/wayfinder-core @ar.io/sdk
|
|
635
|
+
# or
|
|
636
|
+
yarn add @ar.io/wayfinder-core @ar.io/sdk
|
|
637
|
+
```
|
|
638
|
+
- `createWayfinderClient({ ario: ARIO.mainnet() })` uses AR.IO network gateways
|
|
639
|
+
- Supports intelligent gateway selection criteria
|
|
640
|
+
- Dynamic gateway discovery and updates
|
|
641
|
+
|
|
642
|
+
**Without AR.IO SDK:**
|
|
643
|
+
```bash
|
|
644
|
+
npm install @ar.io/wayfinder-core
|
|
645
|
+
```
|
|
646
|
+
- `createWayfinderClient()` falls back to curated static gateways
|
|
647
|
+
- `createWayfinderClientSync()` uses only static gateways
|
|
648
|
+
- Full routing and verification functionality available
|
|
649
|
+
- No network gateway selection options
|
|
650
|
+
|
|
651
|
+
### Caching
|
|
652
|
+
|
|
653
|
+
Wayfinder supports intelligent caching:
|
|
654
|
+
|
|
655
|
+
- **In browsers**: Uses localStorage for persistent caching across page reloads
|
|
656
|
+
- **In Node.js**: Uses in-memory caching
|
|
657
|
+
- **What's cached**: Gateway lists, routing decisions, and more
|
|
658
|
+
- **Cache configuration**:
|
|
659
|
+
- `cache: true` - Enable with default 5-minute TTL
|
|
660
|
+
- `cache: { ttlSeconds: 3600 }` - Enable with custom TTL (in seconds)
|
|
661
|
+
- `cache: false` - Disable caching (default)
|
|
662
|
+
|
|
513
663
|
## Advanced Usage
|
|
514
664
|
|
|
515
|
-
### Custom
|
|
665
|
+
### Using createWayfinderClient with Custom Providers
|
|
666
|
+
|
|
667
|
+
For advanced use cases, you can provide custom providers and strategies to `createWayfinderClient`:
|
|
668
|
+
|
|
669
|
+
```javascript
|
|
670
|
+
import { createWayfinderClient, NetworkGatewaysProvider } from '@ar.io/wayfinder-core';
|
|
671
|
+
import { ARIO } from '@ar.io/sdk';
|
|
672
|
+
|
|
673
|
+
const wayfinder = createWayfinderClient({
|
|
674
|
+
// Use custom gateways provider
|
|
675
|
+
gatewaysProvider: new NetworkGatewaysProvider({
|
|
676
|
+
ario: ARIO.mainnet(),
|
|
677
|
+
sortBy: 'operatorStake',
|
|
678
|
+
sortOrder: 'desc',
|
|
679
|
+
limit: 10,
|
|
680
|
+
}),
|
|
681
|
+
|
|
682
|
+
// Override with custom verification strategy
|
|
683
|
+
verification: 'hash',
|
|
684
|
+
trustedGateways: ['https://permagate.io'],
|
|
685
|
+
|
|
686
|
+
// Gateway selection
|
|
687
|
+
gatewaySelection: 'highest-staked',
|
|
688
|
+
|
|
689
|
+
// Enable caching with custom TTL
|
|
690
|
+
cache: { ttlSeconds: 3600 }, // 1 hour
|
|
691
|
+
});
|
|
692
|
+
```
|
|
516
693
|
|
|
517
|
-
|
|
694
|
+
### Direct Constructor Usage
|
|
518
695
|
|
|
519
|
-
|
|
696
|
+
For complete control, you can use the Wayfinder constructor directly. This is useful when you need fine-grained control over the configuration:
|
|
520
697
|
|
|
521
698
|
> _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._
|
|
522
699
|
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WayFinder
|
|
3
|
+
* Copyright (C) 2022-2025 Permanent Data Solutions, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { AoARIORead } from '@ar.io/sdk';
|
|
18
|
+
import type { GatewaysProvider, Logger, RoutingStrategy, VerificationStrategy } from './types.js';
|
|
19
|
+
import { Wayfinder } from './wayfinder.js';
|
|
20
|
+
export type RoutingOption = 'random' | 'fastest' | 'round-robin' | 'preferred';
|
|
21
|
+
export type VerificationOption = 'hash' | 'data-root' | 'remote' | 'disabled';
|
|
22
|
+
export type GatewaySelection = 'highest-performing' | 'longest-tenure' | 'highest-staked' | 'highest-weight' | 'longest-streak';
|
|
23
|
+
/**
|
|
24
|
+
* Creates a Wayfinder client synchronously using static gateways
|
|
25
|
+
* Use this when you want to avoid the AR.IO SDK dependency
|
|
26
|
+
*/
|
|
27
|
+
export declare function createWayfinderClientSync(options?: CreateWayfinderClientOptions): Wayfinder;
|
|
28
|
+
export interface CreateWayfinderClientOptions {
|
|
29
|
+
/**
|
|
30
|
+
* The ARIO instance to use for network gateways provider
|
|
31
|
+
* If not provided, will fall back to static gateways
|
|
32
|
+
*/
|
|
33
|
+
ario?: AoARIORead;
|
|
34
|
+
/**
|
|
35
|
+
* The routing strategy to use
|
|
36
|
+
* @default 'random'
|
|
37
|
+
*/
|
|
38
|
+
routing?: RoutingOption;
|
|
39
|
+
/**
|
|
40
|
+
* The verification strategy to use
|
|
41
|
+
* @default 'disabled'
|
|
42
|
+
*/
|
|
43
|
+
verification?: VerificationOption;
|
|
44
|
+
/**
|
|
45
|
+
* The gateway selection when using NetworkGatewaysProvider (requires ario instance)
|
|
46
|
+
* Only applies when using AR.IO network - ignored for static gateways
|
|
47
|
+
* @default 'highest-performing'
|
|
48
|
+
*/
|
|
49
|
+
gatewaySelection?: GatewaySelection;
|
|
50
|
+
/**
|
|
51
|
+
* The trusted gateways to use
|
|
52
|
+
* @default ['https://arweave.net']
|
|
53
|
+
*/
|
|
54
|
+
trustedGateways?: string[];
|
|
55
|
+
/**
|
|
56
|
+
* Cache configuration. Can be:
|
|
57
|
+
* - false/undefined: No caching
|
|
58
|
+
* - true: Enable caching with default TTL (300 seconds)
|
|
59
|
+
* - { ttlSeconds: number }: Enable caching with custom TTL
|
|
60
|
+
* @default false
|
|
61
|
+
*/
|
|
62
|
+
cache?: boolean | {
|
|
63
|
+
ttlSeconds: number;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Custom logger implementation
|
|
67
|
+
*/
|
|
68
|
+
logger?: Logger;
|
|
69
|
+
/**
|
|
70
|
+
* Custom gateways provider (overrides gatewaySelection)
|
|
71
|
+
*/
|
|
72
|
+
gatewaysProvider?: GatewaysProvider;
|
|
73
|
+
/**
|
|
74
|
+
* Custom routing strategy (overrides routing option)
|
|
75
|
+
*/
|
|
76
|
+
routingStrategy?: RoutingStrategy;
|
|
77
|
+
/**
|
|
78
|
+
* Custom verification strategy (overrides verification option)
|
|
79
|
+
*/
|
|
80
|
+
verificationStrategy?: VerificationStrategy;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Creates a Wayfinder client with the specified configuration
|
|
84
|
+
* Uses static gateways by default. Provide an `ario` instance to use NetworkGatewaysProvider
|
|
85
|
+
*/
|
|
86
|
+
export declare function createWayfinderClient(options?: CreateWayfinderClientOptions): Wayfinder;
|
|
87
|
+
export declare const createWayfinder: typeof createWayfinderClient;
|
|
88
|
+
export declare const createWayfinderSync: typeof createWayfinderClientSync;
|
|
89
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAS7C,OAAO,KAAK,EACV,gBAAgB,EAChB,MAAM,EACN,eAAe,EACf,oBAAoB,EAErB,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;AAE/E,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GACxB,oBAAoB,GACpB,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,CAAC;AAErB;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,4BAAiC,GACzC,SAAS,CAoLX;AAED,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAElC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAEzC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;OAEG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC;;OAEG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,4BAAiC,GACzC,SAAS,CAmLX;AAGD,eAAO,MAAM,eAAe,8BAAwB,CAAC;AACrD,eAAO,MAAM,mBAAmB,kCAA4B,CAAC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WayFinder
|
|
3
|
+
* Copyright (C) 2022-2025 Permanent Data Solutions, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { LocalStorageGatewaysProvider } from './gateways/local-storage-cache.js';
|
|
18
|
+
import { NetworkGatewaysProvider } from './gateways/network.js';
|
|
19
|
+
import { SimpleCacheGatewaysProvider } from './gateways/simple-cache.js';
|
|
20
|
+
import { StaticGatewaysProvider } from './gateways/static.js';
|
|
21
|
+
import { FastestPingRoutingStrategy } from './routing/ping.js';
|
|
22
|
+
import { PreferredWithFallbackRoutingStrategy } from './routing/preferred-with-fallback.js';
|
|
23
|
+
import { RandomRoutingStrategy } from './routing/random.js';
|
|
24
|
+
import { SimpleCacheRoutingStrategy } from './routing/simple-cache.js';
|
|
25
|
+
import { isBrowser } from './utils/browser.js';
|
|
26
|
+
import { DataRootVerificationStrategy } from './verification/data-root-verification.js';
|
|
27
|
+
import { HashVerificationStrategy } from './verification/hash-verification.js';
|
|
28
|
+
import { RemoteVerificationStrategy } from './verification/remote-verification.js';
|
|
29
|
+
import { Wayfinder } from './wayfinder.js';
|
|
30
|
+
/**
|
|
31
|
+
* Creates a Wayfinder client synchronously using static gateways
|
|
32
|
+
* Use this when you want to avoid the AR.IO SDK dependency
|
|
33
|
+
*/
|
|
34
|
+
export function createWayfinderClientSync(options = {}) {
|
|
35
|
+
const { routing = 'random', verification = 'disabled', trustedGateways = [], cache = false, gatewaySelection, logger, ario, gatewaysProvider: customGatewaysProvider, routingStrategy: customRoutingStrategy, verificationStrategy: customVerificationStrategy, } = options;
|
|
36
|
+
// Parse cache configuration
|
|
37
|
+
const cacheEnabled = !!cache;
|
|
38
|
+
const cacheTTLSeconds = typeof cache === 'object' ? cache.ttlSeconds : 300; // 5 minutes default
|
|
39
|
+
// Set up gateways provider
|
|
40
|
+
let gatewaysProvider;
|
|
41
|
+
if (customGatewaysProvider) {
|
|
42
|
+
gatewaysProvider = customGatewaysProvider;
|
|
43
|
+
}
|
|
44
|
+
else if (ario) {
|
|
45
|
+
// Use NetworkGatewaysProvider if ARIO instance is provided
|
|
46
|
+
let sortBy = 'totalDelegatedStake';
|
|
47
|
+
let sortOrder = 'desc';
|
|
48
|
+
const selection = gatewaySelection || 'highest-performing';
|
|
49
|
+
switch (selection) {
|
|
50
|
+
case 'highest-performing':
|
|
51
|
+
sortBy = 'weights.gatewayPerformanceRatio';
|
|
52
|
+
sortOrder = 'desc';
|
|
53
|
+
break;
|
|
54
|
+
case 'longest-tenure':
|
|
55
|
+
sortBy = 'weights.tenureWeight';
|
|
56
|
+
sortOrder = 'desc';
|
|
57
|
+
break;
|
|
58
|
+
case 'highest-staked':
|
|
59
|
+
sortBy = 'weights.stakeWeight';
|
|
60
|
+
sortOrder = 'desc';
|
|
61
|
+
break;
|
|
62
|
+
case 'highest-weight':
|
|
63
|
+
sortBy = 'weights.normalizedCompositeWeight';
|
|
64
|
+
sortOrder = 'desc';
|
|
65
|
+
break;
|
|
66
|
+
case 'longest-streak':
|
|
67
|
+
sortBy = 'stats.passedConsecutiveEpochs';
|
|
68
|
+
sortOrder = 'desc';
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
sortBy = 'weights.normalizedCompositeWeight';
|
|
72
|
+
sortOrder = 'desc';
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
gatewaysProvider = new NetworkGatewaysProvider({
|
|
76
|
+
ario,
|
|
77
|
+
sortBy,
|
|
78
|
+
sortOrder,
|
|
79
|
+
limit: 10,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Fall back to static gateways when no ARIO instance is provided
|
|
84
|
+
gatewaysProvider = new StaticGatewaysProvider({
|
|
85
|
+
gateways: trustedGateways.length
|
|
86
|
+
? trustedGateways
|
|
87
|
+
: [
|
|
88
|
+
'https://permagate.io',
|
|
89
|
+
'https://arweave.net',
|
|
90
|
+
'https://ardrive.net',
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
// Wrap with cache if enabled
|
|
95
|
+
if (cacheEnabled) {
|
|
96
|
+
if (isBrowser()) {
|
|
97
|
+
gatewaysProvider = new LocalStorageGatewaysProvider({
|
|
98
|
+
gatewaysProvider: gatewaysProvider,
|
|
99
|
+
ttlSeconds: cacheTTLSeconds,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
gatewaysProvider = new SimpleCacheGatewaysProvider({
|
|
104
|
+
gatewaysProvider: gatewaysProvider,
|
|
105
|
+
ttlSeconds: cacheTTLSeconds,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Set up routing strategy
|
|
110
|
+
let routingStrategy;
|
|
111
|
+
if (customRoutingStrategy) {
|
|
112
|
+
routingStrategy = customRoutingStrategy;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
switch (routing) {
|
|
116
|
+
case 'random':
|
|
117
|
+
routingStrategy = new RandomRoutingStrategy();
|
|
118
|
+
break;
|
|
119
|
+
case 'fastest':
|
|
120
|
+
routingStrategy = new FastestPingRoutingStrategy();
|
|
121
|
+
break;
|
|
122
|
+
case 'preferred':
|
|
123
|
+
routingStrategy = new PreferredWithFallbackRoutingStrategy({
|
|
124
|
+
preferredGateway: trustedGateways[0],
|
|
125
|
+
fallbackStrategy: new RandomRoutingStrategy(),
|
|
126
|
+
});
|
|
127
|
+
break;
|
|
128
|
+
default:
|
|
129
|
+
throw new Error(`Unknown routing strategy: ${routing}`);
|
|
130
|
+
}
|
|
131
|
+
// Wrap with cache if enabled
|
|
132
|
+
if (cacheEnabled) {
|
|
133
|
+
// TODO: add browser cache support for routing strategy
|
|
134
|
+
routingStrategy = new SimpleCacheRoutingStrategy({
|
|
135
|
+
routingStrategy,
|
|
136
|
+
ttlSeconds: cacheTTLSeconds,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Set up verification strategy
|
|
141
|
+
let verificationStrategy;
|
|
142
|
+
let verificationEnabled = true;
|
|
143
|
+
if (customVerificationStrategy) {
|
|
144
|
+
verificationStrategy = customVerificationStrategy;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
switch (verification) {
|
|
148
|
+
case 'hash':
|
|
149
|
+
verificationStrategy = new HashVerificationStrategy({
|
|
150
|
+
trustedGateways: trustedGateways.map((url) => new URL(url)),
|
|
151
|
+
});
|
|
152
|
+
break;
|
|
153
|
+
case 'data-root':
|
|
154
|
+
verificationStrategy = new DataRootVerificationStrategy({
|
|
155
|
+
trustedGateways: trustedGateways.map((url) => new URL(url)),
|
|
156
|
+
});
|
|
157
|
+
break;
|
|
158
|
+
case 'remote':
|
|
159
|
+
verificationStrategy = new RemoteVerificationStrategy();
|
|
160
|
+
break;
|
|
161
|
+
case 'disabled':
|
|
162
|
+
verificationEnabled = false;
|
|
163
|
+
verificationStrategy = undefined;
|
|
164
|
+
break;
|
|
165
|
+
default:
|
|
166
|
+
throw new Error(`Unknown verification strategy: ${verification}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Create Wayfinder options
|
|
170
|
+
const wayfinderOptions = {
|
|
171
|
+
logger,
|
|
172
|
+
gatewaysProvider,
|
|
173
|
+
routingSettings: {
|
|
174
|
+
strategy: routingStrategy,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
// Only add verification settings if not disabled
|
|
178
|
+
if (verificationEnabled && verificationStrategy) {
|
|
179
|
+
wayfinderOptions.verificationSettings = {
|
|
180
|
+
enabled: true,
|
|
181
|
+
strategy: verificationStrategy,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
wayfinderOptions.verificationSettings = {
|
|
186
|
+
enabled: false,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
return new Wayfinder(wayfinderOptions);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Creates a Wayfinder client with the specified configuration
|
|
193
|
+
* Uses static gateways by default. Provide an `ario` instance to use NetworkGatewaysProvider
|
|
194
|
+
*/
|
|
195
|
+
export function createWayfinderClient(options = {}) {
|
|
196
|
+
const { routing = 'random', verification = 'disabled', trustedGateways = [], cache = false, gatewaySelection, logger, ario, gatewaysProvider: customGatewaysProvider, routingStrategy: customRoutingStrategy, verificationStrategy: customVerificationStrategy, } = options;
|
|
197
|
+
// Parse cache configuration
|
|
198
|
+
const cacheEnabled = !!cache;
|
|
199
|
+
const cacheTTLSeconds = typeof cache === 'object' ? cache.ttlSeconds : 300; // 5 minutes default
|
|
200
|
+
// Set up gateways provider
|
|
201
|
+
let gatewaysProvider;
|
|
202
|
+
if (customGatewaysProvider) {
|
|
203
|
+
gatewaysProvider = customGatewaysProvider;
|
|
204
|
+
}
|
|
205
|
+
else if (ario) {
|
|
206
|
+
// Use NetworkGatewaysProvider with dynamically imported ARIO
|
|
207
|
+
let sortBy = 'totalDelegatedStake';
|
|
208
|
+
let sortOrder = 'desc';
|
|
209
|
+
switch (gatewaySelection) {
|
|
210
|
+
case 'highest-performing':
|
|
211
|
+
sortBy = 'weights.gatewayPerformanceRatio';
|
|
212
|
+
sortOrder = 'desc';
|
|
213
|
+
break;
|
|
214
|
+
case 'longest-tenure':
|
|
215
|
+
sortBy = 'weights.tenureWeight';
|
|
216
|
+
sortOrder = 'desc';
|
|
217
|
+
break;
|
|
218
|
+
case 'highest-staked':
|
|
219
|
+
sortBy = 'weights.stakeWeight';
|
|
220
|
+
sortOrder = 'desc';
|
|
221
|
+
break;
|
|
222
|
+
case 'highest-weight':
|
|
223
|
+
sortBy = 'weights.normalizedCompositeWeight';
|
|
224
|
+
sortOrder = 'desc';
|
|
225
|
+
break;
|
|
226
|
+
case 'longest-streak':
|
|
227
|
+
sortBy = 'stats.passedConsecutiveEpochs';
|
|
228
|
+
sortOrder = 'desc';
|
|
229
|
+
break;
|
|
230
|
+
default:
|
|
231
|
+
sortBy = 'weights.normalizedCompositeWeight';
|
|
232
|
+
sortOrder = 'desc';
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
gatewaysProvider = new NetworkGatewaysProvider({
|
|
236
|
+
ario,
|
|
237
|
+
sortBy,
|
|
238
|
+
sortOrder,
|
|
239
|
+
limit: 10,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
// Fall back to static gateways when no ARIO instance is provided
|
|
244
|
+
gatewaysProvider = new StaticGatewaysProvider({
|
|
245
|
+
gateways: trustedGateways.length
|
|
246
|
+
? trustedGateways
|
|
247
|
+
: [
|
|
248
|
+
'https://permagate.io',
|
|
249
|
+
'https://arweave.net',
|
|
250
|
+
'https://ardrive.net',
|
|
251
|
+
],
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
// Wrap with cache if enabled
|
|
255
|
+
if (cacheEnabled) {
|
|
256
|
+
if (isBrowser()) {
|
|
257
|
+
gatewaysProvider = new LocalStorageGatewaysProvider({
|
|
258
|
+
gatewaysProvider: gatewaysProvider,
|
|
259
|
+
ttlSeconds: cacheTTLSeconds,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
gatewaysProvider = new SimpleCacheGatewaysProvider({
|
|
264
|
+
gatewaysProvider: gatewaysProvider,
|
|
265
|
+
ttlSeconds: cacheTTLSeconds,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// Set up routing strategy
|
|
270
|
+
let routingStrategy;
|
|
271
|
+
if (customRoutingStrategy) {
|
|
272
|
+
routingStrategy = customRoutingStrategy;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
switch (routing) {
|
|
276
|
+
case 'random':
|
|
277
|
+
routingStrategy = new RandomRoutingStrategy();
|
|
278
|
+
break;
|
|
279
|
+
case 'fastest':
|
|
280
|
+
routingStrategy = new FastestPingRoutingStrategy();
|
|
281
|
+
break;
|
|
282
|
+
case 'preferred':
|
|
283
|
+
routingStrategy = new PreferredWithFallbackRoutingStrategy({
|
|
284
|
+
preferredGateway: trustedGateways[0],
|
|
285
|
+
fallbackStrategy: new RandomRoutingStrategy(),
|
|
286
|
+
});
|
|
287
|
+
break;
|
|
288
|
+
default:
|
|
289
|
+
throw new Error(`Unknown routing strategy: ${routing}`);
|
|
290
|
+
}
|
|
291
|
+
// Wrap with cache if enabled
|
|
292
|
+
if (cacheEnabled) {
|
|
293
|
+
// TODO: add browser cache support for routing strategy
|
|
294
|
+
routingStrategy = new SimpleCacheRoutingStrategy({
|
|
295
|
+
routingStrategy,
|
|
296
|
+
ttlSeconds: cacheTTLSeconds,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// Set up verification strategy
|
|
301
|
+
let verificationStrategy;
|
|
302
|
+
let verificationEnabled = true;
|
|
303
|
+
if (customVerificationStrategy) {
|
|
304
|
+
verificationStrategy = customVerificationStrategy;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
switch (verification) {
|
|
308
|
+
case 'hash':
|
|
309
|
+
verificationStrategy = new HashVerificationStrategy({
|
|
310
|
+
trustedGateways: trustedGateways.map((url) => new URL(url)),
|
|
311
|
+
});
|
|
312
|
+
break;
|
|
313
|
+
case 'data-root':
|
|
314
|
+
verificationStrategy = new DataRootVerificationStrategy({
|
|
315
|
+
trustedGateways: trustedGateways.map((url) => new URL(url)),
|
|
316
|
+
});
|
|
317
|
+
break;
|
|
318
|
+
case 'remote':
|
|
319
|
+
verificationStrategy = new RemoteVerificationStrategy();
|
|
320
|
+
break;
|
|
321
|
+
case 'disabled':
|
|
322
|
+
verificationEnabled = false;
|
|
323
|
+
verificationStrategy = undefined;
|
|
324
|
+
break;
|
|
325
|
+
default:
|
|
326
|
+
throw new Error(`Unknown verification strategy: ${verification}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// Create Wayfinder options
|
|
330
|
+
const wayfinderOptions = {
|
|
331
|
+
logger,
|
|
332
|
+
gatewaysProvider,
|
|
333
|
+
routingSettings: {
|
|
334
|
+
strategy: routingStrategy,
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
// Only add verification settings if not disabled
|
|
338
|
+
if (verificationEnabled && verificationStrategy) {
|
|
339
|
+
wayfinderOptions.verificationSettings = {
|
|
340
|
+
enabled: true,
|
|
341
|
+
strategy: verificationStrategy,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
wayfinderOptions.verificationSettings = {
|
|
346
|
+
enabled: false,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
return new Wayfinder(wayfinderOptions);
|
|
350
|
+
}
|
|
351
|
+
// Re-export as aliases
|
|
352
|
+
export const createWayfinder = createWayfinderClient;
|
|
353
|
+
export const createWayfinderSync = createWayfinderClientSync;
|
|
@@ -25,7 +25,7 @@ export declare class NetworkGatewaysProvider implements GatewaysProvider {
|
|
|
25
25
|
private logger;
|
|
26
26
|
constructor({ ario, sortBy, sortOrder, limit, filter, logger, }: {
|
|
27
27
|
ario: AoARIORead;
|
|
28
|
-
sortBy?: 'totalDelegatedStake' | 'operatorStake' | 'startTimestamp';
|
|
28
|
+
sortBy?: 'totalDelegatedStake' | 'operatorStake' | 'startTimestamp' | 'weights.gatewayPerformanceRatio' | 'weights.tenureWeight' | 'weights.stakeWeight' | 'weights.compositeWeight' | 'stats.passedConsecutiveEpochs' | 'weights.normalizedCompositeWeight';
|
|
29
29
|
sortOrder?: 'asc' | 'desc';
|
|
30
30
|
limit?: number;
|
|
31
31
|
blocklist?: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/gateways/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE5D,qBAAa,uBAAwB,YAAW,gBAAgB;IAC9D,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/gateways/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE5D,qBAAa,uBAAwB,YAAW,gBAAgB;IAC9D,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,MAAM,CAS0B;IACxC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,MAAM,CAAS;gBAEX,EACV,IAAI,EACJ,MAAwB,EACxB,SAAkB,EAClB,KAAY,EACZ,MAAqC,EACrC,MAAsB,GACvB,EAAE;QACD,IAAI,EAAE,UAAU,CAAC;QACjB,MAAM,CAAC,EACH,qBAAqB,GACrB,eAAe,GACf,gBAAgB,GAChB,iCAAiC,GACjC,sBAAsB,GACtB,qBAAqB,GACrB,yBAAyB,GACzB,+BAA+B,GAC/B,mCAAmC,CAAC;QACxC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;QAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC;QACnC,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB;IASK,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;CA2DpC"}
|
package/dist/gateways/network.js
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,cAAc,YAAY,CAAC;AAG3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sCAAsC,CAAC;AACrD,cAAc,2BAA2B,CAAC;AAG1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,mCAAmC,CAAC;AAGlD,cAAc,0CAA0C,CAAC;AACzD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,cAAc,uCAAuC,CAAC;AAGtD,cAAc,cAAc,CAAC;AAG7B,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,cAAc,YAAY,CAAC;AAG3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sCAAsC,CAAC;AACrD,cAAc,2BAA2B,CAAC;AAG1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,mCAAmC,CAAC;AAGlD,cAAc,0CAA0C,CAAC;AACzD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,cAAc,uCAAuC,CAAC;AAGtD,cAAc,cAAc,CAAC;AAG7B,cAAc,gBAAgB,CAAC;AAG/B,cAAc,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/routing/ping.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import type { Logger, RoutingStrategy } from '../types.js';
|
|
1
|
+
import type { GatewaysProvider, Logger, RoutingStrategy } from '../types.js';
|
|
2
2
|
export declare class FastestPingRoutingStrategy implements RoutingStrategy {
|
|
3
3
|
private timeoutMs;
|
|
4
4
|
private logger;
|
|
5
5
|
private maxConcurrency;
|
|
6
|
-
|
|
6
|
+
private gatewaysProvider?;
|
|
7
|
+
constructor({ timeoutMs, maxConcurrency, logger, gatewaysProvider, }?: {
|
|
7
8
|
timeoutMs?: number;
|
|
8
9
|
maxConcurrency?: number;
|
|
9
10
|
logger?: Logger;
|
|
11
|
+
gatewaysProvider?: GatewaysProvider;
|
|
10
12
|
});
|
|
11
13
|
selectGateway({ gateways, path, subdomain, }: {
|
|
12
|
-
gateways
|
|
14
|
+
gateways?: URL[];
|
|
13
15
|
path?: string;
|
|
14
16
|
subdomain?: string;
|
|
15
17
|
}): Promise<URL>;
|
|
@@ -25,11 +27,13 @@ export declare class PingRoutingStrategy implements RoutingStrategy {
|
|
|
25
27
|
private logger;
|
|
26
28
|
private retries;
|
|
27
29
|
private timeoutMs;
|
|
28
|
-
|
|
30
|
+
private gatewaysProvider?;
|
|
31
|
+
constructor({ routingStrategy, logger, retries, timeoutMs, gatewaysProvider, }: {
|
|
29
32
|
routingStrategy: RoutingStrategy;
|
|
30
33
|
logger?: Logger;
|
|
31
34
|
retries?: number;
|
|
32
35
|
timeoutMs?: number;
|
|
36
|
+
gatewaysProvider?: GatewaysProvider;
|
|
33
37
|
});
|
|
34
38
|
selectGateway(params: {
|
|
35
39
|
gateways?: URL[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ping.d.ts","sourceRoot":"","sources":["../../src/routing/ping.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ping.d.ts","sourceRoot":"","sources":["../../src/routing/ping.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7E,qBAAa,0BAA2B,YAAW,eAAe;IAChE,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,gBAAgB,CAAC,CAAmB;gBAEhC,EACV,SAAe,EACf,cAAmB,EACnB,MAAsB,EACtB,gBAAgB,GACjB,GAAE;QACD,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;KAChC;IAOA,aAAa,CAAC,EAClB,QAAQ,EACR,IAAS,EACT,SAAS,GACV,EAAE;QACD,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,GAAG,CAAC;CAoFjB;AAED;;;;;GAKG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IACzD,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,gBAAgB,CAAC,CAAmB;gBAEhC,EACV,eAAe,EACf,MAAsB,EACtB,OAAW,EACX,SAAgB,EAChB,gBAAgB,GACjB,EAAE;QACD,eAAe,EAAE,eAAe,CAAC;QACjC,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;KACrC;IAQK,aAAa,CAAC,MAAM,EAAE;QAC1B,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,GAAG,CAAC;CAkFjB"}
|
package/dist/routing/ping.js
CHANGED
|
@@ -20,25 +20,29 @@ export class FastestPingRoutingStrategy {
|
|
|
20
20
|
timeoutMs;
|
|
21
21
|
logger;
|
|
22
22
|
maxConcurrency;
|
|
23
|
-
|
|
23
|
+
gatewaysProvider;
|
|
24
|
+
constructor({ timeoutMs = 500, maxConcurrency = 50, logger = defaultLogger, gatewaysProvider, } = {}) {
|
|
24
25
|
this.timeoutMs = timeoutMs;
|
|
25
26
|
this.logger = logger;
|
|
26
27
|
this.maxConcurrency = maxConcurrency;
|
|
28
|
+
this.gatewaysProvider = gatewaysProvider;
|
|
27
29
|
}
|
|
28
30
|
async selectGateway({ gateways, path = '', subdomain, }) {
|
|
29
|
-
|
|
31
|
+
const resolvedGateways = gateways ??
|
|
32
|
+
(this.gatewaysProvider ? await this.gatewaysProvider.getGateways() : []);
|
|
33
|
+
if (resolvedGateways.length === 0) {
|
|
30
34
|
const error = new Error('No gateways provided');
|
|
31
35
|
this.logger.error('Failed to select gateway', { error: error.message });
|
|
32
36
|
throw error;
|
|
33
37
|
}
|
|
34
38
|
try {
|
|
35
|
-
this.logger.debug(`Pinging ${
|
|
36
|
-
gateways:
|
|
39
|
+
this.logger.debug(`Pinging ${resolvedGateways.length} gateways with timeout ${this.timeoutMs}ms`, {
|
|
40
|
+
gateways: resolvedGateways.map((g) => g.toString()),
|
|
37
41
|
timeoutMs: this.timeoutMs,
|
|
38
42
|
probePath: path,
|
|
39
43
|
});
|
|
40
|
-
const throttle = pLimit(Math.min(this.maxConcurrency,
|
|
41
|
-
const pingPromises =
|
|
44
|
+
const throttle = pLimit(Math.min(this.maxConcurrency, resolvedGateways.length));
|
|
45
|
+
const pingPromises = resolvedGateways.map(async (gateway) => {
|
|
42
46
|
return throttle(async () => {
|
|
43
47
|
const url = new URL(gateway.toString());
|
|
44
48
|
if (subdomain) {
|
|
@@ -79,11 +83,11 @@ export class FastestPingRoutingStrategy {
|
|
|
79
83
|
this.logger.error('All gateways failed to respond', {
|
|
80
84
|
subdomain,
|
|
81
85
|
path,
|
|
82
|
-
gateways:
|
|
86
|
+
gateways: resolvedGateways.map((g) => g.toString()),
|
|
83
87
|
});
|
|
84
88
|
throw new Error('All gateways failed to respond', {
|
|
85
89
|
cause: {
|
|
86
|
-
gateways:
|
|
90
|
+
gateways: resolvedGateways.map((g) => g.toString()),
|
|
87
91
|
path,
|
|
88
92
|
subdomain,
|
|
89
93
|
},
|
|
@@ -102,21 +106,27 @@ export class PingRoutingStrategy {
|
|
|
102
106
|
logger;
|
|
103
107
|
retries;
|
|
104
108
|
timeoutMs;
|
|
105
|
-
|
|
109
|
+
gatewaysProvider;
|
|
110
|
+
constructor({ routingStrategy, logger = defaultLogger, retries = 5, timeoutMs = 1000, gatewaysProvider, }) {
|
|
106
111
|
this.routingStrategy = routingStrategy;
|
|
107
112
|
this.logger = logger;
|
|
108
113
|
this.retries = retries;
|
|
109
114
|
this.timeoutMs = timeoutMs;
|
|
115
|
+
this.gatewaysProvider = gatewaysProvider;
|
|
110
116
|
}
|
|
111
117
|
async selectGateway(params) {
|
|
112
|
-
const { gateways
|
|
113
|
-
|
|
118
|
+
const { gateways, path, subdomain } = params;
|
|
119
|
+
const resolvedGateways = gateways ??
|
|
120
|
+
(this.gatewaysProvider ? await this.gatewaysProvider.getGateways() : []);
|
|
121
|
+
if (resolvedGateways.length === 0) {
|
|
114
122
|
throw new Error('No gateways available');
|
|
115
123
|
}
|
|
124
|
+
const paramsWithGateways = { ...params, gateways: resolvedGateways };
|
|
116
125
|
for (let i = 0; i < this.retries; i++) {
|
|
117
126
|
let selectedGateway = undefined;
|
|
118
127
|
try {
|
|
119
|
-
selectedGateway =
|
|
128
|
+
selectedGateway =
|
|
129
|
+
await this.routingStrategy.selectGateway(paramsWithGateways);
|
|
120
130
|
const pingUrl = new URL(selectedGateway.toString());
|
|
121
131
|
if (subdomain) {
|
|
122
132
|
pingUrl.hostname = `${subdomain}.${pingUrl.hostname}`;
|
|
@@ -166,7 +176,7 @@ export class PingRoutingStrategy {
|
|
|
166
176
|
}
|
|
167
177
|
throw new Error('Failed to find working gateway after HEAD checks', {
|
|
168
178
|
cause: {
|
|
169
|
-
gateways:
|
|
179
|
+
gateways: resolvedGateways.map((g) => g.toString()),
|
|
170
180
|
path,
|
|
171
181
|
subdomain,
|
|
172
182
|
retries: this.retries,
|
package/dist/routing/random.d.ts
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
* WayFinder
|
|
3
|
-
* Copyright (C) 2022-2025 Permanent Data Solutions, Inc.
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
import type { RoutingStrategy } from '../types.js';
|
|
1
|
+
import type { GatewaysProvider, Logger, RoutingStrategy } from '../types.js';
|
|
18
2
|
export declare class RandomRoutingStrategy implements RoutingStrategy {
|
|
19
|
-
|
|
20
|
-
|
|
3
|
+
private gatewaysProvider?;
|
|
4
|
+
private logger;
|
|
5
|
+
constructor({ gatewaysProvider, logger, }?: {
|
|
6
|
+
gatewaysProvider?: GatewaysProvider;
|
|
7
|
+
logger?: Logger;
|
|
8
|
+
});
|
|
9
|
+
selectGateway({ gateways, }?: {
|
|
10
|
+
gateways?: URL[];
|
|
21
11
|
}): Promise<URL>;
|
|
22
12
|
}
|
|
23
13
|
//# sourceMappingURL=random.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"random.d.ts","sourceRoot":"","sources":["../../src/routing/random.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"random.d.ts","sourceRoot":"","sources":["../../src/routing/random.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG7E,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,MAAM,CAAS;gBAEX,EACV,gBAAgB,EAChB,MAAsB,GACvB,GAAE;QACD,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;QACpC,MAAM,CAAC,EAAE,MAAM,CAAC;KACZ;IAKA,aAAa,CAAC,EAClB,QAAQ,GACT,GAAE;QACD,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;KACb,GAAG,OAAO,CAAC,GAAG,CAAC;CAatB"}
|
package/dist/routing/random.js
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WayFinder
|
|
3
|
+
* Copyright (C) 2022-2025 Permanent Data Solutions, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { defaultLogger } from '../logger.js';
|
|
1
18
|
import { randomInt } from '../utils/random.js';
|
|
2
19
|
export class RandomRoutingStrategy {
|
|
3
|
-
|
|
4
|
-
|
|
20
|
+
gatewaysProvider;
|
|
21
|
+
logger;
|
|
22
|
+
constructor({ gatewaysProvider, logger = defaultLogger, } = {}) {
|
|
23
|
+
this.gatewaysProvider = gatewaysProvider;
|
|
24
|
+
this.logger = logger;
|
|
25
|
+
}
|
|
26
|
+
async selectGateway({ gateways, } = {}) {
|
|
27
|
+
const resolvedGateways = gateways ??
|
|
28
|
+
(this.gatewaysProvider ? await this.gatewaysProvider.getGateways() : []);
|
|
29
|
+
if (resolvedGateways.length === 0) {
|
|
30
|
+
this.logger.error('No gateways available');
|
|
5
31
|
throw new Error('No gateways available');
|
|
6
32
|
}
|
|
7
|
-
|
|
33
|
+
this.logger.debug('Selecting random gateway', {
|
|
34
|
+
gateways: resolvedGateways.map((g) => g.toString()),
|
|
35
|
+
});
|
|
36
|
+
return resolvedGateways[randomInt(0, resolvedGateways.length)];
|
|
8
37
|
}
|
|
9
38
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import type { Logger, RoutingStrategy } from '../types.js';
|
|
1
|
+
import type { GatewaysProvider, Logger, RoutingStrategy } from '../types.js';
|
|
2
2
|
export declare class RoundRobinRoutingStrategy implements RoutingStrategy {
|
|
3
3
|
readonly name = "round-robin";
|
|
4
4
|
private gateways;
|
|
5
5
|
private currentIndex;
|
|
6
6
|
private logger;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
private gatewaysProvider?;
|
|
8
|
+
constructor({ gateways, logger, gatewaysProvider, }?: {
|
|
9
|
+
gateways?: URL[];
|
|
9
10
|
logger?: Logger;
|
|
11
|
+
gatewaysProvider?: GatewaysProvider;
|
|
10
12
|
});
|
|
11
13
|
selectGateway(): Promise<URL>;
|
|
12
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"round-robin.d.ts","sourceRoot":"","sources":["../../src/routing/round-robin.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"round-robin.d.ts","sourceRoot":"","sources":["../../src/routing/round-robin.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7E,qBAAa,yBAA0B,YAAW,eAAe;IAC/D,SAAgB,IAAI,iBAAiB;IACrC,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAC,CAAmB;gBAEhC,EACV,QAAQ,EACR,MAAsB,EACtB,gBAAgB,GACjB,GAAE;QACD,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;KAChC;IAcA,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC;CAqBpC"}
|
|
@@ -20,14 +20,35 @@ export class RoundRobinRoutingStrategy {
|
|
|
20
20
|
gateways;
|
|
21
21
|
currentIndex;
|
|
22
22
|
logger;
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
gatewaysProvider;
|
|
24
|
+
constructor({ gateways, logger = defaultLogger, gatewaysProvider, } = {}) {
|
|
25
|
+
if (gateways && gatewaysProvider) {
|
|
26
|
+
throw new Error('Cannot provide both gateways and gatewaysProvider');
|
|
27
|
+
}
|
|
28
|
+
if (!gateways && !gatewaysProvider) {
|
|
29
|
+
throw new Error('Must provide either gateways or gatewaysProvider');
|
|
30
|
+
}
|
|
31
|
+
this.gateways = gateways || [];
|
|
25
32
|
this.currentIndex = 0;
|
|
26
33
|
this.logger = logger;
|
|
34
|
+
this.gatewaysProvider = gatewaysProvider;
|
|
27
35
|
}
|
|
28
36
|
async selectGateway() {
|
|
37
|
+
// Lazy load gateways from provider if not already loaded
|
|
38
|
+
if (this.gateways.length === 0 && this.gatewaysProvider) {
|
|
39
|
+
this.logger.debug('Loading gateways from provider');
|
|
40
|
+
this.gateways = await this.gatewaysProvider.getGateways();
|
|
41
|
+
this.currentIndex = 0;
|
|
42
|
+
}
|
|
43
|
+
if (this.gateways.length === 0) {
|
|
44
|
+
throw new Error('No gateways available');
|
|
45
|
+
}
|
|
29
46
|
const gateway = this.gateways[this.currentIndex];
|
|
30
|
-
this.logger.
|
|
47
|
+
this.logger.debug('Selecting gateway', {
|
|
48
|
+
gateway: gateway.toString(),
|
|
49
|
+
currentIndex: this.currentIndex,
|
|
50
|
+
totalGateways: this.gateways.length,
|
|
51
|
+
});
|
|
31
52
|
this.currentIndex = (this.currentIndex + 1) % this.gateways.length;
|
|
32
53
|
return gateway;
|
|
33
54
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -14,5 +14,5 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
export declare const WAYFINDER_CORE_VERSION = "v1.
|
|
17
|
+
export declare const WAYFINDER_CORE_VERSION = "v1.4.0-alpha.0";
|
|
18
18
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,sBAAsB,
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,sBAAsB,mBAAmB,CAAC"}
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ar.io/wayfinder-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0-alpha.0",
|
|
4
4
|
"description": "WayFinder core library for intelligently routing to optimal AR.IO gateways",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -57,6 +57,11 @@
|
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@ar.io/sdk": ">=3.12.0"
|
|
59
59
|
},
|
|
60
|
+
"peerDependenciesMeta": {
|
|
61
|
+
"@ar.io/sdk": {
|
|
62
|
+
"optional": true
|
|
63
|
+
}
|
|
64
|
+
},
|
|
60
65
|
"devDependencies": {
|
|
61
66
|
"@ar.io/sdk": "^3.13.0",
|
|
62
67
|
"@types/node": "^24.0.0",
|