@ar.io/sdk 3.12.0-beta.4 → 3.12.0-beta.6

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.
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TrustedGatewaysHashProvider = void 0;
4
+ const wayfinder_js_1 = require("../wayfinder.js");
4
5
  const arioGatewayHeaders = {
5
6
  digest: 'x-ar-io-digest',
6
7
  verified: 'x-ar-io-verified',
@@ -25,17 +26,32 @@ class TrustedGatewaysHashProvider {
25
26
  const hashResults = [];
26
27
  const gateways = await this.gatewaysProvider.getGateways();
27
28
  const hashes = await Promise.all(gateways.map(async (gateway) => {
28
- const response = await fetch(`${gateway.toString()}${txId}`, {
29
- method: 'HEAD',
30
- redirect: 'follow',
31
- });
32
- if (!response.ok) {
33
- // skip this gateway
34
- return undefined;
29
+ const sandbox = (0, wayfinder_js_1.sandboxFromId)(txId);
30
+ const urlWithSandbox = `${gateway.protocol}//${sandbox}.${gateway.hostname}/${txId}/`;
31
+ let txIdHash;
32
+ /**
33
+ * This is a problem because we're not able to verify the hash of the data item if the gateway doesn't have the data in its cache.
34
+ * We should add the ability to send a HEAD request to trigger a GET request to hydrate the cache on the trusted gateway via a header.
35
+ * For now, we'll just do a GET request to hydrate the cache if the HEAD request doesn't contain the digest.
36
+ */
37
+ for (const method of ['HEAD', 'GET']) {
38
+ const response = await fetch(urlWithSandbox, {
39
+ method,
40
+ redirect: 'follow',
41
+ mode: 'cors',
42
+ });
43
+ if (!response.ok) {
44
+ // skip this gateway if the request failed
45
+ break;
46
+ }
47
+ const fetchedTxIdHash = response.headers.get(arioGatewayHeaders.digest);
48
+ if (fetchedTxIdHash !== null && fetchedTxIdHash !== undefined) {
49
+ txIdHash = fetchedTxIdHash;
50
+ break;
51
+ }
35
52
  }
36
- const txIdHash = response.headers.get(arioGatewayHeaders.digest);
37
- if (txIdHash === null || txIdHash === undefined) {
38
- // skip this gateway
53
+ if (txIdHash === undefined) {
54
+ // skip this gateway if we didn't get a hash
39
55
  return undefined;
40
56
  }
41
57
  hashResults.push({
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Wayfinder = exports.createWayfinderClient = exports.WayfinderEmitter = exports.resolveWayfinderUrl = exports.txIdRegex = exports.arnsRegex = void 0;
7
7
  exports.tapAndVerifyStream = tapAndVerifyStream;
8
+ exports.sandboxFromId = sandboxFromId;
8
9
  /**
9
10
  * Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
10
11
  *
@@ -22,6 +23,7 @@ exports.tapAndVerifyStream = tapAndVerifyStream;
22
23
  */
23
24
  const node_events_1 = __importDefault(require("node:events"));
24
25
  const node_stream_1 = require("node:stream");
26
+ const rfc4648_1 = require("rfc4648");
25
27
  const io_js_1 = require("../io.js");
26
28
  const logger_js_1 = require("../logger.js");
27
29
  const network_js_1 = require("./gateways/network.js");
@@ -57,7 +59,8 @@ const resolveWayfinderUrl = ({ originalUrl, selectedGateway, logger, }) => {
57
59
  const [firstPart, ...rest] = path.split('/');
58
60
  // TODO: this breaks 43 character named arns names - we should check a a local name cache list before resolving raw transaction ids
59
61
  if (exports.txIdRegex.test(firstPart)) {
60
- return new URL(`${firstPart}${rest.length > 0 ? '/' + rest.join('/') : ''}`, selectedGateway);
62
+ const sandbox = sandboxFromId(firstPart);
63
+ return new URL(`${firstPart}${rest.length > 0 ? '/' + rest.join('/') : ''}`, `${selectedGateway.protocol}//${sandbox}.${selectedGateway.hostname}`);
61
64
  }
62
65
  if (exports.arnsRegex.test(firstPart)) {
63
66
  // TODO: tests to ensure arns names support query params and paths
@@ -245,6 +248,14 @@ function tapAndVerifyStream({ originalStream, contentLength, verifyData, txId, e
245
248
  }
246
249
  throw new Error('Unsupported body type for cloning');
247
250
  }
251
+ /**
252
+ * Gets the sandbox hash for a given transaction id
253
+ */
254
+ function sandboxFromId(id) {
255
+ return rfc4648_1.base32
256
+ .stringify(Buffer.from(id, 'base64'), { pad: false })
257
+ .toLowerCase();
258
+ }
248
259
  /**
249
260
  * Creates a wrapped fetch function that supports ar:// protocol
250
261
  *
@@ -305,9 +316,11 @@ const createWayfinderClient = ({ resolveUrl, verifyData, selectGateway, emitter
305
316
  });
306
317
  // Make the request to the target gateway
307
318
  const response = await fetch(redirectUrl.toString(), {
308
- ...init,
309
319
  // follow redirects as gateways use sandboxing on /txId requests
310
320
  redirect: 'follow',
321
+ mode: 'cors',
322
+ // allow requestor to override and any additional request configuration
323
+ ...init,
311
324
  });
312
325
  // TODO: update any caching we use for the request and gateway response
313
326
  logger?.debug(`Successfully routed request to gateway`, {
@@ -17,4 +17,4 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.version = void 0;
19
19
  // AUTOMATICALLY GENERATED FILE - DO NOT TOUCH
20
- exports.version = '3.12.0-beta.4';
20
+ exports.version = '3.12.0-beta.6';
@@ -1,3 +1,4 @@
1
+ import { sandboxFromId } from '../wayfinder.js';
1
2
  const arioGatewayHeaders = {
2
3
  digest: 'x-ar-io-digest',
3
4
  verified: 'x-ar-io-verified',
@@ -22,17 +23,32 @@ export class TrustedGatewaysHashProvider {
22
23
  const hashResults = [];
23
24
  const gateways = await this.gatewaysProvider.getGateways();
24
25
  const hashes = await Promise.all(gateways.map(async (gateway) => {
25
- const response = await fetch(`${gateway.toString()}${txId}`, {
26
- method: 'HEAD',
27
- redirect: 'follow',
28
- });
29
- if (!response.ok) {
30
- // skip this gateway
31
- return undefined;
26
+ const sandbox = sandboxFromId(txId);
27
+ const urlWithSandbox = `${gateway.protocol}//${sandbox}.${gateway.hostname}/${txId}/`;
28
+ let txIdHash;
29
+ /**
30
+ * This is a problem because we're not able to verify the hash of the data item if the gateway doesn't have the data in its cache.
31
+ * We should add the ability to send a HEAD request to trigger a GET request to hydrate the cache on the trusted gateway via a header.
32
+ * For now, we'll just do a GET request to hydrate the cache if the HEAD request doesn't contain the digest.
33
+ */
34
+ for (const method of ['HEAD', 'GET']) {
35
+ const response = await fetch(urlWithSandbox, {
36
+ method,
37
+ redirect: 'follow',
38
+ mode: 'cors',
39
+ });
40
+ if (!response.ok) {
41
+ // skip this gateway if the request failed
42
+ break;
43
+ }
44
+ const fetchedTxIdHash = response.headers.get(arioGatewayHeaders.digest);
45
+ if (fetchedTxIdHash !== null && fetchedTxIdHash !== undefined) {
46
+ txIdHash = fetchedTxIdHash;
47
+ break;
48
+ }
32
49
  }
33
- const txIdHash = response.headers.get(arioGatewayHeaders.digest);
34
- if (txIdHash === null || txIdHash === undefined) {
35
- // skip this gateway
50
+ if (txIdHash === undefined) {
51
+ // skip this gateway if we didn't get a hash
36
52
  return undefined;
37
53
  }
38
54
  hashResults.push({
@@ -15,6 +15,7 @@
15
15
  */
16
16
  import EventEmitter from 'node:events';
17
17
  import { PassThrough, Readable } from 'node:stream';
18
+ import { base32 } from 'rfc4648';
18
19
  import { ARIO } from '../io.js';
19
20
  import { Logger } from '../logger.js';
20
21
  import { NetworkGatewaysProvider } from './gateways/network.js';
@@ -50,7 +51,8 @@ export const resolveWayfinderUrl = ({ originalUrl, selectedGateway, logger, }) =
50
51
  const [firstPart, ...rest] = path.split('/');
51
52
  // TODO: this breaks 43 character named arns names - we should check a a local name cache list before resolving raw transaction ids
52
53
  if (txIdRegex.test(firstPart)) {
53
- return new URL(`${firstPart}${rest.length > 0 ? '/' + rest.join('/') : ''}`, selectedGateway);
54
+ const sandbox = sandboxFromId(firstPart);
55
+ return new URL(`${firstPart}${rest.length > 0 ? '/' + rest.join('/') : ''}`, `${selectedGateway.protocol}//${sandbox}.${selectedGateway.hostname}`);
54
56
  }
55
57
  if (arnsRegex.test(firstPart)) {
56
58
  // TODO: tests to ensure arns names support query params and paths
@@ -236,6 +238,14 @@ export function tapAndVerifyStream({ originalStream, contentLength, verifyData,
236
238
  }
237
239
  throw new Error('Unsupported body type for cloning');
238
240
  }
241
+ /**
242
+ * Gets the sandbox hash for a given transaction id
243
+ */
244
+ export function sandboxFromId(id) {
245
+ return base32
246
+ .stringify(Buffer.from(id, 'base64'), { pad: false })
247
+ .toLowerCase();
248
+ }
239
249
  /**
240
250
  * Creates a wrapped fetch function that supports ar:// protocol
241
251
  *
@@ -296,9 +306,11 @@ export const createWayfinderClient = ({ resolveUrl, verifyData, selectGateway, e
296
306
  });
297
307
  // Make the request to the target gateway
298
308
  const response = await fetch(redirectUrl.toString(), {
299
- ...init,
300
309
  // follow redirects as gateways use sandboxing on /txId requests
301
310
  redirect: 'follow',
311
+ mode: 'cors',
312
+ // allow requestor to override and any additional request configuration
313
+ ...init,
302
314
  });
303
315
  // TODO: update any caching we use for the request and gateway response
304
316
  logger?.debug(`Successfully routed request to gateway`, {
@@ -14,4 +14,4 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  // AUTOMATICALLY GENERATED FILE - DO NOT TOUCH
17
- export const version = '3.12.0-beta.4';
17
+ export const version = '3.12.0-beta.6';
@@ -98,6 +98,10 @@ export declare function tapAndVerifyStream<T extends Readable | ReadableStream>(
98
98
  emitter?: WayfinderEmitter;
99
99
  strict?: boolean;
100
100
  }): T extends Readable ? PassThrough : T;
101
+ /**
102
+ * Gets the sandbox hash for a given transaction id
103
+ */
104
+ export declare function sandboxFromId(id: string): string;
101
105
  /**
102
106
  * Creates a wrapped fetch function that supports ar:// protocol
103
107
  *
@@ -13,4 +13,4 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- export declare const version = "3.12.0-beta.3";
16
+ export declare const version = "3.12.0-beta.5";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ar.io/sdk",
3
- "version": "3.12.0-beta.4",
3
+ "version": "3.12.0-beta.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ar-io/ar-io-sdk.git"
@@ -136,6 +136,7 @@
136
136
  "eventemitter3": "^5.0.1",
137
137
  "plimit-lit": "^3.0.1",
138
138
  "prompts": "^2.4.2",
139
+ "rfc4648": "^1.5.4",
139
140
  "winston": "^3.13.0",
140
141
  "zod": "^3.23.8"
141
142
  },