@ipld/car 3.2.4 → 4.1.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 (82) hide show
  1. package/README.md +183 -2
  2. package/api.ts +22 -4
  3. package/buffer-writer +1 -0
  4. package/cjs/browser-test/common.js +78 -3
  5. package/cjs/browser-test/node-test-large.js +8 -8
  6. package/cjs/browser-test/test-buffer-writer.js +330 -0
  7. package/cjs/browser-test/test-errors.js +57 -34
  8. package/cjs/browser-test/test-indexer.js +12 -0
  9. package/cjs/browser-test/test-reader.js +83 -0
  10. package/cjs/browser-test/test-writer.js +3 -3
  11. package/cjs/lib/buffer-writer.js +161 -0
  12. package/cjs/lib/decoder.js +72 -15
  13. package/cjs/lib/encoder.js +2 -2
  14. package/cjs/lib/header-validator.js +29 -0
  15. package/cjs/lib/reader-browser.js +7 -7
  16. package/cjs/lib/writer-browser.js +1 -1
  17. package/cjs/node-test/common.js +78 -3
  18. package/cjs/node-test/node-test-large.js +8 -8
  19. package/cjs/node-test/test-buffer-writer.js +330 -0
  20. package/cjs/node-test/test-errors.js +57 -34
  21. package/cjs/node-test/test-indexer.js +12 -0
  22. package/cjs/node-test/test-reader.js +83 -0
  23. package/cjs/node-test/test-writer.js +3 -3
  24. package/esm/browser-test/common.js +76 -1
  25. package/esm/browser-test/test-buffer-writer.js +311 -0
  26. package/esm/browser-test/test-errors.js +57 -33
  27. package/esm/browser-test/test-indexer.js +15 -0
  28. package/esm/browser-test/test-reader.js +90 -1
  29. package/esm/browser-test/test-writer.js +3 -3
  30. package/esm/lib/buffer-writer.js +126 -0
  31. package/esm/lib/decoder.js +69 -13
  32. package/esm/lib/header-validator.js +23 -0
  33. package/esm/lib/reader-browser.js +7 -8
  34. package/esm/lib/writer-browser.js +1 -1
  35. package/esm/node-test/common.js +76 -1
  36. package/esm/node-test/test-buffer-writer.js +311 -0
  37. package/esm/node-test/test-errors.js +57 -33
  38. package/esm/node-test/test-indexer.js +15 -0
  39. package/esm/node-test/test-reader.js +90 -1
  40. package/esm/node-test/test-writer.js +3 -3
  41. package/examples/car-to-fixture.js +1 -4
  42. package/examples/dump-index.js +24 -0
  43. package/examples/test-examples.js +33 -0
  44. package/lib/buffer-writer.js +286 -0
  45. package/lib/coding.ts +17 -2
  46. package/lib/decoder.js +130 -14
  47. package/lib/header-validator.js +33 -0
  48. package/lib/header.ipldsch +6 -0
  49. package/lib/reader-browser.js +11 -11
  50. package/lib/writer-browser.js +1 -1
  51. package/package.json +16 -6
  52. package/test/_fixtures_to_js.mjs +24 -0
  53. package/test/common.js +49 -3
  54. package/test/go.carv2 +0 -0
  55. package/test/test-buffer-writer.js +256 -0
  56. package/test/test-errors.js +52 -30
  57. package/test/test-indexer.js +24 -1
  58. package/test/test-reader.js +94 -1
  59. package/test/test-writer.js +3 -3
  60. package/tsconfig.json +3 -1
  61. package/types/api.d.ts +16 -0
  62. package/types/api.d.ts.map +1 -1
  63. package/types/lib/buffer-writer.d.ts +86 -0
  64. package/types/lib/buffer-writer.d.ts.map +1 -0
  65. package/types/lib/coding.d.ts +14 -4
  66. package/types/lib/coding.d.ts.map +1 -1
  67. package/types/lib/decoder.d.ts +38 -2
  68. package/types/lib/decoder.d.ts.map +1 -1
  69. package/types/lib/header-validator.d.ts +2 -0
  70. package/types/lib/header-validator.d.ts.map +1 -0
  71. package/types/lib/reader-browser.d.ts +15 -7
  72. package/types/lib/reader-browser.d.ts.map +1 -1
  73. package/types/test/_fixtures_to_js.d.mts +3 -0
  74. package/types/test/_fixtures_to_js.d.mts.map +1 -0
  75. package/types/test/common.d.ts +13 -0
  76. package/types/test/common.d.ts.map +1 -1
  77. package/types/test/fixtures-expectations.d.ts +63 -0
  78. package/types/test/fixtures-expectations.d.ts.map +1 -0
  79. package/types/test/fixtures.d.ts +3 -0
  80. package/types/test/fixtures.d.ts.map +1 -0
  81. package/types/test/test-buffer-writer.d.ts +2 -0
  82. package/types/test/test-buffer-writer.d.ts.map +1 -0
