@helia/unixfs 4.0.2 → 4.0.3-c0bf36e

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 (37) hide show
  1. package/dist/index.min.js +1 -1
  2. package/dist/src/commands/add.d.ts +7 -6
  3. package/dist/src/commands/add.d.ts.map +1 -1
  4. package/dist/src/commands/add.js +35 -13
  5. package/dist/src/commands/add.js.map +1 -1
  6. package/dist/src/commands/utils/add-link.js +4 -4
  7. package/dist/src/commands/utils/add-link.js.map +1 -1
  8. package/dist/src/commands/utils/dir-sharded.js +1 -1
  9. package/dist/src/commands/utils/dir-sharded.js.map +1 -1
  10. package/dist/src/commands/utils/remove-link.js +1 -1
  11. package/dist/src/commands/utils/remove-link.js.map +1 -1
  12. package/dist/src/errors.js +1 -1
  13. package/dist/src/errors.js.map +1 -1
  14. package/dist/src/index.d.ts +51 -10
  15. package/dist/src/index.d.ts.map +1 -1
  16. package/dist/src/index.js.map +1 -1
  17. package/dist/src/unixfs.d.ts +2 -2
  18. package/dist/src/unixfs.d.ts.map +1 -1
  19. package/dist/src/utils/glob-source.d.ts +19 -0
  20. package/dist/src/utils/glob-source.d.ts.map +1 -1
  21. package/dist/src/utils/glob-source.js +19 -0
  22. package/dist/src/utils/glob-source.js.map +1 -1
  23. package/dist/src/utils/url-source.d.ts +48 -2
  24. package/dist/src/utils/url-source.d.ts.map +1 -1
  25. package/dist/src/utils/url-source.js +50 -0
  26. package/dist/src/utils/url-source.js.map +1 -1
  27. package/package.json +4 -4
  28. package/src/commands/add.ts +47 -17
  29. package/src/commands/utils/add-link.ts +4 -4
  30. package/src/commands/utils/dir-sharded.ts +1 -1
  31. package/src/commands/utils/remove-link.ts +1 -1
  32. package/src/errors.ts +1 -1
  33. package/src/index.ts +53 -10
  34. package/src/unixfs.ts +2 -2
  35. package/src/utils/glob-source.ts +19 -0
  36. package/src/utils/url-source.ts +55 -2
  37. package/dist/typedoc-urls.json +0 -56
@@ -1,10 +1,60 @@
1
1
  import { UnknownError } from '../errors.js';
2
+ /**
3
+ * Import a file directly from a URL. The path of the file will be the path
4
+ * section of the URL.
5
+ *
6
+ * @example
7
+ *
8
+ * ```ts
9
+ * import { unixfs, urlSource } from '@helia/unixfs'
10
+ * import { createHelia } from 'helia'
11
+ *
12
+ * const helia = await createHelia()
13
+ * const fs = unixfs(helia)
14
+ *
15
+ * const cid = await fs.addFile(urlSource('http://example.com/path/to/file.html))
16
+ * const stat = await fs.stat(cid)
17
+ *
18
+ * console.info(stat)
19
+ * // { cid: CID(...), type: 'directory', ... }
20
+ *
21
+ * for await (const entry of fs.ls(cid)) {
22
+ * console.info(entry)
23
+ * // { type: 'file', name: 'file.html', cid: CID(...), ... }
24
+ * }
25
+ * ```
26
+ */
2
27
  export function urlSource(url, options) {
28
+ url = new URL(url);
3
29
  return {
4
30
  path: decodeURIComponent(new URL(url).pathname.split('/').pop() ?? ''),
5
31
  content: readURLContent(url, options)
6
32
  };
7
33
  }
