@helia/car 5.0.1 → 5.1.0-faac4ad3

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 (50) hide show
  1. package/README.md +54 -4
  2. package/dist/index.min.js +1 -1
  3. package/dist/index.min.js.map +4 -4
  4. package/dist/src/car.d.ts +1 -2
  5. package/dist/src/car.d.ts.map +1 -1
  6. package/dist/src/car.js +46 -124
  7. package/dist/src/car.js.map +1 -1
  8. package/dist/src/errors.d.ts +8 -0
  9. package/dist/src/errors.d.ts.map +1 -1
  10. package/dist/src/errors.js +8 -0
  11. package/dist/src/errors.js.map +1 -1
  12. package/dist/src/export-strategies/block-exporter.d.ts +5 -2
  13. package/dist/src/export-strategies/block-exporter.d.ts.map +1 -1
  14. package/dist/src/export-strategies/block-exporter.js +9 -3
  15. package/dist/src/export-strategies/block-exporter.js.map +1 -1
  16. package/dist/src/export-strategies/subgraph-exporter.d.ts +5 -2
  17. package/dist/src/export-strategies/subgraph-exporter.d.ts.map +1 -1
  18. package/dist/src/export-strategies/subgraph-exporter.js +8 -3
  19. package/dist/src/export-strategies/subgraph-exporter.js.map +1 -1
  20. package/dist/src/export-strategies/unixfs-exporter.d.ts +10 -4
  21. package/dist/src/export-strategies/unixfs-exporter.d.ts.map +1 -1
  22. package/dist/src/export-strategies/unixfs-exporter.js +15 -8
  23. package/dist/src/export-strategies/unixfs-exporter.js.map +1 -1
  24. package/dist/src/index.d.ts +64 -12
  25. package/dist/src/index.d.ts.map +1 -1
  26. package/dist/src/index.js +56 -6
  27. package/dist/src/index.js.map +1 -1
  28. package/dist/src/traversal-strategies/cid-path.d.ts +9 -6
  29. package/dist/src/traversal-strategies/cid-path.d.ts.map +1 -1
  30. package/dist/src/traversal-strategies/cid-path.js +35 -12
  31. package/dist/src/traversal-strategies/cid-path.js.map +1 -1
  32. package/dist/src/traversal-strategies/graph-search.d.ts +15 -7
  33. package/dist/src/traversal-strategies/graph-search.d.ts.map +1 -1
  34. package/dist/src/traversal-strategies/graph-search.js +57 -11
  35. package/dist/src/traversal-strategies/graph-search.js.map +1 -1
  36. package/dist/src/traversal-strategies/unixfs-path.d.ts +53 -3
  37. package/dist/src/traversal-strategies/unixfs-path.d.ts.map +1 -1
  38. package/dist/src/traversal-strategies/unixfs-path.js +70 -30
  39. package/dist/src/traversal-strategies/unixfs-path.js.map +1 -1
  40. package/package.json +7 -5
  41. package/src/car.ts +54 -163
  42. package/src/errors.ts +10 -0
  43. package/src/export-strategies/block-exporter.ts +13 -4
  44. package/src/export-strategies/subgraph-exporter.ts +13 -4
  45. package/src/export-strategies/unixfs-exporter.ts +20 -9
  46. package/src/index.ts +66 -15
  47. package/src/traversal-strategies/cid-path.ts +43 -13
  48. package/src/traversal-strategies/graph-search.ts +70 -12
  49. package/src/traversal-strategies/unixfs-path.ts +77 -41
  50. package/dist/typedoc-urls.json +0 -20
@@ -1,25 +1,83 @@
1
+ import { breadthFirstWalker, depthFirstWalker } from '@helia/utils'
2
+ import { InvalidParametersError } from '@libp2p/interface'
3
+ import toBuffer from 'it-to-buffer'
4
+ import { createUnsafe } from 'multiformats/block'
5
+ import { InvalidTraversalError } from '../errors.ts'
1
6
  import type { TraversalStrategy } from '../index.js'
2
- import type { BlockView } from 'multiformats/block/interface'
7
+ import type { CodecLoader } from '@helia/interface'
8
+ import type { GraphWalker } from '@helia/utils'
9
+ import type { AbortOptions } from '@libp2p/interface'
10
+ import type { Blockstore } from 'interface-blockstore'
11
+ import type { BlockView } from 'multiformats'
3
12
  import type { CID } from 'multiformats/cid'
4
13
 
14
+ export interface GraphSearchOptions {
15
+ strategy?: 'depth-first' | 'breadth-first'
16
+ }
17
+
18
+ function isCID (obj?: any): obj is CID {
19
+ return obj != null && obj?.asCID === obj
20
+ }
21
+
5
22
  /**
6
- * A traversal strategy that performs a breadth-first search (so as to not load blocks unnecessarily) looking for a
7
- * target CID. Traversal stops when we reach the target CID or run out of nodes.
23
+ * A traversal strategy that performs a depth-first search looking for a target
24
+ * CID.
8
25
  */
