@ipld/car 5.0.2 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,116 @@
1
+ /**
2
+ * @typedef {import('multiformats').CID} CID
3
+ * @typedef {import('./api').Block} Block
4
+ * @typedef {import('./api').CarBufferReader} ICarBufferReader
5
+ * @typedef {import('./coding').CarHeader} CarHeader
6
+ * @typedef {import('./coding').CarV2Header} CarV2Header
7
+ */
8
+ /**
9
+ * Provides blockstore-like access to a CAR.
10
+ *
11
+ * Implements the `RootsBufferReader` interface:
12
+ * {@link ICarBufferReader.getRoots `getRoots()`}. And the `BlockBufferReader` interface:
13
+ * {@link ICarBufferReader.get `get()`}, {@link ICarBufferReader.has `has()`},
14
+ * {@link ICarBufferReader.blocks `blocks()`} and
15
+ * {@link ICarBufferReader.cids `cids()`}.
16
+ *
17
+ * Load this class with either `import { CarBufferReader } from '@ipld/car/buffer-reader'`
18
+ * (`const { CarBufferReader } = require('@ipld/car/buffer-reader')`). Or
19
+ * `import { CarBufferReader } from '@ipld/car'` (`const { CarBufferReader } = require('@ipld/car')`).
20
+ * The former will likely result in smaller bundle sizes where this is
21
+ * important.
22
+ *
23
+ * @name CarBufferReader
24
+ * @class
25
+ * @implements {ICarBufferReader}
26
+ * @property {number} version The version number of the CAR referenced by this
27
+ * reader (should be `1` or `2`).
28
+ */
29
+ export class CarBufferReader implements ICarBufferReader {
30
+ /**
31
+ * Instantiate a {@link CarBufferReader} from a `Uint8Array` blob. This performs a
32
+ * decode fully in memory and maintains the decoded state in memory for full
33
+ * access to the data via the `CarReader` API.
34
+ *
35
+ * @static
36
+ * @memberof CarBufferReader
37
+ * @param {Uint8Array} bytes
38
+ * @returns {CarBufferReader}
39
+ */
40
+ static fromBytes(bytes: Uint8Array): CarBufferReader;
41
+ /**
42
+ * @constructs CarBufferReader
43
+ * @param {CarHeader|CarV2Header} header
44
+ * @param {Block[]} blocks
45
+ */
46
+ constructor(header: CarHeader | CarV2Header, blocks: Block[]);
47
+ _header: import("./coding").CarHeader | import("./coding").CarV2Header;
48
+ _blocks: import("./api").Block[];
49
+ _cids: import("multiformats").CID<unknown, number, number, import("multiformats").Version>[] | undefined;
50
+ /**
51
+ * @property version
52
+ * @memberof CarBufferReader
53
+ * @instance
54
+ */
55
+ get version(): 1 | 2;
56
+ /**
57
+ * Get the list of roots defined by the CAR referenced by this reader. May be
58
+ * zero or more `CID`s.
59
+ *
60
+ * @function
61
+ * @memberof CarBufferReader
62
+ * @instance
63
+ * @returns {CID[]}
64
+ */
65
+ getRoots(): CID[];
66
+ /**
67
+ * Check whether a given `CID` exists within the CAR referenced by this
68
+ * reader.
69
+ *
70
+ * @function
71
+ * @memberof CarBufferReader
72
+ * @instance
73
+ * @param {CID} key
74
+ * @returns {boolean}
75
+ */
76
+ has(key: CID): boolean;
77
+ /**
78
+ * Fetch a `Block` (a `{ cid:CID, bytes:Uint8Array }` pair) from the CAR
79
+ * referenced by this reader matching the provided `CID`. In the case where
80
+ * the provided `CID` doesn't exist within the CAR, `undefined` will be
81
+ * returned.
82
+ *
83
+ * @function
84
+ * @memberof CarBufferReader
85
+ * @instance
86
+ * @param {CID} key
87
+ * @returns {Block | undefined}
88
+ */
89
+ get(key: CID): Block | undefined;
90
+ /**
91
+ * Returns a `Block[]` of the `Block`s (`{ cid:CID, bytes:Uint8Array }` pairs) contained within
92
+ * the CAR referenced by this reader.
93
+ *
94
+ * @function
95
+ * @memberof CarBufferReader
96
+ * @instance
97
+ * @returns {Block[]}
98
+ */
99
+ blocks(): Block[];
100
+ /**
101
+ * Returns a `CID[]` of the `CID`s contained within the CAR referenced by this reader.
102
+ *
103
+ * @function
104
+ * @memberof CarBufferReader
105
+ * @instance
106
+ * @returns {CID[]}
107
+ */
108
+ cids(): CID[];
109
+ }
110
+ export const __browser: true;
111
+ export type CID = import('multiformats').CID;
112
+ export type Block = import('./api').Block;
113
+ export type ICarBufferReader = import('./api').CarBufferReader;
114
+ export type CarHeader = import('./coding').CarHeader;
115
+ export type CarV2Header = import('./coding').CarV2Header;
116
+ //# sourceMappingURL=buffer-reader-browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer-reader-browser.d.ts","sourceRoot":"","sources":["../../src/buffer-reader-browser.js"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;IAkGE;;;;;;;;;OASG;IACH,wBAHW,UAAU,GACR,eAAe,CAS3B;IAlHD;;;;OAIG;IACH,oBAHW,SAAS,GAAC,WAAW,UACrB,KAAK,EAAE,EAMjB;IAHC,uEAAqB;IACrB,iCAAqB;IACrB,yGAAsB;IAGxB;;;;OAIG;IACH,qBAEC;IAED;;;;;;;;OAQG;IACH,YAFa,GAAG,EAAE,CAMjB;IAED;;;;;;;;;OASG;IACH,SAHW,GAAG,GACD,OAAO,CAMnB;IAED;;;;;;;;;;;OAWG;IACH,SAHW,GAAG,GACD,KAAK,GAAG,SAAS,CAM7B;IAED;;;;;;;;OAQG;IACH,UAFa,KAAK,EAAE,CAInB;IAED;;;;;;;OAOG;IACH,QAFa,GAAG,EAAE,CAOjB;CAoBF;AAED,6BAA6B;kBAlJhB,OAAO,cAAc,EAAE,GAAG;oBAC1B,OAAO,OAAO,EAAE,KAAK;+BACrB,OAAO,OAAO,EAAE,eAAe;wBAC/B,OAAO,UAAU,EAAE,SAAS;0BAC5B,OAAO,UAAU,EAAE,WAAW"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @class
3
+ * @implements {ICarBufferReader}
4
+ */
5
+ export class CarBufferReader extends BrowserCarBufferReader implements ICarBufferReader {
6
+ /**
7
+ * Reads a block directly from a file descriptor for an open CAR file. This
8
+ * function is **only available in Node.js** and not a browser environment.
9
+ *
10
+ * This function can be used in connection with {@link CarIndexer} which emits
11
+ * the `BlockIndex` objects that are required by this function.
12
+ *
13
+ * The user is responsible for opening and closing the file used in this call.
14
+ *
15
+ * @static
16
+ * @memberof CarBufferReader
17
+ * @param {number} fd - A file descriptor from the
18
+ * Node.js `fs` module. An integer, from `fs.open()`.
19
+ * @param {BlockIndex} blockIndex - An index pointing to the location of the
20
+ * Block required. This `BlockIndex` should take the form:
21
+ * `{cid:CID, blockLength:number, blockOffset:number}`.
22
+ * @returns {Block} A `{ cid:CID, bytes:Uint8Array }` pair.
23
+ */
24
+ static readRaw(fd: number, blockIndex: BlockIndex): Block;
25
+ }
26
+ export const __browser: false;
27
+ export type Block = import('./api').Block;
28
+ export type BlockIndex = import('./api').BlockIndex;
29
+ export type ICarBufferReader = import('./api').CarBufferReader;
30
+ import { CarBufferReader as BrowserCarBufferReader } from "./buffer-reader-browser.js";
31
+ //# sourceMappingURL=buffer-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffer-reader.d.ts","sourceRoot":"","sources":["../../src/buffer-reader.js"],"names":[],"mappings":"AAWA;;;GAGG;AACH;IACE;;;;;;;;;;;;;;;;;OAiBG;IACH,mBAPW,MAAM,cAEN,UAAU,GAGR,KAAK,CAiBjB;CACF;AAED,8BAA8B;oBAhDjB,OAAO,OAAO,EAAE,KAAK;yBACrB,OAAO,OAAO,EAAE,UAAU;+BAC1B,OAAO,OAAO,EAAE,eAAe"}
@@ -32,10 +32,17 @@ export interface CarDecoder {
32
32
  blocks: () => AsyncGenerator<Block>;
33
33
  blocksIndex: () => AsyncGenerator<BlockIndex>;
34
34
  }