34
+ /**
35
+ * Import a file directly from a URL ignoring the file name or any containing
36
+ * directory.
37
+ *
38
+ * @example
39
+ *
40
+ * ```ts
41
+ * import { unixfs, urlByteSource } from '@helia/unixfs'
42
+ * import { createHelia } from 'helia'
43
+ *
44
+ * const helia = await createHelia()
45
+ * const fs = unixfs(helia)
46
+ *
47
+ * const cid = await fs.addByteSource(urlByteSource('http://example.com/path/to/file.html))
48
+ * const stat = await fs.stat(cid)
49
+ *
50
+ * console.info(stat)
51
+ * // { type: 'file', cid: CID(...), ... }
52
+ * ```
53
+ */
54
+ export function urlByteSource(url, options) {
55
+ url = new URL(url);
56
+ return readURLContent(url, options);
57
+ }
8
58
  async function* readURLContent(url, options) {
9
59
  const response = await globalThis.fetch(url, options);
10
60
  if (response.body == null) {
@@ -1 +1 @@
1
- {"version":3,"file":"url-source.js","sourceRoot":"","sources":["../../../src/utils/url-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAG3C,MAAM,UAAU,SAAS,CAAE,GAAQ,EAAE,OAAqB;IACxD,OAAO;QACL,IAAI,EAAE,kBAAkB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QACtE,OAAO,EAAE,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC;KACtC,CAAA;AACH,CAAC;AAED,KAAK,SAAU,CAAC,CAAC,cAAc,CAAE,GAAQ,EAAE,OAAqB;IAC9D,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IAErD,IAAI,QAAQ,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;QAC1B,MAAM,IAAI,YAAY,CAAC,mCAAmC,CAAC,CAAA;IAC7D,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAA;IAExC,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;YAE3C,IAAI,IAAI,EAAE,CAAC;gBACT,OAAM;YACR,CAAC;YAED,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBAClB,MAAM,KAAK,CAAA;YACb,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAA;IACtB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"url-source.js","sourceRoot":"","sources":["../../../src/utils/url-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAG3C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,SAAS,CAAE,GAAiB,EAAE,OAAqB;IACjE,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;IAElB,OAAO;QACL,IAAI,EAAE,kBAAkB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QACtE,OAAO,EAAE,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC;KACtC,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,aAAa,CAAE,GAAiB,EAAE,OAAqB;IACrE,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;IAElB,OAAO,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AACrC,CAAC;AAED,KAAK,SAAU,CAAC,CAAC,cAAc,CAAE,GAAQ,EAAE,OAAqB;IAC9D,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IAErD,IAAI,QAAQ,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;QAC1B,MAAM,IAAI,YAAY,CAAC,mCAAmC,CAAC,CAAA;IAC7D,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAA;IAExC,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;YAE3C,IAAI,IAAI,EAAE,CAAC;gBACT,OAAM;YACR,CAAC;YAED,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBAClB,MAAM,KAAK,CAAA;YACb,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,WAAW,EAAE,CAAA;IACtB,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helia/unixfs",
3
- "version": "4.0.2",
3
+ "version": "4.0.3-c0bf36e",
4
4
  "description": "A Helia-compatible wrapper for UnixFS",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "homepage": "https://github.com/ipfs/helia/tree/main/packages/unixfs#readme",
@@ -74,7 +74,7 @@
74
74
  "test:electron-main": "aegir test -t electron-main"
75
75
  },
76
76
  "dependencies": {
77
- "@helia/interface": "^5.2.0",
77
+ "@helia/interface": "5.2.1-c0bf36e",
78
78
  "@ipld/dag-pb": "^4.1.3",
79
79
  "@libp2p/interface": "^2.2.1",
80
80
  "@libp2p/logger": "^5.1.4",
@@ -85,6 +85,7 @@
85
85
  "ipfs-unixfs-exporter": "^13.6.1",
86
86
  "ipfs-unixfs-importer": "^15.3.1",
87
87
  "it-all": "^3.0.6",
88
+ "it-first": "^3.0.6",
88
89
  "it-glob": "^3.0.1",
89
90
  "it-last": "^3.0.6",
90
91
  "it-pipe": "^3.0.1",
@@ -95,12 +96,11 @@
95
96
  "uint8arrays": "^5.1.0"
96
97
  },
97
98
  "devDependencies": {
98
- "aegir": "^45.0.6",
99
+ "aegir": "^45.1.1",
99
100
  "blockstore-core": "^5.0.2",
100
101
  "delay": "^6.0.0",
101
102
  "iso-url": "^1.2.1",
102
103
  "it-drain": "^3.0.7",
103
- "it-first": "^3.0.6",
104
104
  "it-to-buffer": "^4.0.7",
105
105
  "wherearewe": "^2.0.1"
106
106
  },
@@ -1,31 +1,36 @@
1
- import { type ByteStream, type DirectoryCandidate, type FileCandidate, importBytes, importByteStream, type ImportCandidateStream, importDirectory, importer, type ImporterOptions, importFile, type ImportResult } from 'ipfs-unixfs-importer'
1
+ import { importBytes, importByteStream, importer } from 'ipfs-unixfs-importer'
2
2
  import { fixedSize } from 'ipfs-unixfs-importer/chunker'
3
3
  import { balanced } from 'ipfs-unixfs-importer/layout'
4
+ import first from 'it-first'
5
+ import last from 'it-last'
6
+ import { InvalidParametersError } from '../errors.js'
7
+ import type { FileCandidate, AddOptions, AddFileOptions } from '../index.js'
4
8
  import type { PutStore } from '../unixfs.js'
9
+ import type { ByteStream, DirectoryCandidate, ImportCandidateStream, ImportResult } from 'ipfs-unixfs-importer'
5
10
  import type { CID } from 'multiformats/cid'
6
11
 
7
12
  /**
8
13
  * Default importer settings match Filecoin
9
14
  */
10
- const defaultImporterSettings: ImporterOptions = {
15
+ const defaultImporterSettings: AddOptions = {
11
16
  cidVersion: 1,
12
17
  rawLeaves: true,
13
18
  layout: balanced({
14
19
  maxChildrenPerNode: 1024
15
20
  }),
16
21
  chunker: fixedSize({
17
- chunkSize: 1048576
22
+ chunkSize: 1_048_576
18
23
  })
19
24
  }
20
25
 
21
- export async function * addAll (source: ImportCandidateStream, blockstore: PutStore, options: Partial<ImporterOptions> = {}): AsyncGenerator<ImportResult, void, unknown> {
26
+ export async function * addAll (source: ImportCandidateStream, blockstore: PutStore, options: Partial<AddOptions> = {}): AsyncGenerator<ImportResult, void, unknown> {
22
27
  yield * importer(source, blockstore, {
23
28
  ...defaultImporterSettings,
24
29
  ...options
25
30
  })
26
31
  }
27
32
 
28
- export async function addBytes (bytes: Uint8Array, blockstore: PutStore, options: Partial<ImporterOptions> = {}): Promise<CID> {
33
+ export async function addBytes (bytes: Uint8Array, blockstore: PutStore, options: Partial<AddFileOptions> = {}): Promise<CID> {
29
34
  const { cid } = await importBytes(bytes, blockstore, {
30
35
  ...defaultImporterSettings,
31
36
  ...options
@@ -34,7 +39,7 @@ export async function addBytes (bytes: Uint8Array, blockstore: PutStore, options
34
39
  return cid
35
40
  }
36
41
 
37
- export async function addByteStream (bytes: ByteStream, blockstore: PutStore, options: Partial<ImporterOptions> = {}): Promise<CID> {
42
+ export async function addByteStream (bytes: ByteStream, blockstore: PutStore, options: Partial<AddFileOptions> = {}): Promise<CID> {
38
43
  const { cid } = await importByteStream(bytes, blockstore, {
39
44
  ...defaultImporterSettings,
40
45
  ...options
@@ -43,23 +48,48 @@ export async function addByteStream (bytes: ByteStream, blockstore: PutStore, op
43
48
  return cid
44
49
  }
45
50
 
46
- export async function addFile (file: FileCandidate, blockstore: PutStore, options: Partial<ImporterOptions> = {}): Promise<CID> {
47
- const { cid } = await importFile(file, blockstore, {
51
+ export async function addFile (file: FileCandidate, blockstore: PutStore, options: Partial<AddFileOptions> = {}): Promise<CID> {
52
+ if (file.path == null) {
53
+ throw new InvalidParametersError('path is required')
54
+ }
55
+
56
+ if (file.content == null) {
57
+ throw new InvalidParametersError('content is required')
58
+ }
59
+
60
+ const result = await last(addAll([file], blockstore, {
48
61
  ...defaultImporterSettings,
49
- ...options
50
- })
62
+ ...options,
63
+ wrapWithDirectory: true
64
+ }))
51
65
 
52
- return cid
66
+ if (result == null) {
67
+ throw new InvalidParametersError('Nothing imported')
68
+ }
69
+
70
+ return result.cid
53
71
  }
54
72
 
55
- export async function addDirectory (dir: Partial<DirectoryCandidate>, blockstore: PutStore, options: Partial<ImporterOptions> = {}): Promise<CID> {
56
- const { cid } = await importDirectory({
73
+ export async function addDirectory (dir: Partial<DirectoryCandidate>, blockstore: PutStore, options: Partial<AddFileOptions> = {}): Promise<CID> {
74
+ // @ts-expect-error field is not in the types
75
+ if (dir.content != null) {
76
+ throw new InvalidParametersError('Directories cannot have content, use addFile instead')
77
+ }
78
+
79
+ const ord = dir.path == null ? first : last
80
+
81
+ const result = await ord(addAll([{
57
82
  ...dir,
58
83
  path: dir.path ?? '-'
59
- }, blockstore, {
84
+ }], blockstore, {
60
85
  ...defaultImporterSettings,
61
- ...options
62
- })
86
+ ...options,
87
+ wrapWithDirectory: dir.path != null
88
+ }))
63
89
 
64
- return cid
90
+ if (result == null) {
91
+ throw new InvalidParametersError('Nothing imported')
92
+ }
93
+
94
+ return result.cid
65
95
  }
@@ -165,7 +165,7 @@ const addToShardedDirectory = async (parent: Directory, child: Required<PBLink>,
165
165
  throw new AlreadyExistsError()
166
166
  }
167
167
 
168
- log('overwriting %s in subshard', child.Name)
168
+ log('overwriting %s in sub-shard', child.Name)
169
169
  finalSegment.node.Links = finalSegment.node.Links.filter(l => l.Name !== linkName)
170
170
  finalSegment.node.Links.push({
171
171
  Name: linkName,
@@ -173,10 +173,10 @@ const addToShardedDirectory = async (parent: Directory, child: Required<PBLink>,
173
173
  Tsize: child.Tsize
174
174
  })
175
175
  } else if (existingLink.Name?.length === 2) {
176
- throw new Error('Existing link was subshard?!')
176
+ throw new Error('Existing link was sub-shard?!')
177
177
  } else {
178
178
  // conflict, add a new HAMT segment
179
- log('prefix %s already exists, creating new subshard', prefix)
179
+ log('prefix %s already exists, creating new sub-shard', prefix)
180
180
  // find the sibling we are going to replace
181
181
  const index = finalSegment.node.Links.findIndex(l => l.Name?.startsWith(prefix))
182
182
  const sibling = finalSegment.node.Links.splice(index, 1)[0]
@@ -186,7 +186,7 @@ const addToShardedDirectory = async (parent: Directory, child: Required<PBLink>,
186
186
  const wrapped = wrapHash(hamtHashFn)
187
187
  const siblingHash = wrapped(uint8ArrayFromString(siblingName))
188
188
 
189
- // discard hash bits until we reach the subshard depth
189
+ // discard hash bits until we reach the sub-shard depth
190
190
  for (let i = 0; i < path.length; i++) {
191
191
  await siblingHash.take(hamtBucketBits)
192
192
  }
@@ -161,7 +161,7 @@ async function * flush (bucket: Bucket<Dir | InProgressImportResult>, blockstore
161
161
  }
162
162
 
163
163
  if (shard == null) {
164
- throw new Error('Could not flush sharded directory, no subshard found')
164
+ throw new Error('Could not flush sharded directory, no sub-shard found')
165
165
  }
166
166
 
167
167
  links.push({
@@ -96,7 +96,7 @@ const removeFromShardedDirectory = async (parent: Directory, name: string, block
96
96
  finalSegment.children.unset(index)
97
97
 
98
98
  if (finalSegment.node.Links.length === 1) {
99
- // replace the subshard with the last remaining file in the parent
99
+ // replace the sub-shard with the last remaining file in the parent
100
100
  while (true) {
101
101
  if (path.length === 1) {
102
102
  break
package/src/errors.ts CHANGED
@@ -18,7 +18,7 @@ export class NotUnixFSError extends UnixFSError {
18
18
 
19
19
  export class InvalidPBNodeError extends UnixFSError {
20
20
  constructor (message = 'invalid PBNode') {
21
- super(message, 'InvalidPBNodeError', 'ERR_INVALID_PBNODE')
21
+ super(message, 'InvalidPBNodeError', 'ERR_INVALID_PB_NODE')
22
22
  }
23
23
  }
24
24
 
package/src/index.ts CHANGED
@@ -52,7 +52,7 @@ import type { AbortOptions } from '@libp2p/interface'
52
52
  import type { Blockstore } from 'interface-blockstore'
53
53
  import type { Mtime, UnixFS as IPFSUnixFS } from 'ipfs-unixfs'
54
54
  import type { ExporterProgressEvents, UnixFSEntry } from 'ipfs-unixfs-exporter'
55
- import type { ByteStream, DirectoryCandidate, FileCandidate, ImportCandidateStream, ImporterOptions, ImporterProgressEvents, ImportResult } from 'ipfs-unixfs-importer'
55
+ import type { ByteStream, DirectoryCandidate, ImportCandidateStream, ImporterOptions, ImporterProgressEvents, ImportResult, ImportContent } from 'ipfs-unixfs-importer'
56
56
  import type { CID, Version } from 'multiformats/cid'
57
57
  import type { ProgressOptions } from 'progress-events'
58
58
 
@@ -60,6 +60,13 @@ export interface UnixFSComponents {
60
60
  blockstore: Pick<Blockstore, 'get' | 'put' | 'has'>
61
61
  }
62
62
 
63
+ export interface FileCandidate<T extends ImportContent = ImportContent> {
64
+ path: string
65
+ content: T
66
+ mtime?: Mtime
67
+ mode?: number
68
+ }
69
+
63
70
  export type AddEvents = PutBlockProgressEvents
64
71
  | ImporterProgressEvents
65
72
 
@@ -67,6 +74,8 @@ export interface AddOptions extends AbortOptions, Omit<ImporterOptions, 'onProgr
67
74
 
68
75
  }
69
76
 
77
+ export type AddFileOptions = Omit<AddOptions, 'wrapWithDirectory'>
78
+
70
79
  export type GetEvents = GetBlockProgressEvents
71
80
  | ExporterProgressEvents
72
81
 
@@ -233,7 +242,7 @@ export interface RmOptions extends AbortOptions, ProgressOptions<GetEvents | Put
233
242
  */
234
243
  export interface StatOptions extends AbortOptions, ProgressOptions<GetEvents> {
235
244
  /**
236
- * An optional path to allow statting paths inside directories
245
+ * An optional path to allow getting stats of paths inside directories
237
246
  */
238
247
  path?: string
239
248
 
@@ -362,7 +371,11 @@ export interface UnixFS {
362
371
  addAll(source: ImportCandidateStream, options?: Partial<AddOptions>): AsyncIterable<ImportResult>
363
372
 
364
373
  /**
365
- * Add a single `Uint8Array` to your Helia node as a file.
374
+ * Add a single `Uint8Array` to your Helia node and receive a CID that will
375
+ * resolve to it.
376
+ *
377
+ * If you want to preserve a file name or other metadata such as modification
378
+ * time or mode, use `addFile` instead.
366
379
  *
367
380
  * @example
368
381
  *
@@ -372,10 +385,14 @@ export interface UnixFS {
372
385
  * console.info(cid)
373
386
  * ```
374
387
  */
375
- addBytes(bytes: Uint8Array, options?: Partial<AddOptions>): Promise<CID>
388
+ addBytes(bytes: Uint8Array, options?: Partial<AddFileOptions>): Promise<CID>
376
389
 
377
390
  /**
378
- * Add a stream of `Uint8Array` to your Helia node as a file.
391
+ * Add a stream of `Uint8Array`s to your Helia node and receive a CID that
392
+ * will resolve to them.
393
+ *
394
+ * If you want to preserve a file name or other metadata such as modification
395
+ * time or mode, use `addFile` instead.
379
396
  *
380
397
  * @example
381
398
  *
@@ -388,10 +405,14 @@ export interface UnixFS {
388
405
  * console.info(cid)
389
406
  * ```
390
407
  */
391
- addByteStream(bytes: ByteStream, options?: Partial<AddOptions>): Promise<CID>
408
+ addByteStream(bytes: ByteStream, options?: Partial<AddFileOptions>): Promise<CID>
392
409
 
393
410
  /**
394
- * Add a file to your Helia node with optional metadata.
411
+ * Add a file to your Helia node with metadata. The returned CID will resolve
412
+ * to a directory with one file entry.
413
+ *
414
+ * If you don't care about file names and just want a CID that will resolve to
415
+ * the contents of the file, use `addBytes` or `addByeStream` instead.
395
416
  *
396
417
  * @example
397
418
  *
@@ -409,20 +430,42 @@ export interface UnixFS {
409
430
  * console.info(cid)
410
431
  * ```
411
432
  */
412
- addFile(file: FileCandidate, options?: Partial<AddOptions>): Promise<CID>
433
+ addFile(file: FileCandidate, options?: Partial<AddFileOptions>): Promise<CID>
413
434
 
414
435
  /**
415
436
  * Add a directory to your Helia node.
416
437
  *
417
438
  * @example
418
439
  *
440
+ * If no path is specified, the returned CID will resolve to an empty
441
+ * directory.
442
+ *
419
443
  * ```typescript
420
444
  * const cid = await fs.addDirectory()
421
445
  *
422
- * console.info(cid)
446
+ * console.info(cid) // empty directory CID
447
+ * ```
448
+ *
449
+ * @example
450
+ *
451
+ * If a path is specified, the CID will resolve to a directory that contains
452
+ * an empty directory with the specified name.
453
+ *
454
+ * ```typescript
455
+ * const cid = await fs.addDirectory({
456
+ * path: 'my-dir'
457
+ * })
458
+ *
459
+ * console.info(cid) // containing directory CID
460
+ *
461
+ * const stat = await fs.stat(cid, {
462
+ * path: 'my-dir'
463
+ * })
464
+ *
465
+ * console.info(stat.cid) // empty directory CID
423
466
  * ```
424
467
  */
425
- addDirectory(dir?: Partial<DirectoryCandidate>, options?: Partial<AddOptions>): Promise<CID>
468
+ addDirectory(dir?: Partial<DirectoryCandidate>, options?: Partial<AddFileOptions>): Promise<CID>
426
469
 
427
470
  /**
428
471
  * Retrieve the contents of a file from your Helia node.
package/src/unixfs.ts CHANGED
@@ -7,10 +7,10 @@ import { mkdir } from './commands/mkdir.js'
7
7
  import { rm } from './commands/rm.js'
8
8
  import { stat } from './commands/stat.js'
9
9
  import { touch } from './commands/touch.js'
10
- import type { AddOptions, CatOptions, ChmodOptions, CpOptions, LsOptions, MkdirOptions, RmOptions, StatOptions, TouchOptions, UnixFSComponents, UnixFS as UnixFSInterface, UnixFSStats } from './index.js'
10
+ import type { AddOptions, CatOptions, ChmodOptions, CpOptions, FileCandidate, LsOptions, MkdirOptions, RmOptions, StatOptions, TouchOptions, UnixFSComponents, UnixFS as UnixFSInterface, UnixFSStats } from './index.js'
11
11
  import type { Blockstore } from 'interface-blockstore'
12
12
  import type { UnixFSEntry } from 'ipfs-unixfs-exporter'
13
- import type { ByteStream, DirectoryCandidate, FileCandidate, ImportCandidateStream, ImportResult } from 'ipfs-unixfs-importer'
13
+ import type { ByteStream, DirectoryCandidate, ImportCandidateStream, ImportResult } from 'ipfs-unixfs-importer'
14
14
  import type { CID } from 'multiformats/cid'
15
15
 
16
16
  export type PutStore = Pick<Blockstore, 'put'>
@@ -50,6 +50,25 @@ export interface GlobSourceResult {
50
50
 
51
51
  /**
52
52
  * Create an async iterator that yields paths that match requested glob pattern
53
+ *
54
+ * @example
55
+ *
56
+ * ```ts
57
+ * import { unixfs, globSource } from '@helia/unixfs'
58
+ * import { createHelia } from 'helia'
59
+ *
60
+ * const helia = await createHelia()
61
+ * const fs = unixfs(helia)
62
+ *
63
+ * for await (const entry of fs.addAll(globSource(
64
+ * '/path/to/dir',
65
+ * '**\/*'
66
+ * ), {
67
+ * wrapWithDirectory: true
68
+ * })) {
69
+ * console.info(entry)
70
+ * }
71
+ * ```
53
72
  */
54
73
  export async function * globSource (cwd: string, pattern: string, options: GlobSourceOptions = {}): AsyncGenerator<ImportCandidate & GlobSourceResult> {
55
74
  if (typeof pattern !== 'string') {
@@ -1,13 +1,66 @@
1
1
  import { UnknownError } from '../errors.js'
2
- import type { FileCandidate } from 'ipfs-unixfs-importer'
2
+ import type { FileCandidate } from '../index.js'
3
+
4
+ /**
5
+ * Import a file directly from a URL. The path of the file will be the path
6
+ * section of the URL.
7
+ *
8
+ * @example
9
+ *
10
+ * ```ts
11
+ * import { unixfs, urlSource } from '@helia/unixfs'
12
+ * import { createHelia } from 'helia'
13
+ *
14
+ * const helia = await createHelia()
15
+ * const fs = unixfs(helia)
16
+ *
17
+ * const cid = await fs.addFile(urlSource('http://example.com/path/to/file.html))
18
+ * const stat = await fs.stat(cid)
19
+ *
20
+ * console.info(stat)
21
+ * // { cid: CID(...), type: 'directory', ... }
22
+ *
23
+ * for await (const entry of fs.ls(cid)) {
24
+ * console.info(entry)
25
+ * // { type: 'file', name: 'file.html', cid: CID(...), ... }
26
+ * }
27
+ * ```
28
+ */
29
+ export function urlSource (url: URL | string, options?: RequestInit): FileCandidate<AsyncGenerator<Uint8Array, void, unknown>> {
30
+ url = new URL(url)
3
31
 
4
- export function urlSource (url: URL, options?: RequestInit): FileCandidate<AsyncGenerator<Uint8Array, void, unknown>> {
5
32
  return {
6
33
  path: decodeURIComponent(new URL(url).pathname.split('/').pop() ?? ''),
7
34
  content: readURLContent(url, options)
8
35
  }
9
36
  }
10
37
 
38
+ /**
39
+ * Import a file directly from a URL ignoring the file name or any containing
40
+ * directory.
41
+ *
42
+ * @example
43
+ *
44
+ * ```ts
45
+ * import { unixfs, urlByteSource } from '@helia/unixfs'
46
+ * import { createHelia } from 'helia'
47
+ *
48
+ * const helia = await createHelia()
49
+ * const fs = unixfs(helia)
50
+ *
51
+ * const cid = await fs.addByteSource(urlByteSource('http://example.com/path/to/file.html))
52
+ * const stat = await fs.stat(cid)
53
+ *
54
+ * console.info(stat)
55
+ * // { type: 'file', cid: CID(...), ... }
56
+ * ```
57
+ */
58
+ export function urlByteSource (url: URL | string, options?: RequestInit): AsyncGenerator<Uint8Array, void, unknown> {
59
+ url = new URL(url)
60
+
61
+ return readURLContent(url, options)
62
+ }
63
+
11
64
  async function * readURLContent (url: URL, options?: RequestInit): AsyncGenerator<Uint8Array, void, unknown> {
12
65
  const response = await globalThis.fetch(url, options)
13
66
 
@@ -1,56 +0,0 @@
1
- {
2
- "AlreadyExistsError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.AlreadyExistsError.html",
3
- "./errors:AlreadyExistsError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.AlreadyExistsError.html",
4
- "DoesNotExistError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.DoesNotExistError.html",
5
- "./errors:DoesNotExistError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.DoesNotExistError.html",
6
- "InvalidPBNodeError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.InvalidPBNodeError.html",
7
- "./errors:InvalidPBNodeError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.InvalidPBNodeError.html",
8
- "InvalidParametersError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.InvalidParametersError.html",
9
- "./errors:InvalidParametersError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.InvalidParametersError.html",
10
- "NoContentError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.NoContentError.html",
11
- "./errors:NoContentError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.NoContentError.html",
12
- "NotADirectoryError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.NotADirectoryError.html",
13
- "./errors:NotADirectoryError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.NotADirectoryError.html",
14
- "NotAFileError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.NotAFileError.html",
15
- "./errors:NotAFileError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.NotAFileError.html",
16
- "NotUnixFSError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.NotUnixFSError.html",
17
- "./errors:NotUnixFSError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.NotUnixFSError.html",
18
- "UnixFSError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.UnixFSError.html",
19
- "./errors:UnixFSError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.UnixFSError.html",
20
- "UnknownError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.UnknownError.html",
21
- "./errors:UnknownError": "https://ipfs.github.io/helia/classes/_helia_unixfs.errors.UnknownError.html",
22
- "AddOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.AddOptions.html",
23
- ".:AddOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.AddOptions.html",
24
- "CatOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.CatOptions.html",
25
- ".:CatOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.CatOptions.html",
26
- "ChmodOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.ChmodOptions.html",
27
- ".:ChmodOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.ChmodOptions.html",
28
- "CpOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.CpOptions.html",
29
- ".:CpOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.CpOptions.html",
30
- "GlobSourceOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.GlobSourceOptions.html",
31
- "GlobSourceResult": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.GlobSourceResult.html",
32
- "LsOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.LsOptions.html",
33
- ".:LsOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.LsOptions.html",
34
- "MkdirOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.MkdirOptions.html",
35
- ".:MkdirOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.MkdirOptions.html",
36
- "RmOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.RmOptions.html",
37
- ".:RmOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.RmOptions.html",
38
- "StatOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.StatOptions.html",
39
- ".:StatOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.StatOptions.html",
40
- "TouchOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.TouchOptions.html",
41
- ".:TouchOptions": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.TouchOptions.html",
42
- "UnixFS": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.UnixFS.html",
43
- ".:UnixFS": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.UnixFS.html",
44
- "UnixFSComponents": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.UnixFSComponents.html",
45
- ".:UnixFSComponents": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.UnixFSComponents.html",
46
- "UnixFSStats": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.UnixFSStats.html",
47
- ".:UnixFSStats": "https://ipfs.github.io/helia/interfaces/_helia_unixfs.index.UnixFSStats.html",
48
- "AddEvents": "https://ipfs.github.io/helia/types/_helia_unixfs.index.AddEvents.html",
49
- ".:AddEvents": "https://ipfs.github.io/helia/types/_helia_unixfs.index.AddEvents.html",
50
- "GetEvents": "https://ipfs.github.io/helia/types/_helia_unixfs.index.GetEvents.html",
51
- ".:GetEvents": "https://ipfs.github.io/helia/types/_helia_unixfs.index.GetEvents.html",
52
- "globSource": "https://ipfs.github.io/helia/functions/_helia_unixfs.index.globSource.html",
53
- "unixfs": "https://ipfs.github.io/helia/functions/_helia_unixfs.index.unixfs-1.html",
54
- ".:unixfs": "https://ipfs.github.io/helia/functions/_helia_unixfs.index.unixfs-1.html",
55
- "urlSource": "https://ipfs.github.io/helia/functions/_helia_unixfs.index.urlSource.html"
56
- }