@ar.io/sdk 3.11.0-alpha.9 → 3.11.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/bundles/web.bundle.min.js +106 -106
  2. package/lib/cjs/cli/utils.js +4 -1
  3. package/lib/cjs/common/contracts/ao-process.js +2 -1
  4. package/lib/cjs/common/wayfinder/{gateways.js → gateways/network.js} +3 -41
  5. package/lib/cjs/common/wayfinder/gateways/simple-cache.js +35 -0
  6. package/lib/cjs/common/wayfinder/gateways/static.js +13 -0
  7. package/lib/cjs/common/wayfinder/index.js +11 -8
  8. package/lib/cjs/common/wayfinder/routing/strategies/ping.js +72 -0
  9. package/lib/cjs/common/wayfinder/routing/strategies/ping.test.js +156 -0
  10. package/lib/cjs/common/wayfinder/routing/strategies/random.js +13 -0
  11. package/lib/cjs/common/wayfinder/routing/strategies/random.test.js +68 -0
  12. package/lib/cjs/common/wayfinder/routing/strategies/round-robin.js +42 -0
  13. package/lib/cjs/common/wayfinder/routing/strategies/round-robin.test.js +78 -0
  14. package/lib/cjs/common/wayfinder/routing/strategies/static.js +29 -0
  15. package/lib/cjs/common/wayfinder/routing/strategies/static.test.js +40 -0
  16. package/lib/cjs/common/wayfinder/verification/{data-root-verifier.js → strategies/data-root-verifier.js} +4 -4
  17. package/lib/cjs/common/wayfinder/verification/{hash-verifier.js → strategies/hash-verifier.js} +4 -4
  18. package/lib/cjs/common/wayfinder/{gateways/trusted-gateways.js → verification/trusted.js} +1 -1
  19. package/lib/cjs/common/wayfinder/wayfinder.js +397 -257
  20. package/lib/cjs/common/wayfinder/wayfinder.test.js +227 -208
  21. package/lib/cjs/version.js +1 -1
  22. package/lib/esm/cli/utils.js +4 -1
  23. package/lib/esm/common/contracts/ao-process.js +2 -1
  24. package/lib/esm/common/wayfinder/{gateways.js → gateways/network.js} +2 -38
  25. package/lib/esm/common/wayfinder/gateways/simple-cache.js +31 -0
  26. package/lib/esm/common/wayfinder/gateways/static.js +9 -0
  27. package/lib/esm/common/wayfinder/index.js +11 -8
  28. package/lib/esm/common/wayfinder/routing/strategies/ping.js +68 -0
  29. package/lib/esm/common/wayfinder/routing/strategies/ping.test.js +151 -0
  30. package/lib/esm/common/wayfinder/routing/strategies/random.js +9 -0
  31. package/lib/esm/common/wayfinder/routing/strategies/random.test.js +63 -0
  32. package/lib/esm/common/wayfinder/routing/strategies/round-robin.js +38 -0
  33. package/lib/esm/common/wayfinder/routing/strategies/round-robin.test.js +73 -0
  34. package/lib/esm/common/wayfinder/routing/strategies/static.js +25 -0
  35. package/lib/esm/common/wayfinder/routing/strategies/static.test.js +35 -0
  36. package/lib/esm/common/wayfinder/verification/{data-root-verifier.js → strategies/data-root-verifier.js} +2 -2
  37. package/lib/esm/common/wayfinder/verification/{hash-verifier.js → strategies/hash-verifier.js} +2 -2
  38. package/lib/esm/common/wayfinder/{gateways/trusted-gateways.js → verification/trusted.js} +1 -1
  39. package/lib/esm/common/wayfinder/wayfinder.js +395 -255
  40. package/lib/esm/common/wayfinder/wayfinder.test.js +227 -208
  41. package/lib/esm/version.js +1 -1
  42. package/lib/types/common/wayfinder/{gateways.d.ts → gateways/network.d.ts} +3 -23
  43. package/lib/types/common/wayfinder/{routers/random.d.ts → gateways/simple-cache.d.ts} +12 -8
  44. package/lib/types/common/wayfinder/{routers → gateways}/static.d.ts +6 -7
  45. package/lib/types/common/wayfinder/index.d.ts +10 -7
  46. package/lib/types/common/wayfinder/{routers/simple-cache.d.ts → routing/strategies/ping.d.ts} +10 -11
  47. package/lib/types/common/wayfinder/routing/strategies/random.d.ts +21 -0
  48. package/lib/types/common/wayfinder/routing/strategies/round-robin.d.ts +29 -0
  49. package/lib/types/common/wayfinder/routing/strategies/static.d.ts +29 -0
  50. package/lib/types/common/wayfinder/verification/{data-root-verifier.d.ts → strategies/data-root-verifier.d.ts} +2 -2
  51. package/lib/types/common/wayfinder/verification/{hash-verifier.d.ts → strategies/hash-verifier.d.ts} +2 -2
  52. package/lib/types/common/wayfinder/{gateways/trusted-gateways.d.ts → verification/trusted.d.ts} +1 -1
  53. package/lib/types/common/wayfinder/wayfinder.d.ts +111 -77
  54. package/lib/types/types/wayfinder.d.ts +8 -4
  55. package/lib/types/version.d.ts +1 -1
  56. package/package.json +1 -1
  57. package/lib/cjs/common/wayfinder/routers/priority.js +0 -29
  58. package/lib/cjs/common/wayfinder/routers/priority.test.js +0 -155
  59. package/lib/cjs/common/wayfinder/routers/random.js +0 -23
  60. package/lib/cjs/common/wayfinder/routers/random.test.js +0 -25
  61. package/lib/cjs/common/wayfinder/routers/simple-cache.js +0 -25
  62. package/lib/cjs/common/wayfinder/routers/simple-cache.test.js +0 -41
  63. package/lib/cjs/common/wayfinder/routers/static.js +0 -14
  64. package/lib/cjs/common/wayfinder/routers/static.test.js +0 -14
  65. package/lib/esm/common/wayfinder/routers/priority.js +0 -25
  66. package/lib/esm/common/wayfinder/routers/priority.test.js +0 -153
  67. package/lib/esm/common/wayfinder/routers/random.js +0 -19
  68. package/lib/esm/common/wayfinder/routers/random.test.js +0 -23
  69. package/lib/esm/common/wayfinder/routers/simple-cache.js +0 -21
  70. package/lib/esm/common/wayfinder/routers/simple-cache.test.js +0 -39
  71. package/lib/esm/common/wayfinder/routers/static.js +0 -10
  72. package/lib/esm/common/wayfinder/routers/static.test.js +0 -12
  73. package/lib/types/common/wayfinder/routers/priority.d.ts +0 -29
  74. /package/lib/types/common/wayfinder/{routers/priority.test.d.ts → routing/strategies/ping.test.d.ts} +0 -0
  75. /package/lib/types/common/wayfinder/{routers → routing/strategies}/random.test.d.ts +0 -0
  76. /package/lib/types/common/wayfinder/{routers/simple-cache.test.d.ts → routing/strategies/round-robin.test.d.ts} +0 -0
  77. /package/lib/types/common/wayfinder/{routers → routing/strategies}/static.test.d.ts +0 -0
