@ar.io/wayfinder-core 0.0.3-alpha.2 → 0.0.3-alpha.3

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.
@@ -0,0 +1,30 @@
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 { DataClassifier } from '../../types/wayfinder.js';
18
+ import { Logger } from '../wayfinder.js';
19
+ export declare class GqlClassifier implements DataClassifier {
20
+ private readonly gqlEndpoint;
21
+ private readonly logger;
22
+ constructor({ gqlEndpoint, logger, }?: {
23
+ gqlEndpoint?: string;
24
+ logger?: Logger;
25
+ });
26
+ classify({ txId, }: {
27
+ txId: string;
28
+ }): Promise<'ans104' | 'transaction'>;
29
+ }
30
+ //# sourceMappingURL=gql-classifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gql-classifier.d.ts","sourceRoot":"","sources":["../../src/classifiers/gql-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAiB,MAAM,iBAAiB,CAAC;AAExD,qBAAa,aAAc,YAAW,cAAc;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAM;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,EACV,WAA0D,EAC1D,MAAsB,GACvB,GAAE;QACD,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;KACZ;IAKA,QAAQ,CAAC,EACb,IAAI,GACL,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,GAAG,aAAa,CAAC;CAuCxD"}
@@ -0,0 +1,45 @@
1
+ import { defaultLogger } from '../wayfinder.js';
2
+ export class GqlClassifier {
3
+ gqlEndpoint;
4
+ logger;
5
+ constructor({ gqlEndpoint = 'https://arweave-search.goldsky.com/graphql', logger = defaultLogger, } = {}) {
6
+ this.gqlEndpoint = new URL(gqlEndpoint);
7
+ this.logger = logger;
8
+ }
9
+ async classify({ txId, }) {
10
+ const response = await fetch(this.gqlEndpoint.toString(), {
11
+ method: 'POST',
12
+ headers: {
13
+ 'Content-Type': 'application/json',
14
+ },
15
+ body: JSON.stringify({
16
+ query: `
17
+ query GetTransaction($id: ID!) {
18
+ transactions(ids: [$id]) {
19
+ edges {
20
+ node {
21
+ bundledIn {
22
+ id
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ `,
29
+ variables: {
30
+ id: txId,
31
+ },
32
+ }),
33
+ });
34
+ if (!response.ok) {
35
+ this.logger.debug('Failed to fetch transaction from GraphQL', {
36
+ txId,
37
+ status: response.status,
38
+ });
39
+ return 'transaction';
40
+ }
41
+ const result = await response.json();
42
+ const bundledIn = result.data?.transaction?.bundledIn;
43
+ return bundledIn ? 'ans104' : 'transaction';
44
+ }
45
+ }
@@ -33,9 +33,6 @@ export declare class NetworkGatewaysProvider implements GatewaysProvider {
33
33
  filter?: (gateway: any) => boolean;
34
34
  logger?: Logger;
35
35
  });
36
- getGateways(_params?: {
37
- path?: string;
38
- subdomain?: string;
39
- }): Promise<URL[]>;
36
+ getGateways(): Promise<URL[]>;
40
37
  }
41
38
  //# sourceMappingURL=network.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/gateways/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAiB,MAAM,iBAAiB,CAAC;AAExD,qBAAa,uBAAwB,YAAW,gBAAgB;IAC9D,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,MAAM,CAA6D;IAC3E,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,YAAY,CAAC;QACnB,MAAM,CAAC,EAAE,qBAAqB,GAAG,eAAe,GAAG,gBAAgB,CAAC;QACpE,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,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;CA0DnF"}
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/gateways/network.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAiB,MAAM,iBAAiB,CAAC;AAExD,qBAAa,uBAAwB,YAAW,gBAAgB;IAC9D,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,MAAM,CAA6D;IAC3E,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,YAAY,CAAC;QACnB,MAAM,CAAC,EAAE,qBAAqB,GAAG,eAAe,GAAG,gBAAgB,CAAC;QACpE,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;CA0DpC"}
@@ -14,7 +14,7 @@ export class NetworkGatewaysProvider {
14
14
  this.filter = filter;
15
15
  this.logger = logger;
16
16
  }