@@ -0,0 +1,330 @@
1
+ 'use strict';
2
+
3
+ var bufferWriter = require('../lib/buffer-writer.js');
4
+ var reader = require('../lib/reader.js');
5
+ var encoder = require('../lib/encoder.js');
6
+ var common = require('./common.js');
7
+ var multiformats = require('multiformats');
8
+ var CBOR = require('@ipld/dag-cbor');
9
+ var sha2 = require('multiformats/hashes/sha2');
10
+ var identity = require('multiformats/hashes/identity');
11
+ var raw = require('multiformats/codecs/raw');
12
+ var Block = require('multiformats/block');
13
+
14
+ function _interopNamespace(e) {
15
+ if (e && e.__esModule) return e;
16
+ var n = Object.create(null);
17
+ if (e) {
18
+ Object.keys(e).forEach(function (k) {
19
+ if (k !== 'default') {
20
+ var d = Object.getOwnPropertyDescriptor(e, k);
21
+ Object.defineProperty(n, k, d.get ? d : {
22
+ enumerable: true,
23
+ get: function () { return e[k]; }
24
+ });
25
+ }
26
+ });
27
+ }
28
+ n["default"] = e;
29
+ return Object.freeze(n);
30
+ }
31
+
32
+ var CBOR__namespace = /*#__PURE__*/_interopNamespace(CBOR);
33
+ var raw__namespace = /*#__PURE__*/_interopNamespace(raw);
34
+ var Block__namespace = /*#__PURE__*/_interopNamespace(Block);
35
+
36
+ describe('CarBufferWriter', () => {
37
+ const cid = multiformats.CID.parse('bafkreifuosuzujyf4i6psbneqtwg2fhplc2wxptc5euspa2gn3bwhnihfu');
38
+ describe('calculateHeaderLength', async () => {
39
+ for (const count of [
40
+ 0,
41
+ 1,
42
+ 10,
43
+ 18,
44
+ 24,
45
+ 48,
46
+ 124,
47
+ 255,
48
+ 258,
49
+ 65536 - 1,
50
+ 65536
51
+ ]) {
52
+ it(`calculateHeaderLength(new Array(${ count }).fill(36))`, () => {
53
+ const roots = new Array(count).fill(cid);
54
+ const sizes = new Array(count).fill(cid.bytes.byteLength);
55
+ common.assert.deepEqual(bufferWriter.calculateHeaderLength(sizes), encoder.createHeader(roots).byteLength);
56
+ });
57
+ it(`calculateHeaderLength(new Array(${ count }).fill(36))`, () => {
58
+ const roots = new Array(count).fill(cid);
59
+ const rootLengths = roots.map(c => c.bytes.byteLength);
60
+ common.assert.deepEqual(bufferWriter.calculateHeaderLength(rootLengths), encoder.createHeader(roots).byteLength);
61
+ });
62
+ }
63
+ it('estimate on large CIDs', () => {
64
+ const largeCID = multiformats.CID.parse(`bafkqbbac${ 'a'.repeat(416) }`);
65
+ common.assert.equal(bufferWriter.calculateHeaderLength([
66
+ cid.bytes.byteLength,
67
+ largeCID.bytes.byteLength
68
+ ]), encoder.createHeader([
69
+ cid,
70
+ largeCID
71
+ ]).byteLength);
72
+ });
73
+ it('estimate on large CIDs 2', () => {
74
+ const largeCID = multiformats.CID.createV1(raw__namespace.code, identity.identity.digest(new Uint8Array(512).fill(1)));
75
+ common.assert.equal(bufferWriter.calculateHeaderLength([
76
+ cid.bytes.byteLength,
77
+ largeCID.bytes.byteLength
78
+ ]), encoder.createHeader([
79
+ cid,
80
+ largeCID
81
+ ]).byteLength);
82
+ });
83
+ });
84
+ describe('writer', () => {
85
+ it('estimate header and write blocks', async () => {
86
+ const headerSize = bufferWriter.estimateHeaderLength(1);
87
+ const dataSize = 256;
88
+ const buffer = new ArrayBuffer(headerSize + dataSize);
89
+ const writer = bufferWriter.createWriter(buffer, { headerSize });
90
+ const b1 = await Block__namespace.encode({
91
+ value: { hello: 'world' },
92
+ codec: CBOR__namespace,
93
+ hasher: sha2.sha256
94
+ });
95
+ writer.write(b1);
96
+ const b2 = await Block__namespace.encode({
97
+ value: { bye: 'world' },
98
+ codec: CBOR__namespace,
99
+ hasher: sha2.sha256
100
+ });
101
+ writer.write(b2);
102
+ writer.addRoot(b1.cid);
103
+ const bytes = writer.close();
104
+ const reader$1 = await reader.CarReader.fromBytes(bytes);
105
+ common.assert.deepEqual(await reader$1.getRoots(), [b1.cid]);
106
+ common.assert.deepEqual(reader$1._blocks, [
107
+ {
108
+ cid: b1.cid,
109
+ bytes: b1.bytes
110
+ },
111
+ {
112
+ cid: b2.cid,
113
+ bytes: b2.bytes
114
+ }
115
+ ]);
116
+ });
117
+ it('overestimate header', async () => {
118
+ const headerSize = bufferWriter.estimateHeaderLength(2);
119
+ const dataSize = 256;
120
+ const buffer = new ArrayBuffer(headerSize + dataSize);
121
+ const writer = bufferWriter.createWriter(buffer, { headerSize });
122
+ const b1 = await Block__namespace.encode({
123
+ value: { hello: 'world' },
124
+ codec: CBOR__namespace,
125
+ hasher: sha2.sha256
126
+ });
127
+ writer.write(b1);
128
+ const b2 = await Block__namespace.encode({
129
+ value: { bye: 'world' },
130
+ codec: CBOR__namespace,
131
+ hasher: sha2.sha256
132
+ });
133
+ writer.write(b2);
134
+ writer.addRoot(b1.cid);
135
+ common.assert.throws(() => writer.close(), /Header size was overestimate/);
136
+ const bytes = writer.close({ resize: true });
137
+ const reader$1 = await reader.CarReader.fromBytes(bytes);
138
+ common.assert.deepEqual(await reader$1.getRoots(), [b1.cid]);
139
+ common.assert.deepEqual(reader$1._blocks, [
140
+ {
141
+ cid: b1.cid,
142
+ bytes: b1.bytes
143
+ },
144
+ {
145
+ cid: b2.cid,
146
+ bytes: b2.bytes
147
+ }
148
+ ]);
149
+ });
150
+ it('underestimate header', async () => {
151
+ const headerSize = bufferWriter.estimateHeaderLength(2);
152
+ const dataSize = 300;
153
+ const buffer = new ArrayBuffer(headerSize + dataSize);
154
+ const writer = bufferWriter.createWriter(buffer, { headerSize });
155
+ const b1 = await Block__namespace.encode({
156
+ value: { hello: 'world' },
157
+ codec: CBOR__namespace,
158
+ hasher: sha2.sha256
159
+ });
160
+ writer.write(b1);
161
+ writer.addRoot(b1.cid);
162
+ const b2 = await Block__namespace.encode({
163
+ value: { bye: 'world' },
164
+ codec: CBOR__namespace,
165
+ hasher: sha2.sha512
166
+ });
167
+ writer.write(b2);
168
+ common.assert.throws(() => writer.addRoot(b2.cid), /has no capacity/);
169
+ writer.addRoot(b2.cid, { resize: true });
170
+ const bytes = writer.close();
171
+ const reader$1 = await reader.CarReader.fromBytes(bytes);
172
+ common.assert.deepEqual(await reader$1.getRoots(), [
173
+ b1.cid,
174
+ b2.cid
175
+ ]);
176
+ common.assert.deepEqual(reader$1._blocks, [
177
+ {
178
+ cid: b1.cid,
179
+ bytes: b1.bytes
180
+ },
181
+ {
182
+ cid: b2.cid,
183
+ bytes: b2.bytes
184
+ }
185
+ ]);
186
+ });
187
+ });
188
+ it('has no space for the root', async () => {
189
+ const headerSize = bufferWriter.estimateHeaderLength(1);
190
+ const dataSize = 100;
191
+ const buffer = new ArrayBuffer(headerSize + dataSize);
192
+ const writer = bufferWriter.createWriter(buffer, { headerSize });
193
+ const b1 = await Block__namespace.encode({
194
+ value: { hello: 'world' },
195
+ codec: CBOR__namespace,
196
+ hasher: sha2.sha256
197
+ });
198
+ writer.write(b1);
199
+ writer.addRoot(b1.cid);
200
+ const b2 = await Block__namespace.encode({
201
+ value: { bye: 'world' },
202
+ codec: CBOR__namespace,
203
+ hasher: sha2.sha256
204
+ });
205
+ writer.write(b2);
206
+ common.assert.throws(() => writer.addRoot(b2.cid), /Buffer has no capacity for a new root/);
207
+ common.assert.throws(() => writer.addRoot(b2.cid, { resize: true }), /Buffer has no capacity for a new root/);
208
+ const bytes = writer.close();
209
+ const reader$1 = await reader.CarReader.fromBytes(bytes);
210
+ common.assert.deepEqual(await reader$1.getRoots(), [b1.cid]);
211
+ common.assert.deepEqual(reader$1._blocks, [
212
+ {
213
+ cid: b1.cid,
214
+ bytes: b1.bytes
215
+ },
216
+ {
217
+ cid: b2.cid,
218
+ bytes: b2.bytes
219
+ }
220
+ ]);
221
+ });
222
+ it('has no space for the block', async () => {
223
+ const headerSize = bufferWriter.estimateHeaderLength(1);
224
+ const dataSize = 58;
225
+ const buffer = new ArrayBuffer(headerSize + dataSize);
226
+ const writer = bufferWriter.createWriter(buffer, { headerSize });
227
+ const b1 = await Block__namespace.encode({
228
+ value: { hello: 'world' },
229
+ codec: CBOR__namespace,
230
+ hasher: sha2.sha256
231
+ });
232
+ writer.write(b1);
233
+ writer.addRoot(b1.cid);
234
+ const b2 = await Block__namespace.encode({
235
+ value: { bye: 'world' },
236
+ codec: CBOR__namespace,
237
+ hasher: sha2.sha256
238
+ });
239
+ common.assert.throws(() => writer.write(b2), /Buffer has no capacity for this block/);
240
+ const bytes = writer.close();
241
+ const reader$1 = await reader.CarReader.fromBytes(bytes);
242
+ common.assert.deepEqual(await reader$1.getRoots(), [b1.cid]);
243
+ common.assert.deepEqual(reader$1._blocks, [{
244
+ cid: b1.cid,
245
+ bytes: b1.bytes
246
+ }]);
247
+ });
248
+ it('provide roots', async () => {
249
+ const b1 = await Block__namespace.encode({
250
+ value: { hello: 'world' },
251
+ codec: CBOR__namespace,
252
+ hasher: sha2.sha256
253
+ });
254
+ const b2 = await Block__namespace.encode({
255
+ value: { bye: 'world' },
256
+ codec: CBOR__namespace,
257
+ hasher: sha2.sha512
258
+ });
259
+ const buffer = new ArrayBuffer(300);
260
+ const writer = bufferWriter.createWriter(buffer, {
261
+ roots: [
262
+ b1.cid,
263
+ b2.cid
264
+ ]
265
+ });
266
+ writer.write(b1);
267
+ writer.write(b2);
268
+ const bytes = writer.close();
269
+ const reader$1 = await reader.CarReader.fromBytes(bytes);
270
+ common.assert.deepEqual(await reader$1.getRoots(), [
271
+ b1.cid,
272
+ b2.cid
273
+ ]);
274
+ common.assert.deepEqual(reader$1._blocks, [
275
+ {
276
+ cid: b1.cid,
277
+ bytes: b1.bytes
278
+ },
279
+ {
280
+ cid: b2.cid,
281
+ bytes: b2.bytes
282
+ }
283
+ ]);
284
+ });
285
+ it('provide large CID root', async () => {
286
+ const bytes = new Uint8Array(512).fill(1);
287
+ const b1 = await Block__namespace.encode({
288
+ value: { hello: 'world' },
289
+ codec: CBOR__namespace,
290
+ hasher: sha2.sha256
291
+ });
292
+ const b2 = {
293
+ cid: multiformats.CID.createV1(raw__namespace.code, identity.identity.digest(bytes)),
294
+ bytes
295
+ };
296
+ const headerSize = CBOR__namespace.encode({
297
+ version: 1,
298
+ roots: [
299
+ b1.cid,
300
+ b2.cid
301
+ ]
302
+ }).byteLength;
303
+ const bodySize = bufferWriter.blockLength(b1) + bufferWriter.blockLength(b2);
304
+ const varintSize = multiformats.varint.encodingLength(headerSize);
305
+ const writer = bufferWriter.createWriter(new ArrayBuffer(varintSize + headerSize + bodySize), {
306
+ roots: [
307
+ b1.cid,
308
+ b2.cid
309
+ ]
310
+ });
311
+ writer.write(b1);
312
+ writer.write(b2);
313
+ const car = writer.close();
314
+ const reader$1 = await reader.CarReader.fromBytes(car);
315
+ common.assert.deepEqual(await reader$1.getRoots(), [
316
+ b1.cid,
317
+ b2.cid
318
+ ]);
319
+ common.assert.deepEqual(reader$1._blocks, [
320
+ {
321
+ cid: b1.cid,
322
+ bytes: b1.bytes
323
+ },
324
+ {
325
+ cid: b2.cid,
326
+ bytes: b2.bytes
327
+ }
328
+ ]);
329
+ });
330
+ });
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  var multiformats = require('multiformats');
4
- var dagCbor = require('@ipld/dag-cbor');
4
+ var CBOR = require('@ipld/dag-cbor');
5
5
  var varint = require('varint');