35
- export interface BytesReader {
36
- upTo: (length: number) => Promise<Uint8Array>;
37
- exactly: (length: number) => Promise<Uint8Array>;
35
+ export interface Seekable {
38
36
  seek: (length: number) => void;
37
+ }
38
+ export interface BytesReader extends Seekable {
39
+ upTo: (length: number) => Promise<Uint8Array>;
40
+ exactly: (length: number, seek?: boolean) => Promise<Uint8Array>;
41
+ pos: number;
42
+ }
43
+ export interface BytesBufferReader extends Seekable {
44
+ upTo: (length: number) => Uint8Array;
45
+ exactly: (length: number, seek?: boolean) => Uint8Array;
39
46
  pos: number;
40
47
  }
41
48
  //# sourceMappingURL=coding.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coding.d.ts","sourceRoot":"","sources":["../../src/coding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAEjD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzC,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3C,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B;AAED,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC,CAAA;IAEjC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,CAAC,CAAA;IACV,KAAK,EAAE,GAAG,EAAE,CAAA;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,WAAY,SAAQ,gBAAgB;IACnD,OAAO,EAAE,CAAC,CAAA;IACV,KAAK,EAAE,GAAG,EAAE,CAAA;CACb;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,OAAO,CAAC,SAAS,GAAC,WAAW,CAAC,CAAA;IAE5C,MAAM,EAAE,MAAM,cAAc,CAAC,KAAK,CAAC,CAAA;IAEnC,WAAW,EAAE,MAAM,cAAc,CAAC,UAAU,CAAC,CAAA;CAC9C;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;IAE7C,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;IAEhD,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAE9B,GAAG,EAAE,MAAM,CAAA;CACZ"}
1
+ {"version":3,"file":"coding.d.ts","sourceRoot":"","sources":["../../src/coding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAEjD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzC,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3C,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B;AAED,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,MAAM,EAAE,sBAAsB,CAAC,CAAC,CAAC,CAAA;IAEjC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,CAAC,CAAA;IACV,KAAK,EAAE,GAAG,EAAE,CAAA;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,WAAY,SAAQ,gBAAgB;IACnD,OAAO,EAAE,CAAC,CAAA;IACV,KAAK,EAAE,GAAG,EAAE,CAAA;CACb;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,OAAO,CAAC,SAAS,GAAC,WAAW,CAAC,CAAA;IAE5C,MAAM,EAAE,MAAM,cAAc,CAAC,KAAK,CAAC,CAAA;IAEnC,WAAW,EAAE,MAAM,cAAc,CAAC,UAAU,CAAC,CAAA;CAC9C;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;CAC/B;AAED,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;IAE7C,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;IAEhE,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,iBAAkB,SAAQ,QAAQ;IACjD,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,UAAU,CAAA;IAEpC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,UAAU,CAAA;IAEvD,GAAG,EAAE,MAAM,CAAA;CACZ"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Decodes varint and seeks the buffer
3
+ *
4
+ * ```js
5
+ * // needs bytes to be read first
6
+ * const bytes = reader.upTo(8) // maybe async
7
+ * ```
8
+ *
9
+ * @param {Uint8Array} bytes
10
+ * @param {import('./coding').Seekable} seeker
11
+ * @returns {number}
12
+ */
13
+ export function decodeVarint(bytes: Uint8Array, seeker: import('./coding').Seekable): number;
14
+ /**
15
+ * Decode v2 header
16
+ *
17
+ * ```js
18
+ * // needs bytes to be read first
19
+ * const bytes = reader.exactly(V2_HEADER_LENGTH, true) // maybe async
20
+ * ```
21
+ *
22
+ * @param {Uint8Array} bytes
23
+ * @returns {import('./coding').CarV2FixedHeader}
24
+ */
25
+ export function decodeV2Header(bytes: Uint8Array): import('./coding').CarV2FixedHeader;
26
+ /**
27
+ * Checks the length of the multihash to be read afterwards
28
+ *
29
+ * ```js
30
+ * // needs bytes to be read first
31
+ * const bytes = reader.upTo(8) // maybe async
32
+ * ```
33
+ *
34
+ * @param {Uint8Array} bytes
35
+ */
36
+ export function getMultihashLength(bytes: Uint8Array): number;
37
+ export namespace CIDV0_BYTES {
38
+ const SHA2_256: number;
39
+ const LENGTH: number;
40
+ const DAG_PB: number;
41
+ }
42
+ export const V2_HEADER_LENGTH: number;
43
+ //# sourceMappingURL=decoder-common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decoder-common.d.ts","sourceRoot":"","sources":["../../src/decoder-common.js"],"names":[],"mappings":"AAUA;;;;;;;;;;;GAWG;AACH,oCAJW,UAAU,UACV,OAAO,UAAU,EAAE,QAAQ,GACzB,MAAM,CAWlB;AAED;;;;;;;;;;GAUG;AACH,sCAHW,UAAU,GACR,OAAO,UAAU,EAAE,gBAAgB,CAmB/C;AAED;;;;;;;;;GASG;AACH,0CAFW,UAAU,UAcpB;;;;;;AA7ED,sCAAqH"}
@@ -1,3 +1,13 @@
1
+ /**
2
+ * @typedef {import('./api').Block} Block
3
+ * @typedef {import('./api').BlockHeader} BlockHeader
4
+ * @typedef {import('./api').BlockIndex} BlockIndex
5
+ * @typedef {import('./coding').BytesReader} BytesReader
6
+ * @typedef {import('./coding').CarHeader} CarHeader
7
+ * @typedef {import('./coding').CarV2Header} CarV2Header
8
+ * @typedef {import('./coding').CarV2FixedHeader} CarV2FixedHeader
9
+ * @typedef {import('./coding').CarDecoder} CarDecoder
10
+ */
1
11
  /**
2
12
  * Reads header data from a `BytesReader`. The header may either be in the form
3
13
  * of a `CarHeader` or `CarV2Header` depending on the CAR being read.
@@ -1 +1 @@
1
- {"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../src/decoder.js"],"names":[],"mappings":"AAmEA;;;;;;;;GAQG;AACH,mCAJW,WAAW,uCAET,QAAQ,SAAS,GAAC,WAAW,CAAC,CAgC1C;AAkDD;;;;;;;;;GASG;AACH,sCAHW,WAAW,GACT,QAAQ,WAAW,CAAC,CAiBhC;AA6BD;;;;;;;;GAQG;AACH,sCAHW,WAAW,GACT,UAAU,CA+BtB;AAED;;;;;;GAMG;AACH,mCAHW,UAAU,GACR,WAAW,CA8BvB;AAED;;;;;;;GAOG;AACH,uCAHW,MAAM,QAAQ,UAAU,GAAC,IAAI,CAAC,GAC5B,WAAW,CAsEvB;AAED;;;;;;;GAOG;AACH,mDAHW,cAAc,UAAU,CAAC,GACvB,WAAW,CAgBvB;AAED;;;;;;;;;GASG;AACH,oCAJW,WAAW,aACX,MAAM,GACJ,WAAW,CAoCvB;oBA1aY,OAAO,OAAO,EAAE,KAAK;0BACrB,OAAO,OAAO,EAAE,WAAW;yBAC3B,OAAO,OAAO,EAAE,UAAU;0BAC1B,OAAO,UAAU,EAAE,WAAW;wBAC9B,OAAO,UAAU,EAAE,SAAS;0BAC5B,OAAO,UAAU,EAAE,WAAW;+BAC9B,OAAO,UAAU,EAAE,gBAAgB;yBACnC,OAAO,UAAU,EAAE,UAAU"}
1
+ {"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../src/decoder.js"],"names":[],"mappings":"AAMA;;;;;;;;;GASG;AAEH;;;;;;;;GAQG;AACH,mCAJW,WAAW,uCAET,QAAQ,SAAS,GAAC,WAAW,CAAC,CA+B1C;AA2BD;;;;;;;;;GASG;AACH,sCAHW,WAAW,GACT,QAAQ,WAAW,CAAC,CAiBhC;AA4BD;;;;;;;;GAQG;AACH,sCAHW,WAAW,GACT,UAAU,CA+BtB;AAED;;;;;;GAMG;AACH,mCAHW,UAAU,GACR,WAAW,CAmCvB;AAED;;;;;;;GAOG;AACH,uCAHW,MAAM,QAAQ,UAAU,GAAC,IAAI,CAAC,GAC5B,WAAW,CA2EvB;AAED;;;;;;;GAOG;AACH,mDAHW,cAAc,UAAU,CAAC,GACvB,WAAW,CAgBvB;AAED;;;;;;;;;GASG;AACH,oCAJW,WAAW,aACX,MAAM,GACJ,WAAW,CAuCvB;oBA5WY,OAAO,OAAO,EAAE,KAAK;0BACrB,OAAO,OAAO,EAAE,WAAW;yBAC3B,OAAO,OAAO,EAAE,UAAU;0BAC1B,OAAO,UAAU,EAAE,WAAW;wBAC9B,OAAO,UAAU,EAAE,SAAS;0BAC5B,OAAO,UAAU,EAAE,WAAW;+BAC9B,OAAO,UAAU,EAAE,gBAAgB;yBACnC,OAAO,UAAU,EAAE,UAAU"}
@@ -1,9 +1,10 @@
1
1
  import { CarReader } from "./reader.js";
2
+ import { CarBufferReader } from "./buffer-reader.js";
2
3
  import { CarIndexer } from "./indexer.js";
3
4
  import { CarBlockIterator } from "./iterator.js";
4
5
  import { CarCIDIterator } from "./iterator.js";
5
6
  import { CarWriter } from "./writer.js";
6
7
  import { CarIndexedReader } from "./indexed-reader.js";
7
8
  import * as CarBufferWriter from "./buffer-writer.js";
8
- export { CarReader, CarIndexer, CarBlockIterator, CarCIDIterator, CarWriter, CarIndexedReader, CarBufferWriter };
9
+ export { CarReader, CarBufferReader, CarIndexer, CarBlockIterator, CarCIDIterator, CarWriter, CarIndexedReader, CarBufferWriter };
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -43,7 +43,7 @@ export class CarReader implements CarReaderIface {
43
43
  * @static
44
44
  * @memberof CarReader
45
45
  * @param {Uint8Array} bytes
46
- * @returns {Promise<CarReader>} blip blop
46
+ * @returns {Promise<CarReader>}
47
47
  */
48
48
  static fromBytes(bytes: Uint8Array): Promise<CarReader>;
49
49
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ipld/car",
3
- "version": "5.0.2",
3
+ "version": "5.1.0",
4
4
  "description": "Content Addressable aRchive format reader and writer",
5
5
  "author": "Rod <rod@vagg.org> (http://r.va.gg/)",
6
6
  "license": "Apache-2.0 OR MIT",
@@ -78,6 +78,11 @@
78
78
  "browser": "./src/reader-browser.js",
79
79
  "import": "./src/reader.js"
80
80
  },
81
+ "./buffer-reader": {
82
+ "types": "./dist/src/buffer-reader-browser.d.ts",
83
+ "browser": "./src/buffer-reader-browser.js",
84
+ "import": "./src/buffer-reader.js"
85
+ },
81
86
  "./writer": {
82
87
  "types": "./dist/src/writer.d.ts",
83
88
  "browser": "./src/writer-browser.js",
@@ -190,7 +195,7 @@
190
195
  "test:examples": "npm run test --prefix examples/",
191
196
  "dep-check": "aegir dep-check",
192
197
  "coverage": "c8 --reporter=html --reporter=text mocha test/test-*.js && npx st -d coverage -p 8888",
193
- "docs": "jsdoc4readme --readme --description-only src/reader*.js src/indexed-reader.js src/iterator.js src/indexer.js src/writer*.js src/buffer-writer.js src/decoder.js"
198
+ "docs": "jsdoc4readme --readme --description-only src/reader*.js src/indexed-reader.js src/iterator.js src/indexer.js src/writer*.js src/buffer-writer.js src/decoder.js src/buffer-reader*.js"
194
199
  },
195
200
  "dependencies": {
196
201
  "@ipld/dag-cbor": "^9.0.0",
@@ -212,6 +217,7 @@
212
217
  "./src/index.js": "./src/index-browser.js",
213
218
  "./src/index-reader.js": "./src/index-reader-browser.js",
214
219
  "./src/reader.js": "./src/reader-browser.js",
220
+ "./src/buffer-reader.js": "./src/buffer-reader-browser.js",
215
221
  "./src/writer.js": "./src/writer-browser.js",
216
222
  "fs": false,
217
223
  "util": false,
package/src/api.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import type { CID } from 'multiformats/cid'
2
2
 
3
+ /**
4
+ * Literally any `Iterable` (async or regular).
5
+ */
6
+ export type AwaitIterable<T> = Iterable<T> | AsyncIterable<T>
7
+
3
8
  export type { CID }
4
9
  /* Generic types for interfacing with block storage */
5
10
 
@@ -24,6 +29,11 @@ export interface RootsReader {
24
29
  getRoots: () => Promise<CID[]>
25
30
  }
26
31
 
32
+ export interface RootsBufferReader {
33
+ version: number
34
+ getRoots: () => CID[]
35
+ }
36
+
27
37
  export interface BlockIterator extends AsyncIterable<Block> {}
28
38
 
29
39
  export interface CIDIterator extends AsyncIterable<CID> {}
@@ -35,6 +45,13 @@ export interface BlockReader {
35
45
  cids: () => CIDIterator
36
46
  }
37
47
 
48
+ export interface BlockBufferReader {
49
+ has: (key: CID) => boolean
50
+ get: (key: CID) => Block | undefined
51
+ blocks: () => Iterable<Block>
52
+ cids: () => Iterable<CID>
53
+ }
54
+
38
55
  export interface BlockWriter {
39
56
  put: (block: Block) => Promise<void>
40
57
  close: () => Promise<void>
@@ -60,6 +77,7 @@ export interface WriterChannel {
60
77
  }
61
78
 
62
79
  export interface CarReader extends BlockReader, RootsReader {}
80
+ export interface CarBufferReader extends BlockBufferReader, RootsBufferReader {}
63
81
 
64
82
  /* Specific implementations for CAR block storage */
65
83
 
@@ -0,0 +1,226 @@
1
+ import { CID } from 'multiformats/cid'
2
+ import * as Digest from 'multiformats/hashes/digest'
3
+ import { decode as decodeDagCbor } from '@ipld/dag-cbor'
4
+ import { CarHeader as headerValidator } from './header-validator.js'
5
+ import { CIDV0_BYTES, decodeV2Header, decodeVarint, getMultihashLength, V2_HEADER_LENGTH } from './decoder-common.js'
6
+
7
+ /**
8
+ * @typedef {import('./api').Block} Block
9
+ * @typedef {import('./api').BlockHeader} BlockHeader
10
+ * @typedef {import('./api').BlockIndex} BlockIndex
11
+ * @typedef {import('./coding').BytesBufferReader} BytesBufferReader
12
+ * @typedef {import('./coding').CarHeader} CarHeader
13
+ * @typedef {import('./coding').CarV2Header} CarV2Header
14
+ * @typedef {import('./coding').CarV2FixedHeader} CarV2FixedHeader
15
+ */
16
+
17
+ /**
18
+ * Reads header data from a `BytesReader`. The header may either be in the form
19
+ * of a `CarHeader` or `CarV2Header` depending on the CAR being read.
20
+ *
21
+ * @name decoder.readHeader(reader)
22
+ * @param {BytesBufferReader} reader
23
+ * @param {number} [strictVersion]
24
+ * @returns {CarHeader | CarV2Header}
25
+ */
26
+ export function readHeader (reader, strictVersion) {
27
+ const length = decodeVarint(reader.upTo(8), reader)
28
+ if (length === 0) {
29
+ throw new Error('Invalid CAR header (zero length)')
30
+ }
31
+ const header = reader.exactly(length, true)
32
+ const block = decodeDagCbor(header)
33
+ if (!headerValidator(block)) {
34
+ throw new Error('Invalid CAR header format')
35
+ }
36
+ if ((block.version !== 1 && block.version !== 2) || (strictVersion !== undefined && block.version !== strictVersion)) {
37
+ throw new Error(`Invalid CAR version: ${block.version}${strictVersion !== undefined ? ` (expected ${strictVersion})` : ''}`)
38
+ }
39
+ // we've made 'roots' optional in the schema so we can do the version check
40
+ // before rejecting the block as invalid if there is no version
41
+ const hasRoots = Array.isArray(block.roots)
42
+ if ((block.version === 1 && !hasRoots) || (block.version === 2 && hasRoots)) {
43
+ throw new Error('Invalid CAR header format')
44
+ }
45
+ if (block.version === 1) {
46
+ return block
47
+ }
48
+ // version 2
49
+ const v2Header = decodeV2Header(reader.exactly(V2_HEADER_LENGTH, true))
50
+ reader.seek(v2Header.dataOffset - reader.pos)
51
+ const v1Header = readHeader(reader, 1)
52
+ return Object.assign(v1Header, v2Header)
53
+ /* c8 ignore next 2 */
54
+ // Node.js 12 c8 bug
55
+ }
56
+
57
+ /**
58
+ * Reads CID sync
59
+ *
60
+ * @param {BytesBufferReader} reader
61
+ * @returns {CID}
62
+ */
63
+ function readCid (reader) {
64
+ const first = reader.exactly(2, false)
65
+ if (first[0] === CIDV0_BYTES.SHA2_256 && first[1] === CIDV0_BYTES.LENGTH) {
66
+ // cidv0 32-byte sha2-256
67
+ const bytes = reader.exactly(34, true)
68
+ const multihash = Digest.decode(bytes)
69
+ return CID.create(0, CIDV0_BYTES.DAG_PB, multihash)
70
+ }
71
+
72
+ const version = decodeVarint(reader.upTo(8), reader)
73
+ if (version !== 1) {
74
+ throw new Error(`Unexpected CID version (${version})`)
75
+ }
76
+ const codec = decodeVarint(reader.upTo(8), reader)
77
+ const bytes = reader.exactly(getMultihashLength(reader.upTo(8)), true)
78
+ const multihash = Digest.decode(bytes)
79
+ return CID.create(version, codec, multihash)
80
+ /* c8 ignore next 2 */
81
+ // Node.js 12 c8 bug
82
+ }
83
+
84
+ /**
85
+ * Reads the leading data of an individual block from CAR data from a
86
+ * `BytesBufferReader`. Returns a `BlockHeader` object which contains
87
+ * `{ cid, length, blockLength }` which can be used to either index the block
88
+ * or read the block binary data.
89
+ *
90
+ * @name async decoder.readBlockHead(reader)
91
+ * @param {BytesBufferReader} reader
92
+ * @returns {BlockHeader}
93
+ */
94
+ export function readBlockHead (reader) {
95
+ // length includes a CID + Binary, where CID has a variable length
96
+ // we have to deal with
97
+ const start = reader.pos
98
+ let length = decodeVarint(reader.upTo(8), reader)
99
+ if (length === 0) {
100
+ throw new Error('Invalid CAR section (zero length)')
101
+ }
102
+ length += (reader.pos - start)
103
+ const cid = readCid(reader)
104
+ const blockLength = length - Number(reader.pos - start) // subtract CID length
105
+
106
+ return { cid, length, blockLength }
107
+ /* c8 ignore next 2 */
108
+ // Node.js 12 c8 bug
109
+ }
110
+
111
+ /**
112
+ * Returns Car header and blocks from a Uint8Array
113
+ *
114
+ * @param {Uint8Array} bytes
115
+ * @returns {{ header : CarHeader | CarV2Header , blocks: Block[]}}
116
+ */
117
+ export function fromBytes (bytes) {
118
+ let reader = bytesReader(bytes)
119
+ const header = readHeader(reader)
120
+ if (header.version === 2) {
121
+ const v1length = reader.pos - header.dataOffset
122
+ reader = limitReader(reader, header.dataSize - v1length)
123
+ }
124
+
125
+ const blocks = []
126
+ while (reader.upTo(8).length > 0) {
127
+ const { cid, blockLength } = readBlockHead(reader)
128
+
129
+ blocks.push({ cid, bytes: reader.exactly(blockLength, true) })
130
+ }
131
+
132
+ return {
133
+ header, blocks
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Creates a `BytesBufferReader` from a `Uint8Array`.
139
+ *
140
+ * @name decoder.bytesReader(bytes)
141
+ * @param {Uint8Array} bytes
142
+ * @returns {BytesBufferReader}
143
+ */
144
+ export function bytesReader (bytes) {
145
+ let pos = 0
146
+
147
+ /** @type {BytesBufferReader} */
148
+ return {
149
+ upTo (length) {
150
+ return bytes.subarray(pos, pos + Math.min(length, bytes.length - pos))
151
+ /* c8 ignore next 2 */
152
+ // Node.js 12 c8 bug
153
+ },
154
+
155
+ exactly (length, seek = false) {
156
+ if (length > bytes.length - pos) {
157
+ throw new Error('Unexpected end of data')
158
+ }
159
+
160
+ const out = bytes.subarray(pos, pos + length)
161
+ if (seek) {
162
+ pos += length
163
+ }
164
+ return out
165
+ /* c8 ignore next 2 */
166
+ // Node.js 12 c8 bug
167
+ },
168
+
169
+ seek (length) {
170
+ pos += length
171
+ },
172
+
173
+ get pos () {
174
+ return pos
175
+ }
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Wraps a `BytesBufferReader` in a limiting `BytesBufferReader` which limits maximum read
181
+ * to `byteLimit` bytes. It _does not_ update `pos` of the original
182
+ * `BytesBufferReader`.
183
+ *
184
+ * @name decoder.limitReader(reader, byteLimit)
185
+ * @param {BytesBufferReader} reader
186
+ * @param {number} byteLimit
187
+ * @returns {BytesBufferReader}
188
+ */
189
+ export function limitReader (reader, byteLimit) {
190
+ let bytesRead = 0
191
+
192
+ /** @type {BytesBufferReader} */
193
+ return {
194
+ upTo (length) {
195
+ let bytes = reader.upTo(length)
196
+ if (bytes.length + bytesRead > byteLimit) {
197
+ bytes = bytes.subarray(0, byteLimit - bytesRead)
198
+ }
199
+ return bytes
200
+ /* c8 ignore next 2 */
201
+ // Node.js 12 c8 bug
202
+ },
203
+
204
+ exactly (length, seek = false) {
205
+ const bytes = reader.exactly(length, seek)
206
+ if (bytes.length + bytesRead > byteLimit) {
207
+ throw new Error('Unexpected end of data')
208
+ }
209
+ if (seek) {
210
+ bytesRead += length
211
+ }
212
+ return bytes
213
+ /* c8 ignore next 2 */
214
+ // Node.js 12 c8 bug
215
+ },
216
+
217
+ seek (length) {
218
+ bytesRead += length
219
+ reader.seek(length)
220
+ },
221
+
222
+ get pos () {
223
+ return reader.pos
224
+ }
225
+ }
226
+ }