@helia/unixfs 1.2.4 → 1.4.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.
- package/dist/index.min.js +3 -1
- package/dist/src/commands/chmod.js +1 -1
- package/dist/src/commands/chmod.js.map +1 -1
- package/dist/src/commands/touch.js +1 -1
- package/dist/src/commands/touch.js.map +1 -1
- package/dist/src/commands/utils/add-link.js +2 -2
- package/dist/src/commands/utils/add-link.js.map +1 -1
- package/dist/src/commands/utils/is-over-shard-threshold.d.ts +2 -1
- package/dist/src/commands/utils/is-over-shard-threshold.d.ts.map +1 -1
- package/dist/src/commands/utils/is-over-shard-threshold.js +5 -5
- package/dist/src/commands/utils/is-over-shard-threshold.js.map +1 -1
- package/dist/src/commands/utils/remove-link.js +1 -1
- package/dist/src/commands/utils/remove-link.js.map +1 -1
- package/dist/src/index.d.ts +54 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +14 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/utils/glob-source.d.ts +39 -0
- package/dist/src/utils/glob-source.d.ts.map +1 -0
- package/dist/src/utils/glob-source.js +42 -0
- package/dist/src/utils/glob-source.js.map +1 -0
- package/dist/src/utils/url-source.d.ts +3 -0
- package/dist/src/utils/url-source.d.ts.map +1 -0
- package/dist/src/utils/url-source.js +29 -0
- package/dist/src/utils/url-source.js.map +1 -0
- package/dist/typedoc-urls.json +4 -1
- package/package.json +12 -2
- package/src/commands/chmod.ts +1 -1
- package/src/commands/touch.ts +1 -1
- package/src/commands/utils/add-link.ts +2 -2
- package/src/commands/utils/is-over-shard-threshold.ts +6 -5
- package/src/commands/utils/remove-link.ts +1 -1
- package/src/index.ts +63 -0
- package/src/utils/glob-source.ts +92 -0
- package/src/utils/url-source.ts +35 -0
package/src/commands/touch.ts
CHANGED
|
@@ -108,7 +108,7 @@ export async function touch (cid: CID, blockstore: Blocks, options: Partial<Touc
|
|
|
108
108
|
return updatePathCids(root.cid, resolved, blockstore, opts)
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
const block = await blockstore.get(resolved.cid)
|
|
111
|
+
const block = await blockstore.get(resolved.cid, options)
|
|
112
112
|
let metadata: UnixFS
|
|
113
113
|
let links: PBLink[] = []
|
|
114
114
|
|
|
@@ -52,12 +52,12 @@ export async function addLink (parent: Directory, child: Required<PBLink>, block
|
|
|
52
52
|
|
|
53
53
|
const result = await addToDirectory(parent, child, blockstore, options)
|
|
54
54
|
|
|
55
|
-
if (await isOverShardThreshold(result.node, blockstore, options.shardSplitThresholdBytes)) {
|
|
55
|
+
if (await isOverShardThreshold(result.node, blockstore, options.shardSplitThresholdBytes, options)) {
|
|
56
56
|
log('converting directory to sharded directory')
|
|
57
57
|
|
|
58
58
|
const converted = await convertToShardedDirectory(result, blockstore)
|
|
59
59
|
result.cid = converted.cid
|
|
60
|
-
result.node = dagPB.decode(await blockstore.get(converted.cid))
|
|
60
|
+
result.node = dagPB.decode(await blockstore.get(converted.cid, options))
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
return result
|
|
@@ -3,6 +3,7 @@ import { UnixFS } from 'ipfs-unixfs'
|
|
|
3
3
|
import { CID_V0, CID_V1 } from './dir-sharded.js'
|
|
4
4
|
import type { Blocks } from '@helia/interface/blocks'
|
|
5
5
|
import type { PBNode } from '@ipld/dag-pb'
|
|
6
|
+
import type { AbortOptions } from '@libp2p/interfaces'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Estimate node size only based on DAGLink name and CID byte lengths
|
|
@@ -10,7 +11,7 @@ import type { PBNode } from '@ipld/dag-pb'
|
|
|
10
11
|
*
|
|
11
12
|
* If the node is a hamt sharded directory the calculation is based on if it was a regular directory.
|
|
12
13
|
*/
|
|
13
|
-
export async function isOverShardThreshold (node: PBNode, blockstore: Blocks, threshold: number): Promise<boolean> {
|
|
14
|
+
export async function isOverShardThreshold (node: PBNode, blockstore: Blocks, threshold: number, options: AbortOptions): Promise<boolean> {
|
|
14
15
|
if (node.Data == null) {
|
|
15
16
|
throw new Error('DagPB node had no data')
|
|
16
17
|
}
|
|
@@ -21,7 +22,7 @@ export async function isOverShardThreshold (node: PBNode, blockstore: Blocks, th
|
|
|
21
22
|
if (unixfs.type === 'directory') {
|
|
22
23
|
size = estimateNodeSize(node)
|
|
23
24
|
} else if (unixfs.type === 'hamt-sharded-directory') {
|
|
24
|
-
size = await estimateShardSize(node, 0, threshold, blockstore)
|
|
25
|
+
size = await estimateShardSize(node, 0, threshold, blockstore, options)
|
|
25
26
|
} else {
|
|
26
27
|
throw new Error('Can only estimate the size of directories or shards')
|
|
27
28
|
}
|
|
@@ -42,7 +43,7 @@ function estimateNodeSize (node: PBNode): number {
|
|
|
42
43
|
return size
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
async function estimateShardSize (node: PBNode, current: number, max: number, blockstore: Blocks): Promise<number> {
|
|
46
|
+
async function estimateShardSize (node: PBNode, current: number, max: number, blockstore: Blocks, options: AbortOptions): Promise<number> {
|
|
46
47
|
if (current > max) {
|
|
47
48
|
return max
|
|
48
49
|
}
|
|
@@ -67,10 +68,10 @@ async function estimateShardSize (node: PBNode, current: number, max: number, bl
|
|
|
67
68
|
current += link.Hash.bytes.byteLength
|
|
68
69
|
|
|
69
70
|
if (link.Hash.code === dagPb.code) {
|
|
70
|
-
const block = await blockstore.get(link.Hash)
|
|
71
|
+
const block = await blockstore.get(link.Hash, options)
|
|
71
72
|
const node = dagPb.decode(block)
|
|
72
73
|
|
|
73
|
-
current += await estimateShardSize(node, current, max, blockstore)
|
|
74
|
+
current += await estimateShardSize(node, current, max, blockstore, options)
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -41,7 +41,7 @@ export async function removeLink (parent: Directory, name: string, blockstore: B
|
|
|
41
41
|
|
|
42
42
|
const result = await removeFromShardedDirectory(parent, name, blockstore, options)
|
|
43
43
|
|
|
44
|
-
if (!(await isOverShardThreshold(result.node, blockstore, options.shardSplitThresholdBytes))) {
|
|
44
|
+
if (!(await isOverShardThreshold(result.node, blockstore, options.shardSplitThresholdBytes, options))) {
|
|
45
45
|
log('converting shard to flat directory %c', parent.cid)
|
|
46
46
|
|
|
47
47
|
return convertToFlatDirectory(result, blockstore, options)
|
package/src/index.ts
CHANGED
|
@@ -29,6 +29,18 @@
|
|
|
29
29
|
* console.info(entry)
|
|
30
30
|
* }
|
|
31
31
|
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
*
|
|
35
|
+
* Recursively adding a directory (Node.js-compatibly environments only):
|
|
36
|
+
*
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import { globSource } from '@helia/unixfs'
|
|
39
|
+
*
|
|
40
|
+
* for await (const entry of fs.addAll(globSource('path/to/containing/dir', 'glob-pattern'))) {
|
|
41
|
+
* console.info(entry)
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
32
44
|
*/
|
|
33
45
|
|
|
34
46
|
import { addAll, addBytes, addByteStream, addDirectory, addFile } from './commands/add.js'
|
|
@@ -80,6 +92,12 @@ export interface CatOptions extends AbortOptions, ProgressOptions<GetEvents> {
|
|
|
80
92
|
* An optional path to allow reading files inside directories
|
|
81
93
|
*/
|
|
82
94
|
path?: string
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* If true, do not perform any network operations and throw if blocks are
|
|
98
|
+
* missing from the local store. (default: false)
|
|
99
|
+
*/
|
|
100
|
+
offline?: boolean
|
|
83
101
|
}
|
|
84
102
|
|
|
85
103
|
/**
|
|
@@ -102,6 +120,12 @@ export interface ChmodOptions extends AbortOptions, ProgressOptions<GetEvents |
|
|
|
102
120
|
* smaller than this value will be regular UnixFS directories.
|
|
103
121
|
*/
|
|
104
122
|
shardSplitThresholdBytes: number
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* If true, do not perform any network operations and throw if blocks are
|
|
126
|
+
* missing from the local store. (default: false)
|
|
127
|
+
*/
|
|
128
|
+
offline?: boolean
|
|
105
129
|
}
|
|
106
130
|
|
|
107
131
|
/**
|
|
@@ -118,6 +142,12 @@ export interface CpOptions extends AbortOptions, ProgressOptions<GetEvents | Put
|
|
|
118
142
|
* smaller than this value will be regular UnixFS directories.
|
|
119
143
|
*/
|
|
120
144
|
shardSplitThresholdBytes: number
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* If true, do not perform any network operations and throw if blocks are
|
|
148
|
+
* missing from the local store. (default: false)
|
|
149
|
+
*/
|
|
150
|
+
offline?: boolean
|
|
121
151
|
}
|
|
122
152
|
|
|
123
153
|
/**
|
|
@@ -139,6 +169,12 @@ export interface LsOptions extends AbortOptions, ProgressOptions<GetEvents> {
|
|
|
139
169
|
* Stop reading the directory contents after this many directory entries
|
|
140
170
|
*/
|
|
141
171
|
length?: number
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* If true, do not perform any network operations and throw if blocks are
|
|
175
|
+
* missing from the local store. (default: false)
|
|
176
|
+
*/
|
|
177
|
+
offline?: boolean
|
|
142
178
|
}
|
|
143
179
|
|
|
144
180
|
/**
|
|
@@ -171,6 +207,12 @@ export interface MkdirOptions extends AbortOptions, ProgressOptions<GetEvents |
|
|
|
171
207
|
* smaller than this value will be regular UnixFS directories.
|
|
172
208
|
*/
|
|
173
209
|
shardSplitThresholdBytes: number
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* If true, do not perform any network operations and throw if blocks are
|
|
213
|
+
* missing from the local store. (default: false)
|
|
214
|
+
*/
|
|
215
|
+
offline?: boolean
|
|
174
216
|
}
|
|
175
217
|
|
|
176
218
|
/**
|
|
@@ -182,6 +224,12 @@ export interface RmOptions extends AbortOptions, ProgressOptions<GetEvents | Put
|
|
|
182
224
|
* smaller than this value will be regular UnixFS directories.
|
|
183
225
|
*/
|
|
184
226
|
shardSplitThresholdBytes: number
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* If true, do not perform any network operations and throw if blocks are
|
|
230
|
+
* missing from the local store. (default: false)
|
|
231
|
+
*/
|
|
232
|
+
offline?: boolean
|
|
185
233
|
}
|
|
186
234
|
|
|
187
235
|
/**
|
|
@@ -192,6 +240,12 @@ export interface StatOptions extends AbortOptions, ProgressOptions<GetEvents> {
|
|
|
192
240
|
* An optional path to allow statting paths inside directories
|
|
193
241
|
*/
|
|
194
242
|
path?: string
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* If true, do not perform any network operations and throw if blocks are
|
|
246
|
+
* missing from the local store. (default: false)
|
|
247
|
+
*/
|
|
248
|
+
offline?: boolean
|
|
195
249
|
}
|
|
196
250
|
|
|
197
251
|
/**
|
|
@@ -275,6 +329,12 @@ export interface TouchOptions extends AbortOptions, ProgressOptions<GetEvents |
|
|
|
275
329
|
* smaller than this value will be regular UnixFS directories.
|
|
276
330
|
*/
|
|
277
331
|
shardSplitThresholdBytes: number
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* If true, do not perform any network operations and throw if blocks are
|
|
335
|
+
* missing from the local store. (default: false)
|
|
336
|
+
*/
|
|
337
|
+
offline?: boolean
|
|
278
338
|
}
|
|
279
339
|
|
|
280
340
|
/**
|
|
@@ -559,3 +619,6 @@ class DefaultUnixFS implements UnixFS {
|
|
|
559
619
|
export function unixfs (helia: { blockstore: Blocks }): UnixFS {
|
|
560
620
|
return new DefaultUnixFS(helia)
|
|
561
621
|
}
|
|
622
|
+
|
|
623
|
+
export { globSource } from './utils/glob-source.js'
|
|
624
|
+
export { urlSource } from './utils/url-source.js'
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import fsp from 'node:fs/promises'
|
|
3
|
+
import Path from 'node:path'
|
|
4
|
+
import glob from 'it-glob'
|
|
5
|
+
import { InvalidParametersError } from '../errors.js'
|
|
6
|
+
import type { MtimeLike } from 'ipfs-unixfs'
|
|
7
|
+
import type { ImportCandidateStream } from 'ipfs-unixfs-importer'
|
|
8
|
+
|
|
9
|
+
export interface GlobSourceOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Include .dot files in matched paths
|
|
12
|
+
*/
|
|
13
|
+
hidden?: boolean
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* follow symlinks
|
|
17
|
+
*/
|
|
18
|
+
followSymlinks?: boolean
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Preserve mode
|
|
22
|
+
*/
|
|
23
|
+
preserveMode?: boolean
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Preserve mtime
|
|
27
|
+
*/
|
|
28
|
+
preserveMtime?: boolean
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* mode to use - if preserveMode is true this will be ignored
|
|
32
|
+
*/
|
|
33
|
+
mode?: number
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* mtime to use - if preserveMtime is true this will be ignored
|
|
37
|
+
*/
|
|
38
|
+
mtime?: MtimeLike
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface GlobSourceResult {
|
|
42
|
+
path: string
|
|
43
|
+
content: AsyncIterable<Uint8Array> | undefined
|
|
44
|
+
mode: number | undefined
|
|
45
|
+
mtime: MtimeLike | undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create an async iterator that yields paths that match requested glob pattern
|
|
50
|
+
*/
|
|
51
|
+
export async function * globSource (cwd: string, pattern: string, options: GlobSourceOptions = {}): ImportCandidateStream {
|
|
52
|
+
if (typeof pattern !== 'string') {
|
|
53
|
+
throw new InvalidParametersError('Pattern must be a string')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!Path.isAbsolute(cwd)) {
|
|
57
|
+
cwd = Path.resolve(process.cwd(), cwd)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const globOptions = Object.assign({}, {
|
|
61
|
+
nodir: false,
|
|
62
|
+
realpath: false,
|
|
63
|
+
absolute: true,
|
|
64
|
+
dot: Boolean(options.hidden),
|
|
65
|
+
follow: options.followSymlinks != null ? options.followSymlinks : true
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
for await (const p of glob(cwd, pattern, globOptions)) {
|
|
69
|
+
const stat = await fsp.stat(p)
|
|
70
|
+
|
|
71
|
+
let mode = options.mode
|
|
72
|
+
|
|
73
|
+
if (options.preserveMode === true) {
|
|
74
|
+
mode = stat.mode
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let mtime = options.mtime
|
|
78
|
+
|
|
79
|
+
if (options.preserveMtime === true) {
|
|
80
|
+
mtime = stat.mtime
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
yield {
|
|
84
|
+
path: toPosix(p.replace(cwd, '')),
|
|
85
|
+
content: stat.isFile() ? fs.createReadStream(p) : undefined,
|
|
86
|
+
mode,
|
|
87
|
+
mtime
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const toPosix = (path: string): string => path.replace(/\\/g, '/')
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { UnknownError } from '../errors.js'
|
|
2
|
+
import type { FileCandidate } from 'ipfs-unixfs-importer'
|
|
3
|
+
|
|
4
|
+
export function urlSource (url: URL, options?: RequestInit): FileCandidate<AsyncGenerator<Uint8Array, void, unknown>> {
|
|
5
|
+
return {
|
|
6
|
+
path: decodeURIComponent(new URL(url).pathname.split('/').pop() ?? ''),
|
|
7
|
+
content: readURLContent(url, options)
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function * readURLContent (url: URL, options?: RequestInit): AsyncGenerator<Uint8Array, void, unknown> {
|
|
12
|
+
const response = await globalThis.fetch(url, options)
|
|
13
|
+
|
|
14
|
+
if (response.body == null) {
|
|
15
|
+
throw new UnknownError('HTTP response did not have a body')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const reader = response.body.getReader()
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
while (true) {
|
|
22
|
+
const { done, value } = await reader.read()
|
|
23
|
+
|
|
24
|
+
if (done) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (value != null) {
|
|
29
|
+
yield value
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
} finally {
|
|
33
|
+
reader.releaseLock()
|
|
34
|
+
}
|
|
35
|
+
}
|