6
6
  var reader = require('../lib/reader.js');
7
7
  var common = require('./common.js');
8
8
 
9
9
  function makeHeader(block) {
10
- const u = dagCbor.encode(block);
10
+ const u = CBOR.encode(block);
11
11
  const l = varint.encode(u.length);
12
12
  const u2 = new Uint8Array(u.length + l.length);
13
13
  u2.set(l, 0);
@@ -26,42 +26,65 @@ describe('Misc errors', () => {
26
26
  });
27
27
  });
28
28
  it('bad version', async () => {
29
- const buf2 = multiformats.bytes.fromHex('0aa16776657273696f6e02');
30
- common.assert.strictEqual(multiformats.bytes.toHex(makeHeader({ version: 2 })), '0aa16776657273696f6e02');
31
- await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR version: 2');
29
+ const buf2 = multiformats.bytes.fromHex('0aa16776657273696f6e03');
30
+ common.assert.strictEqual(multiformats.bytes.toHex(makeHeader({ version: 3 })), '0aa16776657273696f6e03');
31
+ await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR version: 3');
32
32
  });
33
- it('bad header', async () => {
34
- let buf2 = makeHeader({
35
- version: 1,
36
- roots: []
33
+ describe('bad header', async () => {
34
+ it('sanity check', async () => {
35
+ const buf2 = makeHeader({
36
+ version: 1,
37
+ roots: []
38
+ });
39
+ await common.assert.isFulfilled(reader.CarReader.fromBytes(buf2));
37
40
  });
38
- await common.assert.isFulfilled(reader.CarReader.fromBytes(buf2));
39
- buf2 = makeHeader({ roots: [] });
40
- await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR version: undefined');
41
- buf2 = makeHeader({
42
- version: '1',
43
- roots: []
41
+ it('no \'version\' array', async () => {
42
+ const buf2 = makeHeader({ roots: [] });
43
+ await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
44
44
  });
45
- await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR version: "1"');
46
- buf2 = makeHeader({ version: 1 });
47
- await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
48
- buf2 = makeHeader({
49
- version: 1,
50
- roots: {}
45
+ it('bad \'version\' type', async () => {
46
+ const buf2 = makeHeader({
47
+ version: '1',
48
+ roots: []
49
+ });
50
+ await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
51
51
  });
52
- await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
53
- buf2 = makeHeader({
54
- version: 1,
55
- roots: [],
56
- blip: true
52
+ it('no \'roots\' array', async () => {
53
+ const buf2 = makeHeader({ version: 1 });
54
+ await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
55
+ });
56
+ it('bad \'roots\' type', async () => {
57
+ const buf2 = makeHeader({
58
+ version: 1,
59
+ roots: {}
60
+ });
61
+ await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
62
+ });
63
+ it('extraneous properties', async () => {
64
+ const buf2 = makeHeader({
65
+ version: 1,
66
+ roots: [],
67
+ blip: true
68
+ });
69
+ await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
70
+ });
71
+ it('not an object', async () => {
72
+ const buf2 = makeHeader([
73
+ 1,
74
+ []
75
+ ]);
76
+ await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
77
+ });
78
+ it('not an object', async () => {
79
+ const buf2 = makeHeader(null);
80
+ await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
81
+ });
82
+ it('recursive v2 header', async () => {
83
+ const v2Header = common.goCarV2Bytes.slice(0, 51);
84
+ const buf2 = new Uint8Array(51 * 2);
85
+ buf2.set(v2Header, 0);
86
+ buf2.set(v2Header, 51);
87
+ await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR version: 2 (expected 1)');
57
88
  });
58
- await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
59
- buf2 = makeHeader([
60
- 1,
61
- []
62
- ]);
63
- await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
64
- buf2 = makeHeader(null);
65
- await common.assert.isRejected(reader.CarReader.fromBytes(buf2), Error, 'Invalid CAR header format');
66
89
  });
67
90
  });
@@ -15,6 +15,18 @@ describe('CarIndexer fromBytes()', () => {
15
15
  }
16
16
  common.assert.deepStrictEqual(indexData, common.goCarIndex);
17
17
  });
18
+ it('v2 complete', async () => {
19
+ const indexer$1 = await indexer.CarIndexer.fromBytes(common.goCarV2Bytes);
20
+ const roots = await indexer$1.getRoots();
21
+ common.assert.strictEqual(roots.length, 1);
22
+ common.assert.ok(common.goCarV2Roots[0].equals(roots[0]));
23
+ common.assert.strictEqual(indexer$1.version, 2);
24
+ const indexData = [];
25
+ for await (const index of indexer$1) {
26
+ indexData.push(index);
27
+ }
28
+ common.assert.deepStrictEqual(indexData, common.goCarV2Index);
29
+ });
18
30
  it('bad argument', async () => {
19
31
  for (const arg of [
20
32
  true,
@@ -2,11 +2,16 @@
2
2
 
3
3
  var reader = require('../lib/reader.js');
4
4
  var writer = require('../lib/writer.js');
5
+ var decoder = require('../lib/decoder.js');
5
6
  var Block = require('multiformats/block');
6
7
  var sha2 = require('multiformats/hashes/sha2');
7
8
  var raw = require('multiformats/codecs/raw');
9
+ var base64 = require('multiformats/bases/base64');
10
+ var dagPb = require('@ipld/dag-pb');
8
11
  var common = require('./common.js');
9
12
  var verifyStoreReader = require('./verify-store-reader.js');
13
+ var fixtures = require('./fixtures.js');
14
+ var fixturesExpectations = require('./fixtures-expectations.js');
10
15
 
11
16
  function _interopNamespace(e) {
12
17
  if (e && e.__esModule) return e;
@@ -28,6 +33,7 @@ function _interopNamespace(e) {
28
33
 
29
34
  var Block__namespace = /*#__PURE__*/_interopNamespace(Block);
30
35
  var raw__namespace = /*#__PURE__*/_interopNamespace(raw);
36
+ var dagPb__namespace = /*#__PURE__*/_interopNamespace(dagPb);
31
37
 
32
38
  describe('CarReader fromBytes()', () => {
33
39
  it('complete', async () => {
@@ -66,6 +72,29 @@ describe('CarReader fromBytes()', () => {
66
72
  message: 'Unexpected end of data'
67
73
  });
68
74
  });
75
+ it('v2 complete', async () => {
76
+ const reader$1 = await reader.CarReader.fromBytes(common.goCarV2Bytes);
77
+ const roots = await reader$1.getRoots();
78
+ common.assert.strictEqual(roots.length, 1);
79
+ common.assert.ok(common.goCarV2Roots[0].equals(roots[0]));
80
+ common.assert.strictEqual(reader$1.version, 2);
81
+ for (const {cid} of common.goCarV2Index) {
82
+ const block = await reader$1.get(cid);
83
+ common.assert.isDefined(block);
84
+ if (block) {
85
+ common.assert.ok(cid.equals(block.cid));
86
+ let content;
87
+ if (cid.code === dagPb__namespace.code) {
88
+ content = dagPb__namespace.decode(block.bytes);
89
+ } else if (cid.code === 85) {
90
+ content = new TextDecoder().decode(block.bytes);
91
+ } else {
92
+ common.assert.fail('Unexpected codec');
93
+ }
94
+ common.assert.deepStrictEqual(content, common.goCarV2Contents[cid.toString()]);
95
+ }
96
+ }
97
+ });
69
98
  it('decode error - trailing null bytes', async () => {
70
99
  const bytes = new Uint8Array(common.carBytes.length + 5);
71
100
  bytes.set(common.carBytes);
@@ -192,4 +221,58 @@ describe('CarReader fromIterable()', () => {
192
221
  message: 'Unexpected end of data'
193
222
  });
194
223
  });
224
+ it('v2 decode error - truncated', async () => {
225
+ const bytes = common.goCarV2Bytes.slice();
226
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
227
+ dv.setBigUint64(35, BigInt(448 - 10), true);
228
+ await common.assert.isRejected(reader.CarReader.fromIterable(common.makeIterable(bytes, 64)), {
229
+ name: 'Error',
230
+ message: 'Unexpected end of data'
231
+ });
232
+ });
233
+ });
234
+ describe('Shared fixtures', () => {
235
+ describe('Header', () => {
236
+ for (const [name, {
237
+ version: expectedVersion,
238
+ err: expectedError
239
+ }] of Object.entries(fixturesExpectations.expectations)) {
240
+ it(name, async () => {
241
+ const data = base64.base64.baseDecode(fixtures.data[name]);
242
+ let header;
243
+ try {
244
+ header = await decoder.readHeader(decoder.bytesReader(data));
245
+ } catch (err) {
246
+ if (expectedError != null) {
247
+ common.assert.equal(err.message, expectedError);
248
+ return;
249
+ }
250
+ common.assert.ifError(err);
251
+ }
252
+ if (expectedError != null) {
253
+ common.assert.fail(`Expected error: ${ expectedError }`);
254
+ }
255
+ common.assert.isDefined(header, 'did not decode header');
256
+ if (expectedVersion != null && header != null) {
257
+ common.assert.strictEqual(header.version, expectedVersion);
258
+ }
259
+ });
260
+ }
261
+ });
262
+ describe('Contents', () => {
263
+ for (const [name, {cids: expectedCids}] of Object.entries(fixturesExpectations.expectations)) {
264
+ if (expectedCids == null) {
265
+ continue;
266
+ }
267
+ it(name, async () => {
268
+ const data = base64.base64.baseDecode(fixtures.data[name]);
269
+ const reader$1 = await reader.CarReader.fromBytes(data);
270
+ let i = 0;
271
+ for await (const cid of reader$1.cids()) {
272
+ common.assert.strictEqual(cid.toString(), expectedCids[i++]);
273
+ }
274
+ common.assert.strictEqual(i, expectedCids.length);
275
+ });
276
+ }
277
+ });
195
278
  });
@@ -182,9 +182,9 @@ describe('CarWriter', () => {
182
182
  const rawBytes = await append(0);
183
183
  const pbBytes = await append(1);
184
184
  const cborBytes = await append(2);
185
- common.assert(rawBytes.length > 0);
186
- common.assert(pbBytes.length > 0);
187
- common.assert(cborBytes.length > 0);
185
+ common.assert.ok(rawBytes.length > 0);
186
+ common.assert.ok(pbBytes.length > 0);
187
+ common.assert.ok(cborBytes.length > 0);
188
188
  const reassembled = concatBytes([
189
189
  headerBytes,
190
190
  rawBytes,
@@ -186,6 +186,77 @@ const goCarIndex = [
186
186
  blockLength: 18
187
187
  }
188
188
  ];
189
+ const goCarV2Bytes = bytes.fromHex('0aa16776657273696f6e02000000000000000000000000000000003300000000000000c001000000000000f30100000000000038a265726f6f747381d82a5823001220fb16f5083412ef1371d031ed4aa239903d84efdadf1ba3cd678e6475b1a232f86776657273696f6e01511220fb16f5083412ef1371d031ed4aa239903d84efdadf1ba3cd678e6475b1a232f8122d0a221220d9c0d5376d26f1931f7ad52d7acc00fc1090d2edb0808bf61eeb0a152826f6261204f09f8da418a40185011220d9c0d5376d26f1931f7ad52d7acc00fc1090d2edb0808bf61eeb0a152826f62612310a221220d745b7757f5b4593eeab7820306c7bc64eb496a7410a0d07df7a34ffec4b97f1120962617272656c657965183a122e0a2401551220a2e1c40da1ae335d4dffe729eb4d5ca23b74b9e51fc535f4a804a261080c294d1204f09f90a11807581220d745b7757f5b4593eeab7820306c7bc64eb496a7410a0d07df7a34ffec4b97f112340a2401551220b474a99a2705e23cf905a484ec6d14ef58b56bbe62e9292783466ec363b5072d120a666973686d6f6e67657218042801551220b474a99a2705e23cf905a484ec6d14ef58b56bbe62e9292783466ec363b5072d666973682b01551220a2e1c40da1ae335d4dffe729eb4d5ca23b74b9e51fc535f4a804a261080c294d6c6f62737465720100000028000000c800000000000000a2e1c40da1ae335d4dffe729eb4d5ca23b74b9e51fc535f4a804a261080c294d9401000000000000b474a99a2705e23cf905a484ec6d14ef58b56bbe62e9292783466ec363b5072d6b01000000000000d745b7757f5b4593eeab7820306c7bc64eb496a7410a0d07df7a34ffec4b97f11201000000000000d9c0d5376d26f1931f7ad52d7acc00fc1090d2edb0808bf61eeb0a152826f6268b00000000000000fb16f5083412ef1371d031ed4aa239903d84efdadf1ba3cd678e6475b1a232f83900000000000000');
190
+ const goCarV2Roots = [CID.parse('QmfEoLyB5NndqeKieExd1rtJzTduQUPEV8TwAYcUiy3H5Z')];
191
+ const goCarV2Index = [
192
+ {
193
+ blockLength: 47,
194
+ blockOffset: 143,
195
+ cid: CID.parse('QmfEoLyB5NndqeKieExd1rtJzTduQUPEV8TwAYcUiy3H5Z'),
196
+ length: 82,
197
+ offset: 108
198
+ },
199
+ {
200
+ blockLength: 99,
201
+ blockOffset: 226,
202
+ cid: CID.parse('QmczfirA7VEH7YVvKPTPoU69XM3qY4DC39nnTsWd4K3SkM'),
203
+ length: 135,
204
+ offset: 190
205
+ },
206
+ {
207
+ blockLength: 54,
208
+ blockOffset: 360,
209
+ cid: CID.parse('Qmcpz2FHJD7VAhg1fxFXdYJKePtkx1BsHuCrAgWVnaHMTE'),
210
+ length: 89,
211
+ offset: 325
212
+ },
213
+ {
214
+ blockLength: 4,
215
+ blockOffset: 451,
216
+ cid: CID.parse('bafkreifuosuzujyf4i6psbneqtwg2fhplc2wxptc5euspa2gn3bwhnihfu'),
217
+ length: 41,
218
+ offset: 414
219
+ },
220
+ {
221
+ blockLength: 7,
222
+ blockOffset: 492,
223
+ cid: CID.parse('bafkreifc4hca3inognou377hfhvu2xfchn2ltzi7yu27jkaeujqqqdbjju'),
224
+ length: 44,
225
+ offset: 455
226
+ }
227
+ ];
228
+ const goCarV2Contents = {
229
+ QmfEoLyB5NndqeKieExd1rtJzTduQUPEV8TwAYcUiy3H5Z: {
230
+ Links: [{
231
+ Hash: CID.parse('QmczfirA7VEH7YVvKPTPoU69XM3qY4DC39nnTsWd4K3SkM'),
232
+ Name: '\uD83C\uDF64',
233
+ Tsize: 164
234
+ }]
235
+ },
236
+ QmczfirA7VEH7YVvKPTPoU69XM3qY4DC39nnTsWd4K3SkM: {
237
+ Links: [
238
+ {
239
+ Hash: CID.parse('Qmcpz2FHJD7VAhg1fxFXdYJKePtkx1BsHuCrAgWVnaHMTE'),
240
+ Name: 'barreleye',
241
+ Tsize: 58
242
+ },
243
+ {
244
+ Hash: CID.parse('bafkreifc4hca3inognou377hfhvu2xfchn2ltzi7yu27jkaeujqqqdbjju'),
245
+ Name: '\uD83D\uDC21',
246
+ Tsize: 7
247
+ }
248
+ ]
249
+ },
250
+ Qmcpz2FHJD7VAhg1fxFXdYJKePtkx1BsHuCrAgWVnaHMTE: {
251
+ Links: [{
252
+ Hash: CID.parse('bafkreifuosuzujyf4i6psbneqtwg2fhplc2wxptc5euspa2gn3bwhnihfu'),
253
+ Name: 'fishmonger',
254
+ Tsize: 4
255
+ }]
256
+ },
257
+ bafkreifuosuzujyf4i6psbneqtwg2fhplc2wxptc5euspa2gn3bwhnihfu: 'fish',
258
+ bafkreifc4hca3inognou377hfhvu2xfchn2ltzi7yu27jkaeujqqqdbjju: 'lobster'
259
+ };
189
260
  export {
190
261
  toBlock,
191
262
  assert,
@@ -195,5 +266,9 @@ export {
195
266
  carBytes,
196
267
  goCarBytes,
197
268
  goCarRoots,
198
- goCarIndex
269
+ goCarIndex,
270
+ goCarV2Bytes,
271
+ goCarV2Roots,
272
+ goCarV2Index,
273
+ goCarV2Contents
199
274
  };