9
26
  export class GraphSearch implements TraversalStrategy {
10
- private readonly target: CID
27
+ private haystack?: CID
28
+ private readonly needle: CID
29
+ private readonly options?: GraphSearchOptions
11
30
 
12
- constructor (target: CID) {
13
- this.target = target
31
+ constructor (needle: CID, options?: GraphSearchOptions)
32
+ constructor (haystack: CID, needle: CID, options?: GraphSearchOptions)
33
+ constructor (...args: any[]) {
34
+ if (isCID(args[0])) {
35
+ if (isCID(args[1])) {
36
+ this.haystack = args[0]
37
+ this.needle = args[1]
38
+ this.options = args[2]
39
+ } else {
40
+ this.needle = args[0]
41
+ this.options = args[1]
42
+ }
43
+ } else {
44
+ throw new InvalidParametersError('needle must be specified')
45
+ }
14
46
  }
15
47
 
16
- isTarget (cid: CID): boolean {
17
- return this.target.equals(cid)
18
- }
48
+ async * traverse (root: CID, blockstore: Blockstore, getCodec: CodecLoader, options?: AbortOptions): AsyncGenerator<BlockView<unknown, number, number, 0 | 1>, void, undefined> {
49
+ const start = this.haystack ?? root
50
+ let walker: GraphWalker
19
51
 
20
- async * traverse <T extends BlockView<any, any, any, 0 | 1>>(cid: CID, block: T): AsyncGenerator<CID, void, undefined> {
21
- for (const [, linkedCid] of block.links()) {
22
- yield linkedCid
52
+ if (this.options?.strategy === 'breadth-first') {
53
+ walker = breadthFirstWalker({
54
+ blockstore,
55
+ getCodec
56
+ })
57
+ } else {
58
+ walker = depthFirstWalker({
59
+ blockstore,
60
+ getCodec
61
+ })
23
62
  }
63
+
64
+ for await (const node of walker.walk(start, options)) {
65
+ if (node.block.cid.equals(this.needle)) {
66
+ for (const cid of node.path) {
67
+ const bytes = await toBuffer(blockstore.get(cid, options))
68
+ const block = createUnsafe({
69
+ cid,
70
+ bytes,
71
+ codec: await getCodec(cid.code)
72
+ })
73
+
74
+ yield block
75
+ }
76
+
77
+ return
78
+ }
79
+ }
80
+
81
+ throw new InvalidTraversalError(`${this.needle} was not a child of ${start}`)
24
82
  }
25
83
  }
@@ -1,58 +1,94 @@
1
- import { decode } from '@ipld/dag-pb'
2
- import { UnixFS } from 'ipfs-unixfs'
3
- import { DAG_PB_CODEC_CODE } from '../constants.js'
4
- import { NotUnixFSError } from '../errors.js'
1
+ import * as dagPb from '@ipld/dag-pb'
2
+ import { walkPath } from 'ipfs-unixfs-exporter'
3
+ import { createUnsafe } from 'multiformats/block'
5
4
  import type { TraversalStrategy } from '../index.js'
6
- import type { BlockView } from 'multiformats/block/interface'
5
+ import type { CodecLoader } from '@helia/interface'
6
+ import type { AbortOptions } from '@libp2p/interface'
7
+ import type { Blockstore } from 'interface-blockstore'
8
+ import type { BlockView } from 'multiformats'
7
9
  import type { CID } from 'multiformats/cid'
8
10
 
9
11
  /**
10
12
  * Traverses a DAG containing UnixFS directories
13
+ *
14
+ * A root CID may be specified to begin traversal from, otherwise the root
15
+ * currently being exported will be used.
16
+ *
17
+ * @example Begin traversal from the root being exported
18
+ *
19
+ * In this example, the UnixFS path `/foo/bar/baz.txt` path should be resolvable
20
+ * beneath the `root` CID.
21
+ *
22
+ * ```typescript
23
+ * import { createHelia } from 'helia'
24
+ * import { car, UnixFSPath } from '@helia/car'
25
+ * import { CID } from 'multiformats/cid'
26
+ *
27
+ * const helia = await createHelia()
28
+ * const c = car(helia)
29
+ * const root = CID.parse('QmRoot')
30
+ *
31
+ * for await (const buf of c.export(root, {
32
+ * traversal: new UnixFSPath('/foo/bar/baz.txt')
33
+ * })) {
34
+ * // do something with `buf`
35
+ * }
36
+ * ```
37
+ *
38
+ * @example Begin traversal from a parent node
39
+ *
40
+ * In this example, the `root` CID should be resolvable at the UnixFS path
41
+ * beneath `parentCID`.
42
+ *
43
+ * ```typescript
44
+ * import { createHelia } from 'helia'
45
+ * import { car, UnixFSPath } from '@helia/car'
46
+ * import { CID } from 'multiformats/cid'
47
+ *
48
+ * const helia = await createHelia()
49
+ * const c = car(helia)
50
+ * const root = CID.parse('QmRoot')
51
+ * const parentCID = CID.parse('QmParent')
52
+ *
53
+ * for await (const buf of c.export(root, {
54
+ * traversal: new UnixFSPath(parentCID, '/foo/bar/baz.txt')
55
+ * })) {
56
+ * // do something with `buf`
57
+ * }
58
+ * ```
11
59
  */
12
60
  export class UnixFSPath implements TraversalStrategy {
13
- private readonly path: string[]
61
+ private readonly root?: CID
62
+ private readonly path: string
14
63
 
15
- constructor (path: string) {
16
- // "/foo/bar/baz.txt" -> ['foo', 'bar', 'baz.txt']
17
- this.path = path.replace(/^\//, '').split('/')
18
- }
19
-
20
- isTarget (): boolean {
21
- return this.path.length === 0
22
- }
23
-
24
- async * traverse <T extends BlockView<any, any, any, 0 | 1>>(cid: CID, block: T): AsyncGenerator<CID, void, undefined> {
25
- if (cid.code !== DAG_PB_CODEC_CODE) {
26
- throw new NotUnixFSError('Target CID is not UnixFS')
27
- }
28
-
29
- const segment = this.path.shift()
64
+ constructor (path: string)
65
+ constructor (root: CID, path: string)
66
+ constructor (...args: any[]) {
67
+ let root: CID | string | undefined = args[0]
68
+ let path: string = args[1]
30
69
 
31
- if (segment == null) {
32
- return
70
+ if (typeof root === 'string') {
71
+ path = root
72
+ root = undefined
73
+ } else if (args.length < 2) {
74
+ throw new Error('path or CID and path must be specified')
33
75
  }
34
76
 
35
- const pb = decode(block.bytes)
36
-
37
- if (pb.Data == null) {
38
- throw new NotUnixFSError('Target CID has no UnixFS data in decoded bytes')
77
+ if (!path.startsWith('/')) {
78
+ path = `/${path}`
39
79
  }
40
80
 
41
- const unixfs = UnixFS.unmarshal(pb.Data)
42
-
43
- if (unixfs.type === 'directory') {
44
- const link = pb.Links.filter(link => link.Name === segment).pop()
45
-
46
- if (link == null) {
47
- throw new NotUnixFSError(`Target CID directory has no link with name ${segment}`)
48
- }
81
+ this.root = root
82
+ this.path = path
83
+ }
49
84
 
50
- yield link.Hash
51
- return
85
+ async * traverse (root: CID, blockstore: Blockstore, getCodec: CodecLoader, options?: AbortOptions): AsyncGenerator<BlockView<unknown, number, number, 0 | 1>, void, undefined> {
86
+ for await (const entry of walkPath(`${this.root ?? root}${this.path}`, blockstore, options)) {
87
+ yield createUnsafe({
88
+ cid: entry.cid,
89
+ bytes: entry.node instanceof Uint8Array ? entry.node : dagPb.encode(entry.node),
90
+ codec: await getCodec(entry.cid.code)
91
+ })
52
92
  }
53
-
54
- // TODO: HAMT support
55
-
56
- throw new NotUnixFSError('Target CID is not a UnixFS directory')
57
93
  }
58
94
  }
@@ -1,20 +0,0 @@
1
- {
2
- "BlockExporter": "https://ipfs.github.io/helia/classes/_helia_car.BlockExporter.html",
3
- "CIDPath": "https://ipfs.github.io/helia/classes/_helia_car.CIDPath.html",
4
- "GraphSearch": "https://ipfs.github.io/helia/classes/_helia_car.GraphSearch.html",
5
- "SubgraphExporter": "https://ipfs.github.io/helia/classes/_helia_car.SubgraphExporter.html",
6
- "UnixFSExporter": "https://ipfs.github.io/helia/classes/_helia_car.UnixFSExporter.html",
7
- "UnixFSPath": "https://ipfs.github.io/helia/classes/_helia_car.UnixFSPath.html",
8
- "Car": "https://ipfs.github.io/helia/interfaces/_helia_car.Car.html",
9
- ".:Car": "https://ipfs.github.io/helia/interfaces/_helia_car.Car.html",
10
- "CarComponents": "https://ipfs.github.io/helia/interfaces/_helia_car.CarComponents.html",
11
- ".:CarComponents": "https://ipfs.github.io/helia/interfaces/_helia_car.CarComponents.html",
12
- "ExportCarOptions": "https://ipfs.github.io/helia/interfaces/_helia_car.ExportCarOptions.html",
13
- ".:ExportCarOptions": "https://ipfs.github.io/helia/interfaces/_helia_car.ExportCarOptions.html",
14
- "ExportStrategy": "https://ipfs.github.io/helia/interfaces/_helia_car.ExportStrategy.html",
15
- ".:ExportStrategy": "https://ipfs.github.io/helia/interfaces/_helia_car.ExportStrategy.html",
16
- "TraversalStrategy": "https://ipfs.github.io/helia/interfaces/_helia_car.TraversalStrategy.html",
17
- ".:TraversalStrategy": "https://ipfs.github.io/helia/interfaces/_helia_car.TraversalStrategy.html",
18
- "car": "https://ipfs.github.io/helia/functions/_helia_car.car.html",
19
- ".:car": "https://ipfs.github.io/helia/functions/_helia_car.car.html"
20
- }