@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.
- package/bundles/web.bundle.min.js +106 -106
- package/lib/cjs/cli/utils.js +4 -1
- package/lib/cjs/common/contracts/ao-process.js +2 -1
- package/lib/cjs/common/wayfinder/{gateways.js → gateways/network.js} +3 -41
- package/lib/cjs/common/wayfinder/gateways/simple-cache.js +35 -0
- package/lib/cjs/common/wayfinder/gateways/static.js +13 -0
- package/lib/cjs/common/wayfinder/index.js +11 -8
- package/lib/cjs/common/wayfinder/routing/strategies/ping.js +72 -0
- package/lib/cjs/common/wayfinder/routing/strategies/ping.test.js +156 -0
- package/lib/cjs/common/wayfinder/routing/strategies/random.js +13 -0
- package/lib/cjs/common/wayfinder/routing/strategies/random.test.js +68 -0
- package/lib/cjs/common/wayfinder/routing/strategies/round-robin.js +42 -0
- package/lib/cjs/common/wayfinder/routing/strategies/round-robin.test.js +78 -0
- package/lib/cjs/common/wayfinder/routing/strategies/static.js +29 -0
- package/lib/cjs/common/wayfinder/routing/strategies/static.test.js +40 -0
- package/lib/cjs/common/wayfinder/verification/{data-root-verifier.js → strategies/data-root-verifier.js} +4 -4
- package/lib/cjs/common/wayfinder/verification/{hash-verifier.js → strategies/hash-verifier.js} +4 -4
- package/lib/cjs/common/wayfinder/{gateways/trusted-gateways.js → verification/trusted.js} +1 -1
- package/lib/cjs/common/wayfinder/wayfinder.js +397 -257
- package/lib/cjs/common/wayfinder/wayfinder.test.js +227 -208
- package/lib/cjs/version.js +1 -1
- package/lib/esm/cli/utils.js +4 -1
- package/lib/esm/common/contracts/ao-process.js +2 -1
- package/lib/esm/common/wayfinder/{gateways.js → gateways/network.js} +2 -38
- package/lib/esm/common/wayfinder/gateways/simple-cache.js +31 -0
- package/lib/esm/common/wayfinder/gateways/static.js +9 -0
- package/lib/esm/common/wayfinder/index.js +11 -8
- package/lib/esm/common/wayfinder/routing/strategies/ping.js +68 -0
- package/lib/esm/common/wayfinder/routing/strategies/ping.test.js +151 -0
- package/lib/esm/common/wayfinder/routing/strategies/random.js +9 -0
- package/lib/esm/common/wayfinder/routing/strategies/random.test.js +63 -0
- package/lib/esm/common/wayfinder/routing/strategies/round-robin.js +38 -0
- package/lib/esm/common/wayfinder/routing/strategies/round-robin.test.js +73 -0
- package/lib/esm/common/wayfinder/routing/strategies/static.js +25 -0
- package/lib/esm/common/wayfinder/routing/strategies/static.test.js +35 -0
- package/lib/esm/common/wayfinder/verification/{data-root-verifier.js → strategies/data-root-verifier.js} +2 -2
- package/lib/esm/common/wayfinder/verification/{hash-verifier.js → strategies/hash-verifier.js} +2 -2
- package/lib/esm/common/wayfinder/{gateways/trusted-gateways.js → verification/trusted.js} +1 -1
- package/lib/esm/common/wayfinder/wayfinder.js +395 -255
- package/lib/esm/common/wayfinder/wayfinder.test.js +227 -208
- package/lib/esm/version.js +1 -1
- package/lib/types/common/wayfinder/{gateways.d.ts → gateways/network.d.ts} +3 -23
- package/lib/types/common/wayfinder/{routers/random.d.ts → gateways/simple-cache.d.ts} +12 -8
- package/lib/types/common/wayfinder/{routers → gateways}/static.d.ts +6 -7
- package/lib/types/common/wayfinder/index.d.ts +10 -7
- package/lib/types/common/wayfinder/{routers/simple-cache.d.ts → routing/strategies/ping.d.ts} +10 -11
- package/lib/types/common/wayfinder/routing/strategies/random.d.ts +21 -0
- package/lib/types/common/wayfinder/routing/strategies/round-robin.d.ts +29 -0
- package/lib/types/common/wayfinder/routing/strategies/static.d.ts +29 -0
- package/lib/types/common/wayfinder/verification/{data-root-verifier.d.ts → strategies/data-root-verifier.d.ts} +2 -2
- package/lib/types/common/wayfinder/verification/{hash-verifier.d.ts → strategies/hash-verifier.d.ts} +2 -2
- package/lib/types/common/wayfinder/{gateways/trusted-gateways.d.ts → verification/trusted.d.ts} +1 -1
- package/lib/types/common/wayfinder/wayfinder.d.ts +111 -77
- package/lib/types/types/wayfinder.d.ts +8 -4
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
- package/lib/cjs/common/wayfinder/routers/priority.js +0 -29
- package/lib/cjs/common/wayfinder/routers/priority.test.js +0 -155
- package/lib/cjs/common/wayfinder/routers/random.js +0 -23
- package/lib/cjs/common/wayfinder/routers/random.test.js +0 -25
- package/lib/cjs/common/wayfinder/routers/simple-cache.js +0 -25
- package/lib/cjs/common/wayfinder/routers/simple-cache.test.js +0 -41
- package/lib/cjs/common/wayfinder/routers/static.js +0 -14
- package/lib/cjs/common/wayfinder/routers/static.test.js +0 -14
- package/lib/esm/common/wayfinder/routers/priority.js +0 -25
- package/lib/esm/common/wayfinder/routers/priority.test.js +0 -153
- package/lib/esm/common/wayfinder/routers/random.js +0 -19
- package/lib/esm/common/wayfinder/routers/random.test.js +0 -23
- package/lib/esm/common/wayfinder/routers/simple-cache.js +0 -21
- package/lib/esm/common/wayfinder/routers/simple-cache.test.js +0 -39
- package/lib/esm/common/wayfinder/routers/static.js +0 -10
- package/lib/esm/common/wayfinder/routers/static.test.js +0 -12
- package/lib/types/common/wayfinder/routers/priority.d.ts +0 -29
- /package/lib/types/common/wayfinder/{routers/priority.test.d.ts → routing/strategies/ping.test.d.ts} +0 -0
- /package/lib/types/common/wayfinder/{routers → routing/strategies}/random.test.d.ts +0 -0
- /package/lib/types/common/wayfinder/{routers/simple-cache.test.d.ts → routing/strategies/round-robin.test.d.ts} +0 -0
- /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 {
|
|
10
|
-
import {
|
|
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
|
|
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
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
134
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
220
|
-
|
|
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}`, {
|
|
235
|
-
|
|
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
|
-
|
|
255
|
+
routingStrategy: new StaticRoutingStrategy({
|
|
245
256
|
gateway: `http://${gatewayUrl}`,
|
|
246
257
|
}),
|
|
247
|
-
|
|
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-
|
|
262
|
-
events.push({ type: 'verification-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
314
|
+
assert.ok(verificationPassed, 'Should emit verification-succeeded');
|
|
303
315
|
});
|
|
304
316
|
});
|
|
305
|
-
describe
|
|
317
|
+
describe('tapAndVerifyRequest', () => {
|
|
306
318
|
describe('Readable', () => {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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
|
-
|
|
394
|
-
assert.ok(events.find((e) => e.type === 'verification-
|
|
395
|
-
|
|
396
|
-
|
|
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
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
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
|
-
|
|
490
|
-
assert.ok(events.find((e) => e.type === 'verification-
|
|
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
|
});
|
package/lib/esm/version.js
CHANGED