@helia/unixfs 1.0.0 → 1.0.2

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,34 @@
1
+ import type { CID } from 'multiformats/cid'
2
+ import type { Blockstore } from 'interface-blockstore'
3
+ import { ByteStream, DirectoryCandidate, FileCandidate, importBytes, importByteStream, ImportCandidateStream, importDirectory, importer, ImporterOptions, importFile, ImportResult } from 'ipfs-unixfs-importer'
4
+
5
+ export async function * addAll (source: ImportCandidateStream, blockstore: Blockstore, options: Partial<ImporterOptions> = {}): AsyncGenerator<ImportResult, void, unknown> {
6
+ yield * importer(source, blockstore, options)
7
+ }
8
+
9
+ export async function addBytes (bytes: Uint8Array, blockstore: Blockstore, options: Partial<ImporterOptions> = {}): Promise<CID> {
10
+ const { cid } = await importBytes(bytes, blockstore, options)
11
+
12
+ return cid
13
+ }
14
+
15
+ export async function addByteStream (bytes: ByteStream, blockstore: Blockstore, options: Partial<ImporterOptions> = {}): Promise<CID> {
16
+ const { cid } = await importByteStream(bytes, blockstore, options)
17
+
18
+ return cid
19
+ }
20
+
21
+ export async function addFile (file: FileCandidate, blockstore: Blockstore, options: Partial<ImporterOptions> = {}): Promise<CID> {
22
+ const { cid } = await importFile(file, blockstore, options)
23
+
24
+ return cid
25
+ }
26
+
27
+ export async function addDirectory (dir: Partial<DirectoryCandidate>, blockstore: Blockstore, options: Partial<ImporterOptions> = {}): Promise<CID> {
28
+ const { cid } = await importDirectory({
29
+ ...dir,
30
+ path: dir.path ?? '-'
31
+ }, blockstore, options)
32
+
33
+ return cid
34
+ }
@@ -63,10 +63,8 @@ export async function chmod (cid: CID, mode: number, blockstore: Blockstore, opt
63
63
  }
64
64
  }
65
65
  },