@@ -6,8 +6,8 @@ import { Readable } from 'node:stream';
6
6
  import { buffer } from 'node:stream/consumers';
7
7
  import { before, describe, it } from 'node:test';
8
8
  import { Logger } from '../../common/logger.js';
9
- import { RandomGatewayRouter } from './routers/random.js';
10
- import { StaticGatewayRouter } from './routers/static.js';
9
+ import { RandomRoutingStrategy } from './routing/strategies/random.js';
10
+ import { StaticRoutingStrategy } from './routing/strategies/static.js';
11
11
  import { Wayfinder, tapAndVerifyStream } from './wayfinder.js';
12
12
  // TODO: replace with locally running gateway
13
13
  const gatewayUrl = 'permagate.io';
@@ -16,15 +16,14 @@ const stubbedGatewaysProvider = {
16
16
  };
17
17
  Logger.default.setLogLevel('none');
18
18
  describe('Wayfinder', () => {
19
- describe.skip('http wrapper', () => {
19
+ describe('http wrapper', () => {
20
20
  describe('fetch', () => {
21
21
  let wayfinder;
22
22
  before(() => {
23
23
  wayfinder = new Wayfinder({
24
24
  httpClient: fetch,
25
- router: new RandomGatewayRouter({
26
- gatewaysProvider: stubbedGatewaysProvider,
27
- }),
25
+ routingStrategy: new RandomRoutingStrategy(),
26
+ gatewaysProvider: stubbedGatewaysProvider,
28
27
  });
29
28
  });
30
29
  it('should fetch the data using the selected gateway', async () => {
@@ -49,9 +48,11 @@ describe('Wayfinder', () => {
49
48
  const [nativeFetch, response] = await Promise.all([
50
49
  fetch(`https://${gatewayUrl}/`, {
51
50
  method: 'HEAD',
51
+ redirect: 'follow',
52
52
  }),
53
53
  wayfinder.request(`https://${gatewayUrl}/`, {
54
54
  method: 'HEAD',
55
+ redirect: 'follow',
55
56
  }),
56
57
  ]);
57
58
  assert.strictEqual(response.status, 200);
@@ -59,10 +60,14 @@ describe('Wayfinder', () => {
59
60
  // TODO: ensure the headers are the same excluding unique headers
60
61
  });
61
62
  for (const api of ['/info', '/block/current']) {
62
- it(`supports native arweave node apis ${api}`, async () => {
63
+ it.skip(`supports native arweave node apis ${api}`, async () => {
63
64
  const [nativeFetch, response] = await Promise.all([
64
- fetch(`https://${gatewayUrl}${api}`),
65
- wayfinder.request(`ar://${api}`),
65
+ fetch(`https://${gatewayUrl}${api}`, {
66
+ redirect: 'follow',
67
+ }),
68
+ wayfinder.request(`ar://${api}`, {
69
+ redirect: 'follow',
70
+ }),
66
71
  ]);
67
72
  assert.strictEqual(response.status, 200);
68
73
  assert.strictEqual(response.status, nativeFetch.status);
@@ -83,6 +88,7 @@ describe('Wayfinder', () => {
83
88
  it('supports a post request to graphql', async () => {
84
89
  const response = await wayfinder.request('ar:///graphql', {
85
90
  method: 'POST',
91
+ redirect: 'follow',
86
92
  headers: {
87
93
  'Content-Type': 'application/json',
88
94
  },
@@ -116,10 +122,14 @@ describe('Wayfinder', () => {
116
122
  });
117
123
  assert.strictEqual(response.status, 200);
118
124
  });
119
- it.skip('returns the error from the target gateway if the route is not found', async () => {
125
+ it('returns the error from the target gateway if the route is not found', async () => {
120
126
  const [nativeFetch, response] = await Promise.all([
121
- fetch(`https://${gatewayUrl}/ar-io/not-found`),
122
- wayfinder.request('ar:///not-found'),
127
+ fetch(`https://${gatewayUrl}/ar-io/not-found`, {
128
+ redirect: 'follow',
129
+ }),
130
+ wayfinder.request('ar:///ar-io/not-found', {
131
+ redirect: 'follow',
132
+ }),
123
133
  ]);
124
134
  assert.strictEqual(response.status, nativeFetch.status);
125
135
  assert.strictEqual(response.statusText, nativeFetch.statusText);
@@ -130,17 +140,17 @@ describe('Wayfinder', () => {
130
140
  before(() => {
131
141
  wayfinder = new Wayfinder({
132
142
  httpClient: axios,
133
- router: new RandomGatewayRouter({
134
- gatewaysProvider: stubbedGatewaysProvider,
135
- }),
143
+ routingStrategy: new RandomRoutingStrategy(),
144
+ gatewaysProvider: stubbedGatewaysProvider,
136
145
  });
137
146
  });
138
147
  it('should fetch the data using axios default function against the target gateway', async () => {
139
148
  const [nativeAxios, response] = await Promise.all([
140
149
  axios(`https://ao.${gatewayUrl}`),
141
- wayfinder.request('ar://ao'),
150
+ wayfinder.request('ar://ao', {
151
+ maxRedirects: 5,
152
+ }),
142
153
  ]);
143
- assert.strictEqual(response.status, 200);
144
154
  assert.strictEqual(response.status, nativeAxios.status);
145
155
  // assert the arns headers are the same
146
156
  const arnsHeaders = Object.entries(response.headers)
@@ -154,7 +164,6 @@ describe('Wayfinder', () => {
154
164
  axios.get(`https://ao.${gatewayUrl}`),
155
165
  wayfinder.request.get('ar://ao'),
156
166
  ]);
157
- assert.strictEqual(response.status, 200);
158
167
  assert.strictEqual(response.status, nativeAxios.status);
159
168
  // assert the arns headers are the same
160
169
  const arnsHeaders = Object.entries(response.headers)
@@ -173,7 +182,7 @@ describe('Wayfinder', () => {
173
182
  // TODO: ensure the headers are the same excluding unique headers
174
183
  });
175
184
  for (const api of ['/info', '/block/current']) {
176
- it(`supports native arweave node apis ${api}`, async () => {
185
+ it.skip(`supports native arweave node apis ${api}`, async () => {
177
186
  const [nativeAxios, response] = await Promise.all([
178
187
  axios(`https://${gatewayUrl}${api}`),
179
188
  wayfinder.request(`ar://${api}`),
@@ -187,26 +196,24 @@ describe('Wayfinder', () => {
187
196
  it(`supports native ario node gateway apis ${api}`, async () => {
188
197
  const [nativeAxios, response] = await Promise.all([
189
198
  axios(`https://${gatewayUrl}${api}`),
190
- wayfinder.request(`ar:///${api}`),
199
+ wayfinder.request(`ar://${api}`),
191
200
  ]);
192
201
  assert.strictEqual(response.status, 200);
193
202
  assert.strictEqual(response.status, nativeAxios.status);
194
203
  // TODO: ensure the headers are the same excluding unique headers
195
204
  });
196
205
  }
197
- it.skip('should return the error from the target gateway if the route is not found', async () => {
206
+ it('should return the error from the target gateway if the route is not found', async () => {
198
207
  const axiosInstance = axios.create({
199
208
  validateStatus: () => true, // don't throw so we can compare axios result with wrapped axios result
200
209
  });
201
210
  const wayfinder = new Wayfinder({
202
211
  httpClient: axiosInstance,
203
- router: new RandomGatewayRouter({
204
- gatewaysProvider: stubbedGatewaysProvider,
205
- }),
212
+ routingStrategy: new RandomRoutingStrategy(),
206
213
  });
207
214
  const [nativeAxios, response] = await Promise.all([
208
215
  axiosInstance(`https://${gatewayUrl}/ar-io/not-found`),
209
- wayfinder.request('ar:///not-found'),
216
+ wayfinder.request('ar:///ar-io/not-found'),
210
217
  ]);
211
218
  assert.strictEqual(response.status, nativeAxios.status);
212
219
  });
@@ -216,9 +223,8 @@ describe('Wayfinder', () => {
216
223
  before(() => {
217
224
  wayfinder = new Wayfinder({
218
225
  httpClient: got,
219
- router: new RandomGatewayRouter({
220
- gatewaysProvider: stubbedGatewaysProvider,
221
- }),
226
+ routingStrategy: new RandomRoutingStrategy(),
227
+ gatewaysProvider: stubbedGatewaysProvider,
222
228
  });
223
229
  });
224
230
  it('should fetch the data using the got default function against the target gateway', async () => {
@@ -226,13 +232,18 @@ describe('Wayfinder', () => {
226
232
  got(`https://ao.${gatewayUrl}`),
227
233
  wayfinder.request('ar://ao'),
228
234
  ]);
229
- assert.strictEqual(response.statusCode, 200);
230
235
  assert.strictEqual(response.statusCode, nativeGot.statusCode);
231
236
  assert.deepStrictEqual(response.body, nativeGot.body);
232
237
  });
233
238
  it('should stream the data using got.stream against the selected target gateway', async () => {
234
- const nativeBuffer = await buffer(await got.stream(`https://ao.${gatewayUrl}`, { decompress: false }));
235
- const wayfinderBuffer = await buffer(await wayfinder.request.stream('ar://ao', { decompress: false }));
239
+ const nativeBuffer = await buffer(await got.stream(`https://ao.${gatewayUrl}`, {
240
+ decompress: false,
241
+ followRedirect: true,
242
+ }));
243
+ const wayfinderBuffer = await buffer(await wayfinder.request.stream('ar://ao', {
244
+ decompress: false,
245
+ followRedirect: true,
246
+ }));
236
247
  assert.deepStrictEqual(wayfinderBuffer, nativeBuffer);
237
248
  });
238
249
  });
@@ -241,10 +252,10 @@ describe('Wayfinder', () => {
241
252
  it('should emit events on the wayfinder event emitter', async () => {
242
253
  const wayfinder = new Wayfinder({
243
254
  httpClient: fetch,
244
- router: new StaticGatewayRouter({
255
+ routingStrategy: new StaticRoutingStrategy({
245
256
  gateway: `http://${gatewayUrl}`,
246
257
  }),
247
- verifier: {
258
+ verificationStrategy: {
248
259
  // @ts-expect-error
249
260
  verifyData: async (params) => {
250
261
  return;
@@ -258,8 +269,8 @@ describe('Wayfinder', () => {
258
269
  wayfinder.emitter.on('verification-progress', (event) => {
259
270
  events.push({ type: 'verification-progress', ...event });
260
271
  });
261
- wayfinder.emitter.on('verification-passed', (event) => {
262
- events.push({ type: 'verification-passed', ...event });
272
+ wayfinder.emitter.on('verification-succeeded', (event) => {
273
+ events.push({ type: 'verification-succeeded', ...event });
263
274
  });
264
275
  // request data and assert the event is emitted
265
276
  const response = await wayfinder.request('ar://c7wkwt6TKgcWJUfgvpJ5q5qi4DIZyJ1_TqhjXgURh0U', {
@@ -268,7 +279,7 @@ describe('Wayfinder', () => {
268
279
  // read the full response body to ensure the stream is fully consumed
269
280
  await response.text();
270
281
  assert.strictEqual(response.status, 200);
271
- assert.ok(events.find((e) => e.type === 'verification-passed'), 'Should emit at least one verification-passed');
282
+ assert.ok(events.find((e) => e.type === 'verification-succeeded'), 'Should emit at least one verification-succeeded');
272
283
  });
273
284
  it('should execute callbacks provided to the wayfinder constructor', async () => {
274
285
  let verificationFailed = false;
@@ -276,7 +287,7 @@ describe('Wayfinder', () => {
276
287
  let verificationPassed = false;
277
288
  const wayfinder = new Wayfinder({
278
289
  httpClient: fetch,
279
- router: new StaticGatewayRouter({
290
+ routingStrategy: new StaticRoutingStrategy({
280
291
  gateway: `http://${gatewayUrl}`,
281
292
  }),
282
293
  events: {
@@ -290,6 +301,7 @@ describe('Wayfinder', () => {
290
301
  verificationPassed = true;
291
302
  },
292
303
  },
304
+ strict: true,
293
305
  });
294
306
  const response = await wayfinder.request('ar://c7wkwt6TKgcWJUfgvpJ5q5qi4DIZyJ1_TqhjXgURh0U', {
295
307
  redirect: 'follow',
@@ -299,196 +311,203 @@ describe('Wayfinder', () => {
299
311
  assert.strictEqual(response.status, 200);
300
312
  assert.ok(verificationFailed === false, 'Should not emit verification-failed');
301
313
  assert.ok(verificationProgress, 'Should emit verification-progress');
302
- assert.ok(verificationPassed, 'Should emit verification-passed');
314
+ assert.ok(verificationPassed, 'Should emit verification-succeeded');
303
315
  });
304
316
  });
305
- describe.skip('tapAndVerifyRequest', () => {
317
+ describe('tapAndVerifyRequest', () => {
306
318
  describe('Readable', () => {
307
- it('should duplicate the stream, verify the first and return the second if verification passes', async () => {
308
- // create a simple readable
309
- const chunks = [
310
- Buffer.from('foo'),
311
- Buffer.from('bar'),
312
- Buffer.from('baz'),
313
- ];
314
- const contentLength = chunks.reduce((sum, c) => sum + c.length, 0);
315
- // a stream that will emit chunks
316
- const originalStream = Readable.from(chunks);
317
- let seen = Buffer.alloc(0);
318
- const verifyData = async ({ data,
319
- // @ts-expect-error
320
- txId, }) => {
321
- return new Promise((resolve, reject) => {
322
- data.on('data', (chunk) => {
323
- seen = Buffer.concat([seen, chunk]);
324
- });
325
- data.on('end', () => {
326
- // Should have seen exactly the full payload
327
- assert.strictEqual(seen.length, contentLength);
328
- resolve();
319
+ describe('strict mode enabled', () => {
320
+ it('should duplicate the stream, verify the first and return the second if verification passes', async () => {
321
+ // create a simple readable
322
+ const chunks = [
323
+ Buffer.from('foo'),
324
+ Buffer.from('bar'),
325
+ Buffer.from('baz'),
326
+ ];
327
+ const contentLength = chunks.reduce((sum, c) => sum + c.length, 0);
328
+ // a stream that will emit chunks
329
+ const originalStream = Readable.from(chunks);
330
+ let seen = Buffer.alloc(0);
331
+ const verifyData = async ({ data,
332
+ // @ts-expect-error
333
+ txId, }) => {
334
+ return new Promise((resolve, reject) => {
335
+ data.on('data', (chunk) => {
336
+ seen = Buffer.concat([seen, chunk]);
337
+ });
338
+ data.on('end', () => {
339
+ // Should have seen exactly the full payload
340
+ assert.strictEqual(seen.length, contentLength);
341
+ resolve();
342
+ });
343
+ data.on('error', reject);
329
344
  });
330
- data.on('error', reject);
345
+ };
346
+ const txId = 'test-tx-1';
347
+ const emitter = new EventEmitter();
348
+ const events = [];
349
+ emitter.on('verification-progress', (e) => {
350
+ events.push({ type: 'verification-progress', ...e });
331
351
  });
332
- };
333
- const txId = 'test-tx-1';
334
- const emitter = new EventEmitter();
335
- const events = [];
336
- emitter.on('verification-progress', (e) => {
337
- console.log('verification-progress', e);
338
- events.push({ type: 'verification-progress', ...e });
339
- });
340
- emitter.on('verification-passed', (e) => events.push({ type: 'verification-passed', ...e }));
341
- // tap with verification
342
- const tapped = tapAndVerifyStream({
343
- originalStream,
344
- contentLength,
345
- verifyData,
346
- txId,
347
- emitter,
348
- });
349
- // read the stream
350
- const out = [];
351
- for await (const chunk of tapped) {
352
- out.push(chunk);
353
- }
354
- // assert the stream is the same
355
- assert.strictEqual(Buffer.concat(out).toString(), Buffer.concat(chunks).toString(), 'The tapped stream should emit exactly the original data');
356
- assert.ok(events.find((e) => e.type === 'verification-progress'), 'Should emit at least one verification-progress');
357
- assert.ok(events.find((e) => e.type === 'verification-passed' && e.txId === txId), 'Should emit at least one verification-passed');
358
- });
359
- it('should throw an error on the client stream if verification fails', async () => {
360
- const chunks = [
361
- Buffer.from('foo'),
362
- Buffer.from('bar'),
363
- Buffer.from('baz'),
364
- ];
365
- const contentLength = chunks.reduce((sum, c) => sum + c.length, 0);
366
- // a stream that will emit chunks
367
- const originalStream = Readable.from(chunks);
368
- const verifyData = async ({
369
- // @ts-expect-error
370
- data, txId, }) => {
371
- throw new Error('Verification failed for txId: ' + txId);
372
- };
373
- const txId = 'test-tx-1';
374
- const emitter = new EventEmitter();
375
- const events = [];
376
- emitter.on('verification-progress', (e) => events.push({ type: 'verification-progress', ...e }));
377
- emitter.on('verification-failed', (e) => events.push({ type: 'verification-failed', ...e }));
378
- // tap with verification
379
- const tapped = tapAndVerifyStream({
380
- originalStream,
381
- contentLength,
382
- verifyData,
383
- txId,
384
- emitter,
385
- });
386
- // read the stream
387
- try {
352
+ emitter.on('verification-succeeded', (e) => events.push({ type: 'verification-succeeded', ...e }));
353
+ // tap with verification
354
+ const tapped = tapAndVerifyStream({
355
+ originalStream,
356
+ contentLength,
357
+ verifyData,
358
+ txId,
359
+ emitter,
360
+ strict: true,
361
+ });
362
+ // read the stream
388
363
  const out = [];
389
364
  for await (const chunk of tapped) {
390
365
  out.push(chunk);
391
366
  }
392
- }
393
- catch (error) {
394
- assert.ok(events.find((e) => e.type === 'verification-failed' && e.txId === txId), 'Should emit at least one verification-failed');
395
- // stream should be closed
396
- assert.ok(tapped.closed);
397
- }
367
+ // assert the stream is the same
368
+ assert.strictEqual(Buffer.concat(out).toString(), Buffer.concat(chunks).toString(), 'The tapped stream should emit exactly the original data');
369
+ assert.ok(events.find((e) => e.type === 'verification-progress'), 'Should emit at least one verification-progress');
370
+ assert.ok(events.find((e) => e.type === 'verification-succeeded' && e.txId === txId), 'Should emit at least one verification-succeeded');
371
+ });
372
+ it('should throw an error on the client stream if verification fails', async () => {
373
+ const chunks = [
374
+ Buffer.from('foo'),
375
+ Buffer.from('bar'),
376
+ Buffer.from('baz'),
377
+ ];
378
+ const contentLength = chunks.reduce((sum, c) => sum + c.length, 0);
379
+ // a stream that will emit chunks
380
+ const originalStream = Readable.from(chunks);
381
+ const verifyData = async ({
382
+ // @ts-expect-error
383
+ data, txId, }) => {
384
+ throw new Error('Verification failed for txId: ' + txId);
385
+ };
386
+ const txId = 'test-tx-1';
387
+ const emitter = new EventEmitter();
388
+ const events = [];
389
+ emitter.on('verification-progress', (e) => events.push({ type: 'verification-progress', ...e }));
390
+ emitter.on('verification-failed', (e) => events.push({ type: 'verification-failed', ...e }));
391
+ // tap with verification (using strict mode)
392
+ const tapped = tapAndVerifyStream({
393
+ originalStream,
394
+ contentLength,
395
+ verifyData,
396
+ txId,
397
+ emitter,
398
+ strict: true,
399
+ });
400
+ // read the stream
401
+ try {
402
+ const out = [];
403
+ for await (const chunk of tapped) {
404
+ out.push(chunk);
405
+ }
406
+ }
407
+ catch (error) {
408
+ assert.ok(events.find((e) => e.type === 'verification-failed' && e.txId === txId), 'Should emit at least one verification-failed');
409
+ // stream should be closed
410
+ assert.ok(tapped.closed);
411
+ }
412
+ });
398
413
  });
399
414
  });
400
415
  describe('ReadableStream', () => {
401
- it('should duplicate the ReadableStream, verify the first and return the second if verification passes', async () => {
402
- // create a simple readable
403
- const chunks = [
404
- Buffer.from('foo'),
405
- Buffer.from('bar'),
406
- Buffer.from('baz'),
407
- ];
408
- const contentLength = chunks.reduce((sum, c) => sum + c.length, 0);
409
- // a stream that will emit chunks
410
- const originalStream = ReadableStream.from(chunks);
411
- let seen = Buffer.alloc(0);
412
- const verifyData = async ({ data,
413
- // @ts-expect-error
414
- txId, }) => {
415
- return new Promise(async (resolve, reject) => {
416
- const reader = data.getReader();
417
- while (true) {
418
- try {
419
- const { done, value } = await reader.read();
420
- if (done) {
421
- resolve();
422
- break;
416
+ describe('strict mode enabled', () => {
417
+ it('should duplicate the ReadableStream, verify the first and return the second if verification passes', async () => {
418
+ // create a simple readable
419
+ const chunks = [
420
+ Buffer.from('foo'),
421
+ Buffer.from('bar'),
422
+ Buffer.from('baz'),
423
+ ];
424
+ const contentLength = chunks.reduce((sum, c) => sum + c.length, 0);
425
+ // a stream that will emit chunks
426
+ const originalStream = ReadableStream.from(chunks);
427
+ let seen = Buffer.alloc(0);
428
+ const verifyData = async ({ data,
429
+ // @ts-expect-error
430
+ txId, }) => {
431
+ return new Promise(async (resolve, reject) => {
432
+ const reader = data.getReader();
433
+ while (true) {
434
+ try {
435
+ const { done, value } = await reader.read();
436
+ if (done) {
437
+ resolve();
438
+ break;
439
+ }
440
+ seen = Buffer.concat([seen, value]);
441
+ }
442
+ catch (error) {
443
+ reject(error);
423
444
  }
424
- seen = Buffer.concat([seen, value]);
425
- }
426
- catch (error) {
427
- reject(error);
428
445
  }
429
- }
446
+ });
447
+ };
448
+ const txId = 'test-tx-1';
449
+ const emitter = new EventEmitter();
450
+ const events = [];
451
+ emitter.on('verification-progress', (e) => events.push({ type: 'verification-progress', ...e }));
452
+ emitter.on('verification-succeeded', (e) => events.push({ type: 'verification-succeeded', ...e }));
453
+ // tap with verification
454
+ const tapped = tapAndVerifyStream({
455
+ originalStream,
456
+ contentLength,
457
+ verifyData,
458
+ txId,
459
+ emitter,
460
+ strict: true,
430
461
  });
431
- };
432
- const txId = 'test-tx-1';
433
- const emitter = new EventEmitter();
434
- const events = [];
435
- emitter.on('verification-progress', (e) => events.push({ type: 'verification-progress', ...e }));
436
- emitter.on('verification-passed', (e) => events.push({ type: 'verification-passed', ...e }));
437
- // tap with verification
438
- const tapped = tapAndVerifyStream({
439
- originalStream,
440
- contentLength,
441
- verifyData,
442
- txId,
443
- emitter,
444
- });
445
- // read the stream
446
- const out = [];
447
- for await (const chunk of tapped) {
448
- out.push(chunk);
449
- }
450
- // assert the stream is the same
451
- assert.strictEqual(Buffer.concat(out).toString(), Buffer.concat(chunks).toString(), 'The tapped stream should emit exactly the original data');
452
- assert.ok(events.find((e) => e.type === 'verification-progress'), 'Should emit at least one verification-progress');
453
- assert.ok(events.find((e) => e.type === 'verification-passed' && e.txId === txId), 'Should emit at least one verification-passed');
454
- });
455
- it('should throw an error on the client stream if verification fails', async () => {
456
- const chunks = [
457
- Buffer.from('foo'),
458
- Buffer.from('bar'),
459
- Buffer.from('baz'),
460
- ];
461
- const contentLength = chunks.reduce((sum, c) => sum + c.length, 0);
462
- // a stream that will emit chunks
463
- const originalStream = ReadableStream.from(chunks);
464
- const verifyData = async ({
465
- // @ts-expect-error
466
- data, txId, }) => {
467
- throw new Error('Verification failed for txId: ' + txId);
468
- };
469
- const txId = 'test-tx-1';
470
- const emitter = new EventEmitter();
471
- const events = [];
472
- emitter.on('verification-progress', (e) => events.push({ type: 'verification-progress', ...e }));
473
- emitter.on('verification-failed', (e) => events.push({ type: 'verification-failed', ...e }));
474
- // tap with verification
475
- const tapped = tapAndVerifyStream({
476
- originalStream,
477
- contentLength,
478
- verifyData,
479
- txId,
480
- emitter,
481
- });
482
- // read the stream
483
- try {
462
+ // read the stream
484
463
  const out = [];
485
464
  for await (const chunk of tapped) {
486
465
  out.push(chunk);
487
466
  }
488
- }
489
- catch (error) {
490
- assert.ok(events.find((e) => e.type === 'verification-failed' && e.txId === txId), 'Should emit at least one verification-failed');
491
- }
467
+ // assert the stream is the same
468
+ assert.strictEqual(Buffer.concat(out).toString(), Buffer.concat(chunks).toString(), 'The tapped stream should emit exactly the original data');
469
+ assert.ok(events.find((e) => e.type === 'verification-progress'), 'Should emit at least one verification-progress');
470
+ assert.ok(events.find((e) => e.type === 'verification-succeeded' && e.txId === txId), 'Should emit at least one verification-succeeded');
471
+ });
472
+ it('should throw an error on the client stream if verification fails', async () => {
473
+ const chunks = [
474
+ Buffer.from('foo'),
475
+ Buffer.from('bar'),
476
+ Buffer.from('baz'),
477
+ ];
478
+ const contentLength = chunks.reduce((sum, c) => sum + c.length, 0);
479
+ // a stream that will emit chunks
480
+ const originalStream = ReadableStream.from(chunks);
481
+ const verifyData = async ({
482
+ // @ts-expect-error
483
+ data, txId, }) => {
484
+ throw new Error('Verification failed for txId: ' + txId);
485
+ };
486
+ const txId = 'test-tx-1';
487
+ const emitter = new EventEmitter();
488
+ const events = [];
489
+ emitter.on('verification-progress', (e) => events.push({ type: 'verification-progress', ...e }));
490
+ emitter.on('verification-failed', (e) => events.push({ type: 'verification-failed', ...e }));
491
+ // tap with verification (using strict mode)
492
+ const tapped = tapAndVerifyStream({
493
+ originalStream,
494
+ contentLength,
495
+ verifyData,
496
+ txId,
497
+ emitter,
498
+ strict: true,
499
+ });
500
+ // read the stream
501
+ try {
502
+ const out = [];
503
+ for await (const chunk of tapped) {
504
+ out.push(chunk);
505
+ }
506
+ }
507
+ catch (error) {
508
+ assert.ok(events.find((e) => e.type === 'verification-failed' && e.txId === txId), 'Should emit at least one verification-failed');
509
+ }
510
+ });
492
511
  });
493
512
  });
494
513
  });
@@ -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.11.0-alpha.9';
17
+ export const version = '3.11.0-beta.1';