17
- async getGateways(_params) {
17
+ async getGateways() {
18
18
  let cursor;
19
19
  let attempts = 0;
20
20
  const gateways = [];
@@ -1 +1 @@
1
- {"version":3,"file":"simple-cache.d.ts","sourceRoot":"","sources":["../../src/gateways/simple-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,MAAM,EAAiB,MAAM,iBAAiB,CAAC;AAExD,qBAAa,2BAA4B,YAAW,gBAAgB;IAClE,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,MAAM,CAAS;gBAEX,EACV,gBAAgB,EAChB,UAAoB,EAAE,SAAS;IAC/B,MAAsB,GACvB,EAAE;QACD,gBAAgB,EAAE,gBAAgB,CAAC;QACnC,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB;IAQK,WAAW,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;CAmClF"}
1
+ {"version":3,"file":"simple-cache.d.ts","sourceRoot":"","sources":["../../src/gateways/simple-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,MAAM,EAAiB,MAAM,iBAAiB,CAAC;AAExD,qBAAa,2BAA4B,YAAW,gBAAgB;IAClE,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,MAAM,CAAS;gBAEX,EACV,gBAAgB,EAChB,UAAoB,EAAE,SAAS;IAC/B,MAAsB,GACvB,EAAE;QACD,gBAAgB,EAAE,gBAAgB,CAAC;QACnC,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB;IAQK,WAAW,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CACxE,GAAG,EAAE,CACN;CAmCF"}
@@ -20,9 +20,6 @@ export declare class StaticGatewaysProvider implements GatewaysProvider {
20
20
  constructor({ gateways }: {
21
21
  gateways: string[];
22
22
  });
23
- getGateways(_params?: {
24
- path?: string;
25
- subdomain?: string;
26
- }): Promise<URL[]>;
23
+ getGateways(): Promise<URL[]>;
27
24
  }
28
25
  //# sourceMappingURL=static.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/gateways/static.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,sBAAuB,YAAW,gBAAgB;IAC7D,OAAO,CAAC,QAAQ,CAAQ;gBACZ,EAAE,QAAQ,EAAE,EAAE;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE;IAI1C,WAAW,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;CAGnF"}
1
+ {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../../src/gateways/static.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,sBAAuB,YAAW,gBAAgB;IAC7D,OAAO,CAAC,QAAQ,CAAQ;gBACZ,EAAE,QAAQ,EAAE,EAAE;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE;IAI1C,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;CAGpC"}
@@ -3,7 +3,7 @@ export class StaticGatewaysProvider {
3
3
  constructor({ gateways }) {
4
4
  this.gateways = gateways.map((g) => new URL(g));
5
5
  }
6
- async getGateways(_params) {
6
+ async getGateways() {
7
7
  return this.gateways;
8
8
  }
9
9
  }
package/dist/index.d.ts CHANGED
@@ -25,4 +25,5 @@ export * from './gateways/simple-cache.js';
25
25
  export * from './gateways/static.js';
26
26
  export * from './verification/data-root-verifier.js';
27
27
  export * from './verification/hash-verifier.js';
28
+ export * from './verification/signature-verifier.js';
28
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,gBAAgB,CAAC;AAG/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sCAAsC,CAAC;AAGrD,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AAGrC,cAAc,sCAAsC,CAAC;AACrD,cAAc,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,gBAAgB,CAAC;AAG/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sCAAsC,CAAC;AAGrD,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AAGrC,cAAc,sCAAsC,CAAC;AACrD,cAAc,iCAAiC,CAAC;AAChD,cAAc,sCAAsC,CAAC"}
package/dist/index.js CHANGED
@@ -28,4 +28,4 @@ export * from './gateways/static.js';
28
28
  // verification strategies
29
29
  export * from './verification/data-root-verifier.js';
30
30
  export * from './verification/hash-verifier.js';
31
- // TODO: signature verification
31
+ export * from './verification/signature-verifier.js';
@@ -61,7 +61,7 @@ export class FastestPingRoutingStrategy {
61
61
  throw new Error('Failed to ping gateway', {
62
62
  cause: {
63
63
  gateway: gateway.toString(),
64
- probePath: path,
64
+ path: path,
65
65
  status: response.status,
66
66
  },
67
67
  });
@@ -1 +1 @@
1
- {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,MAAM,EAAiB,MAAM,iBAAiB,CAAC;AAGxD,wBAAgB,eAAe,CAC7B,GAAG,EAAE,OAAO,GACX,GAAG,IAAI,aAAa,CAAC,UAAU,CAAC,CAQlC;AAED,wBAAuB,6BAA6B,CAClD,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GACjC,aAAa,CAAC,UAAU,CAAC,CAa3B;AAED,wBAAsB,sBAAsB,CAAC,EAC3C,MAAM,EACN,SAAqB,EACrB,MAAsB,GACvB,EAAE;IACD,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA2C9B"}
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,MAAM,EAAiB,MAAM,iBAAiB,CAAC;AAGxD,wBAAgB,eAAe,CAC7B,GAAG,EAAE,OAAO,GACX,GAAG,IAAI,aAAa,CAAC,UAAU,CAAC,CAQlC;AAED,wBAAuB,6BAA6B,CAClD,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GACjC,aAAa,CAAC,UAAU,CAAC,CAa3B;AAED,wBAAsB,sBAAsB,CAAC,EAC3C,MAAM,EACN,SAAoB,EACpB,MAAsB,GACvB,EAAE;IACD,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA2C9B"}
@@ -39,7 +39,7 @@ export async function* readableStreamToAsyncIterable(stream) {
39
39
  reader.releaseLock();
40
40
  }
41
41
  }
42
- export async function hashDataStreamToB64Url({ stream, algorithm = 'SHA-256', logger = defaultLogger, }) {
42
+ export async function hashDataStreamToB64Url({ stream, algorithm = 'sha256', logger = defaultLogger, }) {
43
43
  try {
44
44
  logger.debug('Starting to hash data stream', {
45
45
  algorithm,
@@ -1,4 +1,4 @@
1
- import { DataStream, VerificationStrategy } from '../../types/wayfinder.js';
1
+ import { DataClassifier, DataStream, VerificationStrategy } from '../../types/wayfinder.js';
2
2
  import { Logger } from '../wayfinder.js';
3
3
  export declare const convertDataStreamToDataRoot: ({ stream, }: {
4
4
  stream: DataStream;
@@ -7,10 +7,12 @@ export declare class DataRootVerificationStrategy implements VerificationStrateg
7
7
  private readonly trustedGateways;
8
8
  private readonly maxConcurrency;
9
9
  private readonly logger;
10
- constructor({ trustedGateways, maxConcurrency, logger, }: {
10
+ private readonly classifier;
11
+ constructor({ trustedGateways, maxConcurrency, logger, classifier, }: {
11
12
  trustedGateways: URL[];
12
13
  maxConcurrency?: number;
13
14
  logger?: Logger;
15
+ classifier?: DataClassifier;
14
16
  });
15
17
  /**
16
18
  * Get the data root for a given txId from all trusted gateways and ensure they all match.
@@ -1 +1 @@
1
- {"version":3,"file":"data-root-verifier.d.ts","sourceRoot":"","sources":["../../src/verification/data-root-verifier.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAM5E,OAAO,EAAE,MAAM,EAAiB,MAAM,iBAAiB,CAAC;AAExD,eAAO,MAAM,2BAA2B,GAAU,aAE/C;IACD,MAAM,EAAE,UAAU,CAAC;CACpB,KAAG,OAAO,CAAC,MAAM,CAwDjB,CAAC;AAEF,qBAAa,4BAA6B,YAAW,oBAAoB;IACvE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBACpB,EACV,eAAe,EACf,cAAkB,EAClB,MAAsB,GACvB,EAAE;QACD,eAAe,EAAE,GAAG,EAAE,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB;IAMD;;;;OAIG;IACG,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAuCxD,UAAU,CAAC,EACf,IAAI,EACJ,IAAI,GACL,EAAE;QACD,IAAI,EAAE,UAAU,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,IAAI,CAAC;CAelB"}
1
+ {"version":3,"file":"data-root-verifier.d.ts","sourceRoot":"","sources":["../../src/verification/data-root-verifier.ts"],"names":[],"mappings":"AA0BA,OAAO,EACL,cAAc,EACd,UAAU,EACV,oBAAoB,EACrB,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAAE,MAAM,EAAiB,MAAM,iBAAiB,CAAC;AAExD,eAAO,MAAM,2BAA2B,GAAU,aAE/C;IACD,MAAM,EAAE,UAAU,CAAC;CACpB,KAAG,OAAO,CAAC,MAAM,CAwDjB,CAAC;AAGF,qBAAa,4BAA6B,YAAW,oBAAoB;IACvE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiB;gBAChC,EACV,eAAe,EACf,cAAkB,EAClB,MAAsB,EACtB,UAA0C,GAC3C,EAAE;QACD,eAAe,EAAE,GAAG,EAAE,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,cAAc,CAAC;KAC7B;IAOD;;;;OAIG;IACG,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAuCxD,UAAU,CAAC,EACf,IAAI,EACJ,IAAI,GACL,EAAE;QACD,IAAI,EAAE,UAAU,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,IAAI,CAAC;CA0BlB"}
@@ -17,6 +17,7 @@
17
17
  import Arweave from 'arweave';
18
18
  import { MAX_CHUNK_SIZE, MIN_CHUNK_SIZE, buildLayers, generateLeaves, } from 'arweave/node/lib/merkle.js';
19
19
  import { pLimit } from 'plimit-lit';
20
+ import { GqlClassifier } from '../classifiers/gql-classifier.js';
20
21
  import { toB64Url } from '../utils/base64.js';
21
22
  import { isAsyncIterable, readableStreamToAsyncIterable, } from '../utils/hash.js';
22
23
  import { defaultLogger } from '../wayfinder.js';
@@ -64,14 +65,17 @@ export const convertDataStreamToDataRoot = async ({ stream, }) => {
64
65
  const root = await buildLayers(leaves);
65
66
  return toB64Url(new Uint8Array(root.id));
66
67
  };
68
+ // TODO: this is a TransactionDataRootVerificationStrategy, we will hold of on implementing Ans104DataRootVerificationStrategy for now
67
69
  export class DataRootVerificationStrategy {
68
70
  trustedGateways;
69
71
  maxConcurrency;
70
72
  logger;
71
- constructor({ trustedGateways, maxConcurrency = 1, logger = defaultLogger, }) {
73
+ classifier;
74
+ constructor({ trustedGateways, maxConcurrency = 1, logger = defaultLogger, classifier = new GqlClassifier({ logger }), }) {
72
75
  this.trustedGateways = trustedGateways;
73
76
  this.maxConcurrency = maxConcurrency;
74
77
  this.logger = logger;
78
+ this.classifier = classifier;
75
79
  }
76
80
  /**
77
81
  * Get the data root for a given txId from all trusted gateways and ensure they all match.
@@ -111,6 +115,13 @@ export class DataRootVerificationStrategy {
111
115
  return dataRoot;
112
116
  }
113
117
  async verifyData({ data, txId, }) {
118
+ // classify the data, if ans104 throw an error
119
+ const dataType = await this.classifier.classify({ txId });
120
+ if (dataType === 'ans104') {
121
+ throw new Error('ANS-104 data is not supported for data root verification', {
122
+ cause: { txId },
123
+ });
124
+ }
114
125
  const [computedDataRoot, trustedDataRoot] = await Promise.all([
115
126
  convertDataStreamToDataRoot({
116
127
  stream: data,
@@ -0,0 +1,117 @@
1
+ import { DataClassifier, DataStream, VerificationStrategy } from '../../types/wayfinder.js';
2
+ import { Logger } from '../wayfinder.js';
3
+ /**
4
+ * Implementation of DataVerificationStrategy that verifies data item signatures
5
+ * using trusted gateways to provide the metadata needed for verification.
6
+ */
7
+ export declare class Ans104SignatureVerificationStrategy implements VerificationStrategy {
8
+ private readonly trustedGateways;
9
+ private readonly maxConcurrency;
10
+ private readonly logger;
11
+ constructor({ trustedGateways, maxConcurrency, logger, }: {
12
+ trustedGateways: URL[];
13
+ maxConcurrency?: number;
14
+ logger?: Logger;
15
+ });
16
+ /**
17
+ * Gets data item information from trusted gateways
18
+ *
19
+ * @param txId - The transaction ID to get information for
20
+ * @returns Object containing offsets and root transaction ID
21
+ */
22
+ private getDataItemAttributes;
23
+ /**
24
+ * Fetches just the bytes header data of a data item from a trusted gateway needed for signature verification.
25
+ *
26
+ * @param txId - The transaction ID to get signature data for
27
+ * @returns The bytes containing the data item up to the data section
28
+ */
29
+ getSignatureData({ txId, }: {
30
+ txId: string;
31
+ }): Promise<{
32
+ signatureType: number;
33
+ signature: Uint8Array;
34
+ owner: Uint8Array;
35
+ target: Uint8Array;
36
+ anchor: Uint8Array;
37
+ tags: Uint8Array;
38
+ }>;
39
+ /**
40
+ * Verifies the signature of a data item using trusted gateways to get the signature data
41
+ * and then verifying it against the data payload.
42
+ *
43
+ * This implementation follows the ANS-104 standard for verifying data item signatures:
44
+ * 1. Get the signature data from the trusted gateway
45
+ * 2. Parse the signature components (owner, signature type, tags, etc.)
46
+ * 3. Calculate the deep hash of all components and the data
47
+ * 4. Verify the signature against the deep hash
48
+ *
49
+ * @param data - The data stream to verify
50
+ * @param txId - The transaction ID of the data
51
+ */
52
+ verifyData({ data, txId, }: {
53
+ data: DataStream;
54
+ txId: string;
55
+ }): Promise<void>;
56
+ }
57
+ /**
58
+ * Implementation of SignatureDataProvider that fetches signature data directly
59
+ * from a trusted gateway's /tx/<tx-id>/signature endpoint.
60
+ */
61
+ export declare class TransactionSignatureVerificationStrategy implements VerificationStrategy {
62
+ private readonly trustedGateways;
63
+ private readonly logger;
64
+ constructor({ trustedGateways, logger, }: {
65
+ trustedGateways: URL[];
66
+ maxConcurrency?: number;
67
+ logger?: Logger;
68
+ });
69
+ /**
70
+ * Fetches signature data directly from a trusted gateway's /tx/<tx-id>/signature endpoint.
71
+ *
72
+ * @param txId - The transaction ID to get signature data for
73
+ * @returns The signature data as a Uint8Array
74
+ */
75
+ getSignatureData({ txId, }: {
76
+ txId: string;
77
+ }): Promise<{
78
+ format: number;
79
+ owner: string;
80
+ target: string;
81
+ anchor: string;
82
+ quantity: string;
83
+ reward: string;
84
+ dataRoot: string;
85
+ dataSize: number;
86
+ lastTx: string;
87
+ tags: {
88
+ name: string;
89
+ value: string;
90
+ }[];
91
+ signature: string;
92
+ }>;
93
+ verifyData({ data, txId, }: {
94
+ data: DataStream;
95
+ txId: string;
96
+ }): Promise<void>;
97
+ }
98
+ export declare const SignatureVerificationStrategies: {
99
+ ans104: typeof Ans104SignatureVerificationStrategy;
100
+ transaction: typeof TransactionSignatureVerificationStrategy;
101
+ };
102
+ export declare class SignatureVerificationStrategy {
103
+ private readonly ans104;
104
+ private readonly transaction;
105
+ private readonly classifier;
106
+ constructor({ trustedGateways, maxConcurrency, logger, classifier, }: {
107
+ trustedGateways: URL[];
108
+ maxConcurrency?: number;
109
+ logger?: Logger;
110
+ classifier?: DataClassifier;
111
+ });
112
+ verifyData({ data, txId, }: {
113
+ data: DataStream;
114
+ txId: string;
115
+ }): Promise<void>;
116
+ }
117
+ //# sourceMappingURL=signature-verifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature-verifier.d.ts","sourceRoot":"","sources":["../../src/verification/signature-verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,362 @@
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 { Arweave, DataItem, deepHash, indexToType, stringToBuffer, } from '@dha-team/arbundles';
18
+ import { pLimit } from 'plimit-lit';
19
+ import { GqlClassifier } from '../classifiers/gql-classifier.js';
20
+ import { arioGatewayHeaders } from '../utils/ario.js';
21
+ import { fromB64Url } from '../utils/base64.js';
22
+ import { isAsyncIterable, readableStreamToAsyncIterable, } from '../utils/hash.js';
23
+ import { defaultLogger } from '../wayfinder.js';
24
+ import { convertDataStreamToDataRoot } from './data-root-verifier.js';
25
+ /**
26
+ * Implementation of DataVerificationStrategy that verifies data item signatures
27
+ * using trusted gateways to provide the metadata needed for verification.
28
+ */
29
+ export class Ans104SignatureVerificationStrategy {
30
+ trustedGateways;
31
+ maxConcurrency;
32
+ logger;
33
+ constructor({ trustedGateways, maxConcurrency = 1, logger = defaultLogger, }) {
34
+ this.trustedGateways = trustedGateways;
35
+ this.maxConcurrency = maxConcurrency;
36
+ this.logger = logger;
37
+ }
38
+ /**
39
+ * Gets data item information from trusted gateways
40
+ *
41
+ * @param txId - The transaction ID to get information for
42
+ * @returns Object containing offsets and root transaction ID
43
+ */
44
+ async getDataItemAttributes(txId) {
45
+ // Try each gateway until we get the information we need
46
+ const throttle = pLimit(this.maxConcurrency);
47
+ const dataItemAttributesPromises = this.trustedGateways.map(async (gateway) => {
48
+ return throttle(async () => {
49
+ // TODO: add sandbox support to the URL - useful to test against localhost with it disabled
50
+ // const sandbox = sandboxFromId(txId);
51
+ const url = `${gateway.protocol}//${gateway.hostname}:${gateway.port}/${txId}`;
52
+ // Make a HEAD request to get headers without fetching the full data
53
+ const response = await fetch(url, {
54
+ method: 'HEAD',
55
+ redirect: 'follow',
56
+ mode: 'cors',
57
+ headers: {
58
+ 'Cache-Control': 'no-cache',
59
+ },
60
+ });
61
+ if (!response.ok) {
62
+ throw new Error('Failed to fetch data item info from trusted gateway', {
63
+ cause: {
64
+ txId,
65
+ gateway: gateway.toString(),
66
+ },
67
+ });
68
+ }
69
+ const dataItemOffset = response.headers.get(arioGatewayHeaders.dataItemOffset);
70
+ const dataItemDataOffset = response.headers.get(arioGatewayHeaders.dataItemDataOffset);
71
+ const rootTransactionId = response.headers.get(arioGatewayHeaders.rootTransactionId);
72
+ const dataItemSize = response.headers.get(arioGatewayHeaders.dataItemSize);
73
+ // if any are undefined, throw an error
74
+ if (dataItemOffset &&
75
+ dataItemDataOffset &&
76
+ rootTransactionId &&
77
+ dataItemSize) {
78
+ throttle.clearQueue();
79
+ return {
80
+ gateway,
81
+ dataItemOffset: parseInt(dataItemOffset, 10),
82
+ dataItemDataOffset: parseInt(dataItemDataOffset, 10),
83
+ rootTransactionId,
84
+ dataItemSize: parseInt(dataItemSize, 10),
85
+ };
86
+ }
87
+ // if we get here, we didn't get the information we need from this gateway
88
+ throw new Error('Missing data item attributes from trusted gateway', {
89
+ cause: {
90
+ txId,
91
+ gateway: gateway.toString(),
92
+ dataItemOffset,
93
+ dataItemDataOffset,
94
+ rootTransactionId,
95
+ dataItemSize,
96
+ },
97
+ });
98
+ });
99
+ });
100
+ const { gateway, dataItemOffset, dataItemDataOffset, rootTransactionId, dataItemSize, } = await Promise.any(dataItemAttributesPromises);
101
+ this.logger.debug('Successfully fetched data item attributes for txId', {
102
+ txId,
103
+ dataItemOffset,
104
+ dataItemDataOffset,
105
+ rootTransactionId,
106
+ dataItemSize,
107
+ gateway: gateway.toString(),
108
+ });
109
+ return {
110
+ dataItemOffset,
111
+ dataItemDataOffset,
112
+ rootTransactionId,
113
+ dataItemSize,
114
+ };
115
+ }
116
+ /**
117
+ * Fetches just the bytes header data of a data item from a trusted gateway needed for signature verification.
118
+ *
119
+ * @param txId - The transaction ID to get signature data for
120
+ * @returns The bytes containing the data item up to the data section
121
+ */
122
+ async getSignatureData({ txId, }) {
123
+ const { rootTransactionId, dataItemOffset, dataItemDataOffset } = await this.getDataItemAttributes(txId);
124
+ // this byte range is the header data of the data item within it's parent transaction, containing all the header data needed for signature verification
125
+ const rangeStart = dataItemOffset;
126
+ const rangeEnd = dataItemDataOffset - 1;
127
+ // TODO: we are fetching data here via range request - we may not want to do this concurrently and instead shuffle gateways before iterating through each
128
+ for (const gateway of this.trustedGateways) {
129
+ try {
130
+ const url = `${gateway.toString()}${rootTransactionId}`;
131
+ const response = await fetch(url, {
132
+ method: 'GET',
133
+ redirect: 'follow',
134
+ mode: 'cors',
135
+ headers: {
136
+ Range: `bytes=${rangeStart}-${rangeEnd}`,
137
+ 'Cache-Control': 'no-cache',
138
+ },
139
+ });
140
+ if (!response.ok || response.body === null) {
141
+ continue;
142
+ }
143
+ // create the data item object from just the headers, so we can get the components easily
144
+ // this is somewhat of a hack as we are not including the data when creating the DataItem object
145
+ const trustedDataItemHeaderBytes = Buffer.from(await response.arrayBuffer());
146
+ const dataItem = new DataItem(trustedDataItemHeaderBytes);
147
+ // first verify the data item id matches the txId before we do any other verification
148
+ const dataItemId = await dataItem.id;
149
+ if (dataItemId !== txId) {
150
+ throw new Error('Data item ID does not match txId', {
151
+ cause: { dataItemId, txId },
152
+ });
153
+ }
154
+ // now get the components needed for verification from the DataItem
155
+ const signatureType = dataItem.signatureType;
156
+ const signature = dataItem.rawSignature;
157
+ const owner = dataItem.rawOwner;
158
+ const target = dataItem.rawTarget;
159
+ const anchor = dataItem.rawAnchor;
160
+ const tags = dataItem.rawTags;
161
+ return {
162
+ signatureType,
163
+ signature,
164
+ owner,
165
+ target,
166
+ anchor,
167
+ tags,
168
+ };
169
+ }
170
+ catch (error) {
171
+ this.logger.debug('Failed to fetch data item signature bytes', {
172
+ error: error.message,
173
+ stack: error.stack,
174
+ txId,
175
+ });
176
+ }
177
+ }
178
+ throw new Error('Failed to fetch data item signature bytes', {
179
+ cause: { txId, rootTransactionId, dataItemOffset, dataItemDataOffset },
180
+ });
181
+ }
182
+ /**
183
+ * Verifies the signature of a data item using trusted gateways to get the signature data
184
+ * and then verifying it against the data payload.
185
+ *
186
+ * This implementation follows the ANS-104 standard for verifying data item signatures:
187
+ * 1. Get the signature data from the trusted gateway
188
+ * 2. Parse the signature components (owner, signature type, tags, etc.)
189
+ * 3. Calculate the deep hash of all components and the data
190
+ * 4. Verify the signature against the deep hash
191
+ *
192
+ * @param data - The data stream to verify
193
+ * @param txId - The transaction ID of the data
194
+ */
195
+ async verifyData({ data, txId, }) {
196
+ // fetch signature data from trusted gateway
197
+ const trustedSignatureData = await this.getSignatureData({ txId });
198
+ if (!DataItem.isDataItem(trustedSignatureData)) {
199
+ throw new Error('TxId is not a data item', {
200
+ cause: { txId },
201
+ });
202
+ }
203
+ // ensure data is in the right format for verification
204
+ const asyncIterable = isAsyncIterable(data)
205
+ ? data
206
+ : readableStreamToAsyncIterable(data);
207
+ const { signatureType, signature, owner, target, anchor, tags } = trustedSignatureData;
208
+ // calculate the deep hash of all components including the data stream
209
+ // this follows the arbundles DataItem.verify() approach but prevents loading the entire data stream into memory
210
+ const signatureData = await deepHash([
211
+ stringToBuffer('dataitem'),
212
+ stringToBuffer('1'),
213
+ stringToBuffer(`${signatureType}`),
214
+ new Uint8Array(owner),
215
+ new Uint8Array(target),
216
+ new Uint8Array(anchor),
217
+ new Uint8Array(tags),
218
+ asyncIterable,
219
+ ]);
220
+ const signer = indexToType[signatureType];
221
+ const isValid = await signer.verify(new Uint8Array(owner), signatureData, new Uint8Array(signature));
222
+ if (!isValid) {
223
+ throw new Error('Data item signature verification failed', {
224
+ cause: { txId },
225
+ });
226
+ }
227
+ }
228
+ }
229
+ /**
230
+ * Implementation of SignatureDataProvider that fetches signature data directly
231
+ * from a trusted gateway's /tx/<tx-id>/signature endpoint.
232
+ */
233
+ export class TransactionSignatureVerificationStrategy {
234
+ trustedGateways;
235
+ logger;
236
+ constructor({ trustedGateways, logger = defaultLogger, }) {
237
+ this.trustedGateways = trustedGateways;
238
+ this.logger = logger;
239
+ }
240
+ /**
241
+ * Fetches signature data directly from a trusted gateway's /tx/<tx-id>/signature endpoint.
242
+ *
243
+ * @param txId - The transaction ID to get signature data for
244
+ * @returns The signature data as a Uint8Array
245
+ */
246
+ async getSignatureData({ txId, }) {
247
+ this.logger.debug('Getting signature data for txId', {
248
+ txId,
249
+ trustedGateways: this.trustedGateways,
250
+ });
251
+ // TODO: shuffle gateways before iterating through each and potentially allow for concurrent requests
252
+ for (const gateway of this.trustedGateways) {
253
+ try {
254
+ const url = `${gateway.toString()}tx/${txId}`;
255
+ const response = await fetch(url, {
256
+ method: 'GET',
257
+ redirect: 'follow',
258
+ mode: 'cors',
259
+ headers: {
260
+ 'Cache-Control': 'no-cache',
261
+ 'Content-Type': 'application/json',
262
+ },
263
+ });
264
+ if (!response.ok) {
265
+ throw new Error('Failed to fetch signature data from trusted gateway', {
266
+ cause: { txId, gateway: gateway.toString() },
267
+ });
268
+ }
269
+ const tx = await response.json();
270
+ return {
271
+ format: tx.format,
272
+ owner: tx.owner,
273
+ target: tx.target,
274
+ anchor: tx.anchor,
275
+ quantity: tx.quantity,
276
+ reward: tx.reward,
277
+ dataRoot: tx.data_root,
278
+ dataSize: tx.data_size,
279
+ lastTx: tx.last_tx,
280
+ tags: tx.tags,
281
+ signature: tx.signature,
282
+ };
283
+ }
284
+ catch (error) {
285
+ this.logger.debug('Error fetching signature data', {
286
+ error: error.message,
287
+ stack: error.stack,
288
+ txId,
289
+ gateway: gateway.toString(),
290
+ });
291
+ }
292
+ }
293
+ throw new Error('Failed to fetch signature data from any trusted gateway', {
294
+ cause: { txId },
295
+ });
296
+ }
297
+ async verifyData({ data, txId, }) {
298
+ const { format, owner, target, quantity, reward, dataSize, lastTx, tags, signature, } = await this.getSignatureData({ txId });
299
+ const tagList = tags.map((tag) => [
300
+ fromB64Url(tag.name),
301
+ fromB64Url(tag.value),
302
+ ]);
303
+ // use the provided data stream to compute the data root for the signature data
304
+ const computedDataRoot = await convertDataStreamToDataRoot({
305
+ stream: data,
306
+ });
307
+ // compute the signature data using the computed data root and retrieved signature data
308
+ const signatureData = await deepHash([
309
+ stringToBuffer(format.toString()),
310
+ fromB64Url(owner),
311
+ fromB64Url(target),
312
+ stringToBuffer(quantity),
313
+ stringToBuffer(reward),
314
+ fromB64Url(lastTx),
315
+ tagList,
316
+ stringToBuffer(dataSize.toString()),
317
+ fromB64Url(computedDataRoot),
318
+ ]);
319
+ // verify the signature using the computed signature data and the computed signature data
320
+ const isValid = await Arweave.crypto.verify(owner, signatureData, fromB64Url(signature));
321
+ if (!isValid) {
322
+ throw new Error('Transaction signature verification failed', {
323
+ cause: { txId },
324
+ });
325
+ }
326
+ }
327
+ }
328
+ export const SignatureVerificationStrategies = {
329
+ ans104: Ans104SignatureVerificationStrategy,
330
+ transaction: TransactionSignatureVerificationStrategy,
331
+ // TODO: ans102
332
+ };
333
+ export class SignatureVerificationStrategy {
334
+ ans104;
335
+ transaction;
336
+ classifier;
337
+ constructor({ trustedGateways, maxConcurrency = 1, logger = defaultLogger, classifier = new GqlClassifier({ logger }), }) {
338
+ this.ans104 = new Ans104SignatureVerificationStrategy({
339
+ trustedGateways,
340
+ maxConcurrency,
341
+ logger,
342
+ });
343
+ this.transaction = new TransactionSignatureVerificationStrategy({
344
+ trustedGateways,
345
+ logger,
346
+ });
347
+ this.classifier = classifier;
348
+ }
349
+ async verifyData({ data, txId, }) {
350
+ const dataType = await this.classifier.classify({ txId });
351
+ switch (dataType) {
352
+ case 'ans104':
353
+ return this.ans104.verifyData({ data, txId });
354
+ case 'transaction':
355
+ return this.transaction.verifyData({ data, txId });
356
+ default:
357
+ throw new Error('Unknown data type', {
358
+ cause: { dataType },
359
+ });
360
+ }
361
+ }
362
+ }
@@ -109,8 +109,9 @@ export declare function sandboxFromId(id: string): string;
109
109
  * @param resolveUrl - the function to construct the redirect url for ar:// requests
110
110
  * @returns a wrapped fetch function that supports ar:// protocol and always returns Response
111
111
  */
112
- export declare const createWayfinderClient: ({ resolveUrl, verifyData, selectGateway, emitter, logger, strict, }: {
113
- selectGateway: () => Promise<URL>;
112
+ export declare const createWayfinderClient: ({ getGateways, resolveUrl, verifyData, selectGateway, emitter, logger, strict, }: {
113
+ getGateways: GatewaysProvider["getGateways"];
114
+ selectGateway: RoutingStrategy["selectGateway"];
114
115
  resolveUrl: (params: {
115
116
  originalUrl: string;
116
117
  selectedGateway: URL;
@@ -1 +1 @@
1
- {"version":3,"file":"wayfinder.d.ts","sourceRoot":"","sources":["../src/wayfinder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wayfinder.d.ts","sourceRoot":"","sources":["../src/wayfinder.ts"],"names":[],"mappings":"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"}
package/dist/wayfinder.js CHANGED
@@ -185,18 +185,18 @@ export function sandboxFromId(id) {
185
185
  * @param resolveUrl - the function to construct the redirect url for ar:// requests
186
186
  * @returns a wrapped fetch function that supports ar:// protocol and always returns Response
187
187
  */
188
- export const createWayfinderClient = ({ resolveUrl, verifyData, selectGateway, emitter = new WayfinderEmitter(), logger = defaultLogger, strict = false, }) => {
188
+ export const createWayfinderClient = ({ getGateways, resolveUrl, verifyData, selectGateway, emitter = new WayfinderEmitter(), logger = defaultLogger, strict = false, }) => {
189
189
  return async (input, init) => {
190
- const url = input instanceof URL ? input.toString() : input.toString();
191
- if (typeof url !== 'string') {
190
+ if (!(input instanceof URL)) {
192
191
  logger?.debug('URL is not a string, skipping routing', {
193
- url,
192
+ input,
194
193
  });
195
194
  emitter?.emit('routing-skipped', {
196
- originalUrl: JSON.stringify(url),
195
+ originalUrl: JSON.stringify(input),
197
196
  });
198
- return fetch(url, init);
197
+ return fetch(input, init);
199
198
  }
199
+ const url = input.toString();
200
200
  emitter?.emit('routing-started', {
201
201
  originalUrl: url,
202
202
  });
@@ -205,7 +205,11 @@ export const createWayfinderClient = ({ resolveUrl, verifyData, selectGateway, e
205
205
  for (let i = 0; i < maxRetries; i++) {
206
206
  try {
207
207
  // select the target gateway
208
- const selectedGateway = await selectGateway();
208
+ const selectedGateway = await selectGateway({
209
+ gateways: await getGateways(),
210
+ path: input.pathname.split('/')[1],
211
+ subdomain: input.hostname.split('.')[0],
212
+ });
209
213
  logger?.debug('Selected gateway', {
210
214
  originalUrl: url,
211
215
  selectedGateway: selectedGateway.toString(),
@@ -477,11 +481,8 @@ export class Wayfinder {
477
481
  };
478
482
  // create a wayfinder client with the routing strategy and gateways provider
479
483
  this.request = createWayfinderClient({
480
- selectGateway: async () => {
481
- return this.routingStrategy.selectGateway({
482
- gateways: await this.gatewaysProvider.getGateways(),
483
- });
484
- },
484
+ getGateways: this.gatewaysProvider.getGateways.bind(this.gatewaysProvider),
485
+ selectGateway: this.routingStrategy.selectGateway.bind(this.routingStrategy),
485
486
  resolveUrl: resolveWayfinderUrl,
486
487
  verifyData: this.verifyData,
487
488
  emitter: this.emitter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ar.io/wayfinder-core",
3
- "version": "0.0.3-alpha.2",
3
+ "version": "0.0.3-alpha.3",
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",