66
- // @ts-expect-error we account for the incompatible source type with our custom dag builder below
67
66
  (source) => importer(source, blockstore, {
68
67
  ...opts,
69
- pin: false,
70
68
  dagBuilder: async function * (source, block) {
71
69
  for await (const entry of source) {
72
70
  yield async function () {
@@ -87,7 +85,7 @@ export async function chmod (cid: CID, mode: number, blockstore: Blockstore, opt
87
85
 
88
86
  return {
89
87
  cid: updatedCid,
90
- size: buf.length,
88
+ size: BigInt(buf.length),
91
89
  path: entry.path,
92
90
  unixfs
93
91
  }
@@ -67,10 +67,8 @@ export async function touch (cid: CID, blockstore: Blockstore, options: Partial<
67
67
  }
68
68
  }
69
69
  },
70
- // @ts-expect-error we account for the incompatible source type with our custom dag builder below
71
70
  (source) => importer(source, blockstore, {
72
71
  ...opts,
73
- pin: false,
74
72
  dagBuilder: async function * (source, block) {
75
73
  for await (const entry of source) {
76
74
  yield async function () {
@@ -91,7 +89,7 @@ export async function touch (cid: CID, blockstore: Blockstore, options: Partial<
91
89
 
92
90
  return {
93
91
  cid: updatedCid,
94
- size: buf.length,
92
+ size: BigInt(buf.length),
95
93
  path: entry.path,
96
94
  unixfs
97
95
  }
package/src/index.ts CHANGED
@@ -1,6 +1,40 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * `@helia/unixfs` is an implementation of a {@link https://github.com/ipfs/specs/blob/main/UNIXFS.md UnixFS filesystem} compatible with {@link https://github.com/ipfs/helia Helia}.
5
+ *
6
+ * See the {@link UnixFS UnixFS interface} for all available operations.
7
+ *
8
+ * @example
9
+ *
10
+ * ```typescript
11
+ * import { createHelia } from 'helia'
12
+ * import { unixfs } from '@helia/unixfs'
13
+ *
14
+ * const helia = createHelia({
15
+ * // ... helia config
16
+ * })
17
+ * const fs = unixfs(helia)
18
+ *
19
+ * // create an empty dir and a file, then add the file to the dir
20
+ * const emptyDirCid = await fs.addDirectory()
21
+ * const fileCid = await fs.addBytes(Uint8Array.from([0, 1, 2, 3]))
22
+ * const updateDirCid = await fs.cp(fileCid, emptyDirCid, 'foo.txt')
23
+ *
24
+ * // or doing the same thing as a stream
25
+ * for await (const entry of fs.addAll([{
26
+ * path: 'foo.txt',
27
+ * content: Uint8Array.from([0, 1, 2, 3])
28
+ * }])) {
29
+ * console.info(entry)
30
+ * }
31
+ * ```
32
+ */
33
+
1
34
  import type { CID, Version } from 'multiformats/cid'
2
35
  import type { Blockstore } from 'interface-blockstore'
3
36
  import type { AbortOptions } from '@libp2p/interfaces'
37
+ import { addAll, addBytes, addByteStream, addDirectory, addFile } from './commands/add.js'
4
38
  import { cat } from './commands/cat.js'
5
39
  import { mkdir } from './commands/mkdir.js'
6
40
  import type { Mtime } from 'ipfs-unixfs'
@@ -11,50 +45,147 @@ import { touch } from './commands/touch.js'
11
45
  import { chmod } from './commands/chmod.js'
12
46
  import type { UnixFSEntry } from 'ipfs-unixfs-exporter'
13
47
  import { ls } from './commands/ls.js'
48
+ import type { ByteStream, DirectoryCandidate, FileCandidate, ImportCandidateStream, ImporterOptions, ImportResult } from 'ipfs-unixfs-importer'
14
49
 
15
50
  export interface UnixFSComponents {
16
51
  blockstore: Blockstore
17
52
  }
18
53
 
54
+ /**
55
+ * Options to pass to the cat command
56
+ */
19
57
  export interface CatOptions extends AbortOptions {
58
+ /**
59
+ * Start reading the file at this offset
60
+ */
20
61
  offset?: number
62
+
63
+ /**
64
+ * Stop reading the file after this many bytes
65
+ */
21
66
  length?: number
67
+
68
+ /**
69
+ * An optional path to allow reading files inside directories
70
+ */
22
71
  path?: string
23
72
  }
24
73
 
74
+ /**
75
+ * Options to pass to the chmod command
76
+ */
25
77
  export interface ChmodOptions extends AbortOptions {
78
+ /**
79
+ * If the target of the operation is a directory and this is true,
80
+ * apply the new mode to all directory contents
81
+ */
26
82
  recursive: boolean
83
+
84
+ /**
85
+ * Optional path to set the mode on directory contents
86
+ */
27
87
  path?: string
88
+
89
+ /**
90
+ * DAGs with a root block larger than this value will be sharded. Blocks
91
+ * smaller than this value will be regular UnixFS directories.
92
+ */
28
93
  shardSplitThresholdBytes: number
29
94
  }
30
95
 
96
+ /**
97
+ * Options to pass to the cp command
98
+ */
31
99
  export interface CpOptions extends AbortOptions {
100
+ /**
101
+ * If true, allow overwriting existing directory entries (default: false)
102
+ */
32
103
  force: boolean
104
+
105
+ /**
106
+ * DAGs with a root block larger than this value will be sharded. Blocks
107
+ * smaller than this value will be regular UnixFS directories.
108
+ */
33
109
  shardSplitThresholdBytes: number
34
110
  }
35
111
 
112
+ /**
113
+ * Options to pass to the ls command
114
+ */
36
115
  export interface LsOptions extends AbortOptions {
116
+ /**
117
+ * Optional path to list subdirectory contents if the target CID resolves to
118
+ * a directory
119
+ */
37
120
  path?: string
121
+
122
+ /**
123
+ * Start reading the directory entries at this offset
124
+ */
38
125
  offset?: number
126
+
127
+ /**
128
+ * Stop reading the directory contents after this many directory entries
129
+ */
39
130
  length?: number
40
131
  }
41
132
 
133
+ /**
134
+ * Options to pass to the mkdir command
135
+ */
42
136
  export interface MkdirOptions extends AbortOptions {
137
+ /**
138
+ * The CID version to create the new directory with - defaults to the same
139
+ * version as the containing directory
140
+ */
43
141
  cidVersion: Version
142
+
143
+ /**
144
+ * If true, allow overwriting existing directory entries (default: false)
145
+ */
44
146
  force: boolean
147
+
148
+ /**
149
+ * An optional mode to set on the new directory
150
+ */
45
151
  mode?: number
152
+
153
+ /**
154
+ * An optional mtime to set on the new directory
155
+ */
46
156
  mtime?: Mtime
157
+
158
+ /**
159
+ * DAGs with a root block larger than this value will be sharded. Blocks
160
+ * smaller than this value will be regular UnixFS directories.
161
+ */
47
162
  shardSplitThresholdBytes: number
48
163
  }
49
164
 
165
+ /**
166
+ * Options to pass to the rm command
167
+ */
50
168
  export interface RmOptions extends AbortOptions {
169
+ /**
170
+ * DAGs with a root block larger than this value will be sharded. Blocks
171
+ * smaller than this value will be regular UnixFS directories.
172
+ */
51
173
  shardSplitThresholdBytes: number
52
174
  }
53
175
 
176
+ /**
177
+ * Options to pass to the stat command
178
+ */
54
179
  export interface StatOptions extends AbortOptions {
180
+ /**
181
+ * An optional path to allow statting paths inside directories
182
+ */
55
183
  path?: string
56
184
  }
57
185
 
186
+ /**
187
+ * Statistics relating to a UnixFS DAG
188
+ */
58
189
  export interface UnixFSStats {
59
190
  /**
60
191
  * The file or directory CID
@@ -109,21 +240,245 @@ export interface UnixFSStats {
109
240
  unixfs?: import('ipfs-unixfs').UnixFS
110
241
  }
111
242
 
243
+ /**
244
+ * Options to pass to the touch command
245
+ */
112
246
  export interface TouchOptions extends AbortOptions {
247
+ /**
248
+ * Optional mtime to set on the DAG root, defaults to the current time
249
+ */
113
250
  mtime?: Mtime
251
+
252
+ /**
253
+ * Optional path to set mtime on directory contents
254
+ */
114
255
  path?: string
256
+
257
+ /**
258
+ * If the DAG is a directory and this is true, update the mtime on all contents
259
+ */
115
260
  recursive: boolean
261
+
262
+ /**
263
+ * DAGs with a root block larger than this value will be sharded. Blocks
264
+ * smaller than this value will be regular UnixFS directories.
265
+ */
116
266
  shardSplitThresholdBytes: number
117
267
  }
118
268
 
269
+ /**
270
+ * The UnixFS interface provides familiar filesystem operations to make working with
271
+ * UnixFS DAGs simple and intuitive.
272
+ */
119
273
  export interface UnixFS {
274
+ /**
275
+ * Add all files and directories from the passed stream. This method wraps the
276
+ * `importer` export from the `ipfs-unixfs-importer` module - please see the docs
277
+ * for input/output types.
278
+ *
279
+ * @example
280
+ *
281
+ * ```typescript
282
+ * const source = [{
283
+ * path: './foo.txt',
284
+ * content: Uint8Array.from([0, 1, 2, 3])
285
+ * }, {
286
+ * path: './bar.txt',
287
+ * content: Uint8Array.from([4, 5, 6, 7])
288
+ * }]
289
+ *
290
+ * for await (const entry of fs.import(source)) {
291
+ * console.info(entry)
292
+ * }
293
+ * ```
294
+ */
295
+ addAll: (source: ImportCandidateStream, options?: Partial<ImporterOptions>) => AsyncIterable<ImportResult>
296
+
297
+ /**
298
+ * Add a single `Uint8Array` to your Helia node as a file.
299
+ *
300
+ * @example
301
+ *
302
+ * ```typescript
303
+ * const cid = await fs.addBytes(Uint8Array.from([0, 1, 2, 3]))
304
+ *
305
+ * console.info(cid)
306
+ * ```
307
+ */
308
+ addBytes: (bytes: Uint8Array, options?: Partial<ImporterOptions>) => Promise<CID>
309
+
310
+ /**
311
+ * Add a stream of `Uint8Array` to your Helia node as a file.
312
+ *
313
+ * @example
314
+ *
315
+ * ```typescript
316
+ * import fs from 'node:fs'
317
+ *
318
+ * const stream = fs.createReadStream('./foo.txt')
319
+ * const cid = await fs.addByteStream(stream)
320
+ *
321
+ * console.info(cid)
322
+ * ```
323
+ */
324
+ addByteStream: (bytes: ByteStream, options?: Partial<ImporterOptions>) => Promise<CID>
325
+
326
+ /**
327
+ * Add a file to your Helia node with optional metadata.
328
+ *
329
+ * @example
330
+ *
331
+ * ```typescript
332
+ * const cid = await fs.addFile({
333
+ * path: './foo.txt'
334
+ * content: Uint8Array.from([0, 1, 2, 3]),
335
+ * mode: 0x755,
336
+ * mtime: {
337
+ * secs: 10n,
338
+ * nsecs: 0
339
+ * }
340
+ * })
341
+ *
342
+ * console.info(cid)
343
+ * ```
344
+ */
345
+ addFile: (file: FileCandidate, options?: Partial<ImporterOptions>) => Promise<CID>
346
+
347
+ /**
348
+ * Add a directory to your Helia node.
349
+ *
350
+ * @example
351
+ *
352
+ * ```typescript
353
+ * const cid = await fs.addDirectory()
354
+ *
355
+ * console.info(cid)
356
+ * ```
357
+ */
358
+ addDirectory: (dir?: Partial<DirectoryCandidate>, options?: Partial<ImporterOptions>) => Promise<CID>
359
+
360
+ /**
361
+ * Retrieve the contents of a file from your Helia node.
362
+ *
363
+ * @example
364
+ *
365
+ * ```typescript
366
+ * for await (const buf of fs.cat(cid)) {
367
+ * console.info(buf)
368
+ * }
369
+ * ```
370
+ */
120
371
  cat: (cid: CID, options?: Partial<CatOptions>) => AsyncIterable<Uint8Array>
121
- chmod: (source: CID, mode: number, options?: Partial<ChmodOptions>) => Promise<CID>
372
+
373
+ /**
374
+ * Change the permissions on a file or directory in a DAG
375
+ *
376
+ * @example
377
+ *
378
+ * ```typescript
379
+ * const beforeCid = await fs.addBytes(Uint8Array.from([0, 1, 2, 3]))
380
+ * const beforeStats = await fs.stat(beforeCid)
381
+ *
382
+ * const afterCid = await fs.chmod(cid, 0x755)
383
+ * const afterStats = await fs.stat(afterCid)
384
+ *
385
+ * console.info(beforeCid, beforeStats)
386
+ * console.info(afterCid, afterStats)
387
+ * ```
388
+ */
389
+ chmod: (cid: CID, mode: number, options?: Partial<ChmodOptions>) => Promise<CID>
390
+
391
+ /**
392
+ * Add a file or directory to a target directory.
393
+ *
394
+ * @example
395
+ *
396
+ * ```typescript
397
+ * const fileCid = await fs.addBytes(Uint8Array.from([0, 1, 2, 3]))
398
+ * const directoryCid = await fs.addDirectory()
399
+ *
400
+ * const updatedCid = await fs.cp(fileCid, directoryCid, 'foo.txt')
401
+ *
402
+ * console.info(updatedCid)
403
+ * ```
404
+ */
122
405
  cp: (source: CID, target: CID, name: string, options?: Partial<CpOptions>) => Promise<CID>
406
+
407
+ /**
408
+ * List directory contents.
409
+ *
410
+ * @example
411
+ *
412
+ * ```typescript
413
+ * for await (const entry of fs.ls(directoryCid)) {
414
+ * console.info(etnry)
415
+ * }
416
+ * ```
417
+ */
123
418
  ls: (cid: CID, options?: Partial<LsOptions>) => AsyncIterable<UnixFSEntry>
419
+
420
+ /**
421
+ * Make a new directory under an existing directory.
422
+ *
423
+ * @example
424
+ *
425
+ * ```typescript
426
+ * const directoryCid = await fs.addDirectory()
427
+ *
428
+ * const updatedCid = await fs.mkdir(directoryCid, 'new-dir')
429
+ *
430
+ * console.info(updatedCid)
431
+ * ```
432
+ */
124
433
  mkdir: (cid: CID, dirname: string, options?: Partial<MkdirOptions>) => Promise<CID>
434
+
435
+ /**
436
+ * Remove a file or directory from an existing directory.
437
+ *
438
+ * @example
439
+ *
440
+ * ```typescript
441
+ * const directoryCid = await fs.addDirectory()
442
+ * const updatedCid = await fs.mkdir(directoryCid, 'new-dir')
443
+ *
444
+ * const finalCid = await fs.rm(updatedCid, 'new-dir')
445
+ *
446
+ * console.info(finalCid)
447
+ * ```
448
+ */
125
449
  rm: (cid: CID, path: string, options?: Partial<RmOptions>) => Promise<CID>
450
+
451
+ /**
452
+ * Return statistics about a UnixFS DAG.
453
+ *
454
+ * @example
455
+ *
456
+ * ```typescript
457
+ * const fileCid = await fs.addBytes(Uint8Array.from([0, 1, 2, 3]))
458
+ *
459
+ * const stats = await fs.stat(fileCid)
460
+ *
461
+ * console.info(stats)
462
+ * ```
463
+ */
126
464
  stat: (cid: CID, options?: Partial<StatOptions>) => Promise<UnixFSStats>
465
+
466
+ /**
467
+ * Update the mtime of a UnixFS DAG
468
+ *
469
+ * @example
470
+ *
471
+ * ```typescript
472
+ * const beforeCid = await fs.addBytes(Uint8Array.from([0, 1, 2, 3]))
473
+ * const beforeStats = await fs.stat(beforeCid)
474
+ *
475
+ * const afterCid = await fs.touch(beforeCid)
476
+ * const afterStats = await fs.stat(afterCid)
477
+ *
478
+ * console.info(beforeCid, beforeStats)
479
+ * console.info(afterCid, afterStats)
480
+ * ```
481
+ */
127
482
  touch: (cid: CID, options?: Partial<TouchOptions>) => Promise<CID>
128
483
  }
129
484
 
@@ -134,12 +489,32 @@ class DefaultUnixFS implements UnixFS {
134
489
  this.components = components
135
490
  }
136
491
 
492
+ async * addAll (source: ImportCandidateStream, options: Partial<ImporterOptions> = {}): AsyncIterable<ImportResult> {
493
+ yield * addAll(source, this.components.blockstore, options)
494
+ }
495
+
496
+ async addBytes (bytes: Uint8Array, options: Partial<ImporterOptions> = {}): Promise<CID> {
497
+ return await addBytes(bytes, this.components.blockstore, options)
498
+ }
499
+
500
+ async addByteStream (bytes: ByteStream, options: Partial<ImporterOptions> = {}): Promise<CID> {
501
+ return await addByteStream(bytes, this.components.blockstore, options)
502
+ }
503
+
504
+ async addFile (file: FileCandidate, options: Partial<ImporterOptions> = {}): Promise<CID> {
505
+ return await addFile(file, this.components.blockstore, options)
506
+ }
507
+
508
+ async addDirectory (dir: Partial<DirectoryCandidate> = {}, options: Partial<ImporterOptions> = {}): Promise<CID> {
509
+ return await addDirectory(dir, this.components.blockstore, options)
510
+ }
511
+
137
512
  async * cat (cid: CID, options: Partial<CatOptions> = {}): AsyncIterable<Uint8Array> {
138
513
  yield * cat(cid, this.components.blockstore, options)
139
514
  }
140
515
 
141
- async chmod (source: CID, mode: number, options: Partial<ChmodOptions> = {}): Promise<CID> {
142
- return await chmod(source, mode, this.components.blockstore, options)
516
+ async chmod (cid: CID, mode: number, options: Partial<ChmodOptions> = {}): Promise<CID> {
517
+ return await chmod(cid, mode, this.components.blockstore, options)
143
518
  }
144
519
 
145
520
  async cp (source: CID, target: CID, name: string, options: Partial<CpOptions> = {}): Promise<CID> {
@@ -167,6 +542,9 @@ class DefaultUnixFS implements UnixFS {
167
542
  }
168
543
  }
169
544
 
545
+ /**
546
+ * Create a {@link UnixFS} instance for use with {@link https://github.com/ipfs/helia Helia}
547
+ */
170
548
  export function unixfs (helia: { blockstore: Blockstore }): UnixFS {
171
549
  return new DefaultUnixFS(helia)
172
550
  }