@helia/utils 2.1.0 → 2.1.1-760ed27f
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 +2 -2
- package/dist/index.min.js.map +3 -3
- package/dist/src/abstract-session.d.ts.map +1 -1
- package/dist/src/abstract-session.js +3 -2
- package/dist/src/abstract-session.js.map +1 -1
- package/dist/src/errors.d.ts +5 -1
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +7 -3
- package/dist/src/errors.js.map +1 -1
- package/dist/src/graph-walker.d.ts.map +1 -1
- package/dist/src/graph-walker.js +43 -64
- package/dist/src/graph-walker.js.map +1 -1
- package/dist/src/utils/datastore-version.js +2 -2
- package/dist/src/utils/datastore-version.js.map +1 -1
- package/dist/src/utils/networked-storage.d.ts.map +1 -1
- package/dist/src/utils/networked-storage.js +6 -0
- package/dist/src/utils/networked-storage.js.map +1 -1
- package/package.json +3 -3
- package/src/abstract-session.ts +3 -2
- package/src/errors.ts +8 -3
- package/src/graph-walker.ts +48 -76
- package/src/utils/datastore-version.ts +2 -2
- package/src/utils/networked-storage.ts +7 -0
- package/dist/typedoc-urls.json +0 -18
package/src/graph-walker.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Queue } from '@libp2p/utils'
|
|
2
|
+
import filter from 'it-filter'
|
|
2
3
|
import toBuffer from 'it-to-buffer'
|
|
3
4
|
import { createUnsafe } from 'multiformats/block'
|
|
4
5
|
import type { CodecLoader } from '@helia/interface'
|
|
@@ -39,35 +40,22 @@ interface JobOptions extends AbortOptions {
|
|
|
39
40
|
path: CID[]
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
class
|
|
43
|
+
abstract class AbstractGraphWalker {
|
|
43
44
|
private readonly components: GraphWalkerComponents
|
|
44
45
|
|
|
45
|
-
constructor (components: GraphWalkerComponents, init: GraphWalkerInit
|
|
46
|
+
constructor (components: GraphWalkerComponents, init: GraphWalkerInit) {
|
|
46
47
|
this.components = components
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
async * walk <T = any> (cid: CID, options
|
|
50
|
-
const queue =
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (a.options.depth === b.options.depth) {
|
|
54
|
-
return 0
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (a.options.depth < b.options.depth) {
|
|
58
|
-
return 1
|
|
59
|
-
}
|
|
50
|
+
async * walk <T = any> (cid: CID, options?: AbortOptions): AsyncGenerator<GraphNode<T>> {
|
|
51
|
+
const queue = this.getQueue()
|
|
52
|
+
const gen = filter(queue.toGenerator(options), (node) => node != null) as AsyncGenerator<GraphNode<T>>
|
|
53
|
+
let finished = false
|
|
60
54
|
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
const gen = queue.toGenerator()
|
|
66
|
-
|
|
67
|
-
const job = async (options: JobOptions): Promise<GraphNode<T>> => {
|
|
55
|
+
const job = async (options: JobOptions): Promise<GraphNode<T> | undefined> => {
|
|
68
56
|
const cid = options.cid
|
|
69
57
|
const bytes = await toBuffer(this.components.blockstore.get(cid, options))
|
|
70
|
-
const block = createUnsafe({
|
|
58
|
+
const block = createUnsafe<T, number, number, 0 | 1>({
|
|
71
59
|
cid,
|
|
72
60
|
bytes,
|
|
73
61
|
codec: await this.components.getCodec(cid.code)
|
|
@@ -80,9 +68,13 @@ class DepthFirstGraphWalker {
|
|
|
80
68
|
depth: options.depth + 1,
|
|
81
69
|
path: [...options.path, linkedCid]
|
|
82
70
|
})
|
|
71
|
+
// eslint-disable-next-line no-loop-func
|
|
83
72
|
.catch(err => {
|
|
84
|
-
|
|
85
|
-
|
|
73
|
+
// only throw if the generator is still yielding results, otherwise
|
|
74
|
+
// it can cause unhandled promise rejections
|
|
75
|
+
if (!finished) {
|
|
76
|
+
gen.throw(err)
|
|
77
|
+
}
|
|
86
78
|
})
|
|
87
79
|
}
|
|
88
80
|
|
|
@@ -100,23 +92,28 @@ class DepthFirstGraphWalker {
|
|
|
100
92
|
path: [cid]
|
|
101
93
|
})
|
|
102
94
|
.catch(err => {
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
// only throw if the generator is still yielding results, otherwise it
|
|
96
|
+
// can cause unhandled promise rejections
|
|
97
|
+
if (!finished) {
|
|
98
|
+
gen.throw(err)
|
|
99
|
+
}
|
|
105
100
|
})
|
|
106
101
|
|
|
107
|
-
|
|
102
|
+
try {
|
|
103
|
+
yield * gen
|
|
104
|
+
} finally {
|
|
105
|
+
finished = true
|
|
106
|
+
// abort any in-progress operations
|
|
107
|
+
queue.abort()
|
|
108
|
+
}
|
|
108
109
|
}
|
|
109
|
-
}
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
constructor (components: GraphWalkerComponents, init: GraphWalkerInit = {}) {
|
|
115
|
-
this.components = components
|
|
116
|
-
}
|
|
111
|
+
abstract getQueue <T> (): Queue<GraphNode<T> | undefined, JobOptions>
|
|
112
|
+
}
|
|
117
113
|
|
|
118
|
-
|
|
119
|
-
|
|
114
|
+
class DepthFirstGraphWalker extends AbstractGraphWalker {
|
|
115
|
+
getQueue<T>(): Queue<GraphNode<T> | undefined, JobOptions> {
|
|
116
|
+
return new Queue<GraphNode<T> | undefined, JobOptions>({
|
|
120
117
|
concurrency: 1,
|
|
121
118
|
sort: (a, b) => {
|
|
122
119
|
if (a.options.depth === b.options.depth) {
|
|
@@ -124,55 +121,30 @@ class BreadthFirstGraphWalker {
|
|
|
124
121
|
}
|
|
125
122
|
|
|
126
123
|
if (a.options.depth < b.options.depth) {
|
|
127
|
-
return
|
|
124
|
+
return 1
|
|
128
125
|
}
|
|
129
126
|
|
|
130
|
-
return 1
|
|
127
|
+
return -1
|
|
131
128
|
}
|
|
132
129
|
})
|
|
130
|
+
}
|
|
131
|
+
}
|
|
133
132
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
codec: await this.components.getCodec(cid.code)
|
|
143
|
-
})
|
|
133
|
+
class BreadthFirstGraphWalker extends AbstractGraphWalker {
|
|
134
|
+
getQueue<T>(): Queue<GraphNode<T> | undefined, JobOptions> {
|
|
135
|
+
return new Queue<GraphNode<T> | undefined, JobOptions>({
|
|
136
|
+
concurrency: 1,
|
|
137
|
+
sort: (a, b) => {
|
|
138
|
+
if (a.options.depth === b.options.depth) {
|
|
139
|
+
return 0
|
|
140
|
+
}
|
|
144
141
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
cid: linkedCid,
|
|
149
|
-
depth: options.depth + 1,
|
|
150
|
-
path: [...options.path, linkedCid]
|
|
151
|
-
})
|
|
152
|
-
.catch(err => {
|
|
153
|
-
gen.throw(err)
|
|
154
|
-
queue.abort()
|
|
155
|
-
})
|
|
156
|
-
}
|
|
142
|
+
if (a.options.depth < b.options.depth) {
|
|
143
|
+
return -1
|
|
144
|
+
}
|
|
157
145
|
|
|
158
|
-
|
|
159
|
-
block,
|
|
160
|
-
depth: options.depth,
|
|
161
|
-
path: options.path
|
|
146
|
+
return 1
|
|
162
147
|
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
queue.add(job, {
|
|
166
|
-
...options,
|
|
167
|
-
cid,
|
|
168
|
-
depth: 0,
|
|
169
|
-
path: [cid]
|
|
170
148
|
})
|
|
171
|
-
.catch(err => {
|
|
172
|
-
gen.throw(err)
|
|
173
|
-
queue.abort()
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
yield * gen
|
|
177
149
|
}
|
|
178
150
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Key } from 'interface-datastore'
|
|
2
2
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
3
3
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
4
|
-
import {
|
|
4
|
+
import { InvalidDatastoreVersionError } from '../errors.js'
|
|
5
5
|
import type { Datastore } from 'interface-datastore'
|
|
6
6
|
|
|
7
7
|
const DS_VERSION_KEY = new Key('/version')
|
|
@@ -20,6 +20,6 @@ export async function assertDatastoreVersionIsCurrent (datastore: Datastore): Pr
|
|
|
20
20
|
|
|
21
21
|
if (version !== CURRENT_VERSION) {
|
|
22
22
|
// TODO: write migrations when we break compatibility - for an example, see https://github.com/ipfs/js-ipfs-repo/tree/master/packages/ipfs-repo-migrations
|
|
23
|
-
throw new
|
|
23
|
+
throw new InvalidDatastoreVersionError('Invalid datastore version, a datastore migration may be required')
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -5,6 +5,7 @@ import filter from 'it-filter'
|
|
|
5
5
|
import forEach from 'it-foreach'
|
|
6
6
|
import { CustomProgressEvent } from 'progress-events'
|
|
7
7
|
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
|
|
8
|
+
import { InvalidConfigurationError } from '../errors.ts'
|
|
8
9
|
import { isPromise } from './is-promise.js'
|
|
9
10
|
import type { HasherLoader } from '@helia/interface'
|
|
10
11
|
import type { BlockBroker, Blocks, Pair, DeleteManyBlocksProgressEvents, DeleteBlockProgressEvents, GetBlockProgressEvents, GetManyBlocksProgressEvents, PutManyBlocksProgressEvents, PutBlockProgressEvents, GetAllBlocksProgressEvents, GetOfflineOptions, BlockRetrievalOptions, CreateSessionOptions, SessionBlockstore } from '@helia/interface/blocks'
|
|
@@ -446,6 +447,10 @@ async function raceBlockRetrievers (cid: CID, blockBrokers: BlockBroker[], hashe
|
|
|
446
447
|
}
|
|
447
448
|
}
|
|
448
449
|
|
|
450
|
+
if (retrievers.length === 0) {
|
|
451
|
+
throw new InvalidConfigurationError(`No block brokers capable of retrieving blocks are configured, the CID ${cid} cannot be fetched from the network`)
|
|
452
|
+
}
|
|
453
|
+
|
|
449
454
|
try {
|
|
450
455
|
return await Promise.any(
|
|
451
456
|
retrievers
|
|
@@ -457,6 +462,7 @@ async function raceBlockRetrievers (cid: CID, blockBrokers: BlockBroker[], hashe
|
|
|
457
462
|
signal,
|
|
458
463
|
validateFn: async (block: Uint8Array): Promise<void> => {
|
|
459
464
|
await validateFn(block)
|
|
465
|
+
options.signal?.throwIfAborted()
|
|
460
466
|
blocksWereValidated = true
|
|
461
467
|
}
|
|
462
468
|
})
|
|
@@ -465,6 +471,7 @@ async function raceBlockRetrievers (cid: CID, blockBrokers: BlockBroker[], hashe
|
|
|
465
471
|
// the blockBroker either did not throw an error when attempting to validate the block
|
|
466
472
|
// or did not call the validateFn at all. We should validate the block ourselves
|
|
467
473
|
await validateFn(block)
|
|
474
|
+
options.signal?.throwIfAborted()
|
|
468
475
|
}
|
|
469
476
|
|
|
470
477
|
return block
|
package/dist/typedoc-urls.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"AbstractSession": "https://ipfs.github.io/helia/classes/_helia_utils.AbstractSession.html",
|
|
3
|
-
"Helia": "https://ipfs.github.io/helia/classes/_helia_utils.Helia.html",
|
|
4
|
-
".:Helia": "https://ipfs.github.io/helia/classes/_helia_utils.Helia.html",
|
|
5
|
-
"AbstractCreateSessionOptions": "https://ipfs.github.io/helia/interfaces/_helia_utils.AbstractCreateSessionOptions.html",
|
|
6
|
-
"AbstractSessionComponents": "https://ipfs.github.io/helia/interfaces/_helia_utils.AbstractSessionComponents.html",
|
|
7
|
-
"BlockStorage": "https://ipfs.github.io/helia/interfaces/_helia_utils.BlockStorage.html",
|
|
8
|
-
"BlockStorageInit": "https://ipfs.github.io/helia/interfaces/_helia_utils.BlockStorageInit.html",
|
|
9
|
-
"BlockstoreSessionEvents": "https://ipfs.github.io/helia/interfaces/_helia_utils.BlockstoreSessionEvents.html",
|
|
10
|
-
"GraphNode": "https://ipfs.github.io/helia/interfaces/_helia_utils.GraphNode.html",
|
|
11
|
-
"GraphWalker": "https://ipfs.github.io/helia/interfaces/_helia_utils.GraphWalker.html",
|
|
12
|
-
"GraphWalkerComponents": "https://ipfs.github.io/helia/interfaces/_helia_utils.GraphWalkerComponents.html",
|
|
13
|
-
"GraphWalkerInit": "https://ipfs.github.io/helia/interfaces/_helia_utils.GraphWalkerInit.html",
|
|
14
|
-
"HeliaInit": "https://ipfs.github.io/helia/interfaces/_helia_utils.HeliaInit.html",
|
|
15
|
-
".:HeliaInit": "https://ipfs.github.io/helia/interfaces/helia.HeliaInit.html",
|
|
16
|
-
"breadthFirstWalker": "https://ipfs.github.io/helia/functions/_helia_utils.breadthFirstWalker.html",
|
|
17
|
-
"depthFirstWalker": "https://ipfs.github.io/helia/functions/_helia_utils.depthFirstWalker.html"
|
|
18
|
-
}
|