helia 6.1.4 → 7.0.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.
Files changed (92) hide show
  1. package/dist/index.min.js +65 -55
  2. package/dist/index.min.js.map +4 -4
  3. package/dist/src/block-storage.d.ts +62 -0
  4. package/dist/src/block-storage.d.ts.map +1 -0
  5. package/dist/src/block-storage.js +159 -0
  6. package/dist/src/block-storage.js.map +1 -0
  7. package/dist/src/datastore-version.d.ts +3 -0
  8. package/dist/src/datastore-version.d.ts.map +1 -0
  9. package/dist/src/datastore-version.js +20 -0
  10. package/dist/src/datastore-version.js.map +1 -0
  11. package/dist/src/get-codec.d.ts +4 -0
  12. package/dist/src/get-codec.d.ts.map +1 -0
  13. package/dist/src/get-codec.js +31 -0
  14. package/dist/src/get-codec.js.map +1 -0
  15. package/dist/src/get-crypto.d.ts +4 -0
  16. package/dist/src/get-crypto.d.ts.map +1 -0
  17. package/dist/src/get-crypto.js +35 -0
  18. package/dist/src/get-crypto.js.map +1 -0
  19. package/dist/src/get-hasher.d.ts +4 -0
  20. package/dist/src/get-hasher.d.ts.map +1 -0
  21. package/dist/src/get-hasher.js +31 -0
  22. package/dist/src/get-hasher.js.map +1 -0
  23. package/dist/src/helia.d.ts +165 -0
  24. package/dist/src/helia.d.ts.map +1 -0
  25. package/dist/src/helia.js +165 -0
  26. package/dist/src/helia.js.map +1 -0
  27. package/dist/src/index.d.ts +30 -19
  28. package/dist/src/index.d.ts.map +1 -1
  29. package/dist/src/index.js +78 -12
  30. package/dist/src/index.js.map +1 -1
  31. package/dist/src/networked-storage.d.ts +28 -0
  32. package/dist/src/networked-storage.d.ts.map +1 -0
  33. package/dist/src/networked-storage.js +52 -0
  34. package/dist/src/networked-storage.js.map +1 -0
  35. package/dist/src/pins.d.ts +21 -0
  36. package/dist/src/pins.d.ts.map +1 -0
  37. package/dist/src/pins.js +140 -0
  38. package/dist/src/pins.js.map +1 -0
  39. package/dist/src/routing.d.ts +51 -0
  40. package/dist/src/routing.d.ts.map +1 -0
  41. package/dist/src/routing.js +311 -0
  42. package/dist/src/routing.js.map +1 -0
  43. package/dist/src/session-storage.d.ts +47 -0
  44. package/dist/src/session-storage.d.ts.map +1 -0
  45. package/dist/src/session-storage.js +148 -0
  46. package/dist/src/session-storage.js.map +1 -0
  47. package/dist/src/storage.d.ts +55 -0
  48. package/dist/src/storage.d.ts.map +1 -0
  49. package/dist/src/storage.js +225 -0
  50. package/dist/src/storage.js.map +1 -0
  51. package/dist/src/version.d.ts +1 -1
  52. package/dist/src/version.js +1 -1
  53. package/dist/typedoc-urls.json +3 -6
  54. package/package.json +38 -41
  55. package/src/block-storage.ts +194 -0
  56. package/src/datastore-version.ts +25 -0
  57. package/src/get-codec.ts +39 -0
  58. package/src/get-crypto.ts +44 -0
  59. package/src/get-hasher.ts +39 -0
  60. package/src/helia.ts +364 -0
  61. package/src/index.ts +58 -30
  62. package/src/networked-storage.ts +74 -0
  63. package/src/pins.ts +208 -0
  64. package/src/routing.ts +389 -0
  65. package/src/session-storage.ts +174 -0
  66. package/src/storage.ts +294 -0
  67. package/src/version.ts +1 -1
  68. package/dist/src/utils/bootstrappers.d.ts +0 -4
  69. package/dist/src/utils/bootstrappers.d.ts.map +0 -1
  70. package/dist/src/utils/bootstrappers.js +0 -13
  71. package/dist/src/utils/bootstrappers.js.map +0 -1
  72. package/dist/src/utils/helia-defaults.d.ts +0 -48
  73. package/dist/src/utils/helia-defaults.d.ts.map +0 -1
  74. package/dist/src/utils/helia-defaults.js +0 -85
  75. package/dist/src/utils/helia-defaults.js.map +0 -1
  76. package/dist/src/utils/libp2p-defaults.browser.d.ts +0 -19
  77. package/dist/src/utils/libp2p-defaults.browser.d.ts.map +0 -1
  78. package/dist/src/utils/libp2p-defaults.browser.js +0 -73
  79. package/dist/src/utils/libp2p-defaults.browser.js.map +0 -1
  80. package/dist/src/utils/libp2p-defaults.d.ts +0 -49
  81. package/dist/src/utils/libp2p-defaults.d.ts.map +0 -1
  82. package/dist/src/utils/libp2p-defaults.js +0 -113
  83. package/dist/src/utils/libp2p-defaults.js.map +0 -1
  84. package/dist/src/utils/libp2p.d.ts +0 -19
  85. package/dist/src/utils/libp2p.d.ts.map +0 -1
  86. package/dist/src/utils/libp2p.js +0 -19
  87. package/dist/src/utils/libp2p.js.map +0 -1
  88. package/src/utils/bootstrappers.ts +0 -12
  89. package/src/utils/helia-defaults.ts +0 -92
  90. package/src/utils/libp2p-defaults.browser.ts +0 -92
  91. package/src/utils/libp2p-defaults.ts +0 -137
  92. package/src/utils/libp2p.ts +0 -42
@@ -0,0 +1,44 @@
1
+ import { UnknownCryptoError } from '@helia/interface'
2
+ import { isPromise } from '@helia/utils'
3
+ import { ecdsaCrypto, ed25519Crypto, rsaCrypto } from '@ipshipyard/crypto'
4
+ import type { CryptoLoader } from '@helia/interface'
5
+ import type { Crypto } from '@ipshipyard/crypto'
6
+
7
+ export function getCrypto (initialCryptos: Array<Crypto> = [], loadCrypto?: CryptoLoader): CryptoLoader {
8
+ const cryptos: Record<string | number, Crypto> = {}
9
+
10
+ initialCryptos = [
11
+ ecdsaCrypto(),
12
+ ed25519Crypto(),
13
+ rsaCrypto(),
14
+ ...initialCryptos
15
+ ]
16
+
17
+ initialCryptos.forEach(crypto => {
18
+ cryptos[crypto.type] = crypto
19
+ cryptos[crypto.code] = crypto
20
+ })
21
+
22
+ return async (nameOrCode) => {
23
+ let crypto = cryptos[nameOrCode]
24
+
25
+ if (crypto == null && loadCrypto != null) {
26
+ const res = loadCrypto(nameOrCode)
27
+
28
+ if (isPromise(res)) {
29
+ crypto = await res
30
+ } else {
31
+ crypto = res
32
+ }
33
+
34
+ cryptos[crypto.type] = crypto
35
+ cryptos[crypto.code] = crypto
36
+ }
37
+
38
+ if (crypto != null) {
39
+ return crypto
40
+ }
41
+
42
+ throw new UnknownCryptoError(`Could not load crypto for ${crypto}`)
43
+ }
44
+ }
@@ -0,0 +1,39 @@
1
+ import { UnknownHashAlgorithmError } from '@helia/interface'
2
+ import { isPromise } from '@helia/utils'
3
+ import { identity } from 'multiformats/hashes/identity'
4
+ import { sha256 } from 'multiformats/hashes/sha2'
5
+ import type { HasherLoader } from '@helia/interface'
6
+ import type { MultihashHasher } from 'multiformats/hashes/interface'
7
+
8
+ export function getHasher (initialHashers: MultihashHasher[] = [], loadHasher?: HasherLoader): HasherLoader {
9
+ const hashers: Record<number, MultihashHasher> = {
10
+ [sha256.code]: sha256,
11
+ [identity.code]: identity
12
+ }
13
+
14
+ initialHashers.forEach(hasher => {
15
+ hashers[hasher.code] = hasher
16
+ })
17
+
18
+ return async (code) => {
19
+ let hasher = hashers[code]
20
+
21
+ if (hasher == null && loadHasher != null) {
22
+ const res = loadHasher(code)
23
+
24
+ if (isPromise(res)) {
25
+ hasher = await res
26
+ } else {
27
+ hasher = res
28
+ }
29
+
30
+ hashers[hasher.code] = hasher
31
+ }
32
+
33
+ if (hasher != null) {
34
+ return hasher
35
+ }
36
+
37
+ throw new UnknownHashAlgorithmError(`No hasher configured for multihash code 0x${code.toString(16)}, please configure one. You can look up which hash this is at https://github.com/multiformats/multicodec/blob/master/table.csv`)
38
+ }
39
+ }
package/src/helia.ts ADDED
@@ -0,0 +1,364 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * This module contains utility code that is shared between various Helia
5
+ * modules such as `helia`, `@helia/http`, etc.
6
+ */
7
+
8
+ import { InvalidConfigurationError } from '@helia/utils'
9
+ import { keychain } from '@ipshipyard/keychain'
10
+ import { start, stop } from '@libp2p/interface'
11
+ import { dns } from '@multiformats/dns'
12
+ import { defaultLogger } from 'birnam'
13
+ import { MemoryBlockstore } from 'blockstore-core'
14
+ import { MemoryDatastore } from 'datastore-core'
15
+ import drain from 'it-drain'
16
+ import { TypedEventEmitter } from 'main-event'
17
+ import { CustomProgressEvent } from 'progress-events'
18
+ import { BlockStorage } from './block-storage.ts'
19
+ import { assertDatastoreVersionIsCurrent } from './datastore-version.ts'
20
+ import { getCodec } from './get-codec.ts'
21
+ import { getCrypto } from './get-crypto.ts'
22
+ import { getHasher } from './get-hasher.ts'
23
+ import { NetworkedStorage } from './networked-storage.ts'
24
+ import { PinsImpl } from './pins.ts'
25
+ import { Routing as RoutingClass } from './routing.ts'
26
+ import type { BlockStorageInit } from './block-storage.ts'
27
+ import type { CodecLoader, GCOptions, HasherLoader, Helia as HeliaInterface, HeliaEvents, Routing, CryptoLoader, Crypto, NodeInfo, Router, HeliaMixin } from '@helia/interface'
28
+ import type { BlockBroker } from '@helia/interface'
29
+ import type { Pins } from '@helia/interface'
30
+ import type { Keychain, KeychainInit } from '@ipshipyard/keychain'
31
+ import type { ComponentLogger, Logger, Metrics } from '@libp2p/interface'
32
+ import type { DNS } from '@multiformats/dns'
33
+ import type { Blockstore } from 'interface-blockstore'
34
+ import type { Datastore } from 'interface-datastore'
35
+ import type { BlockCodec } from 'multiformats'
36
+ import type { CID } from 'multiformats/cid'
37
+ import type { MultihashHasher } from 'multiformats/hashes/interface'
38
+
39
+ export type { BlockStorage, BlockStorageInit }
40
+
41
+ /**
42
+ * Options used to create a Helia node.
43
+ */
44
+ export interface HeliaInit {
45
+ /**
46
+ * By default Helia stores the node's PeerId in an encrypted form in a
47
+ * libp2p keystore. These options control how that keystore is configured.
48
+ */
49
+ keychain?: KeychainInit
50
+
51
+ /**
52
+ * The blockstore is where blocks are stored
53
+ */
54
+ blockstore?: Blockstore
55
+
56
+ /**
57
+ * The datastore is where data is stored
58
+ */
59
+ datastore?: Datastore
60
+
61
+ /**
62
+ * By default sha256, sha512 and identity hashes are supported for
63
+ * bitswap operations. To bitswap blocks with CIDs using other hashes
64
+ * pass appropriate MultihashHashers here.
65
+ */
66
+ hashers?: MultihashHasher[]
67
+
68
+ /**
69
+ * An optional function that can load a MultihashHasher on demand. May return
70
+ * a promise.
71
+ */
72
+ loadHasher?(code: number): MultihashHasher | Promise<MultihashHasher>
73
+
74
+ /**
75
+ * A BlockCodec allows converting a block to an object representation
76
+ */
77
+ codecs?: Array<BlockCodec<any, any>>
78
+
79
+ /**
80
+ * An optional function that can load a BlockCodec on demand. May return a
81
+ * promise.
82
+ */
83
+ loadCodec?(code: number): BlockCodec<any, any> | Promise<BlockCodec<any, any>>
84
+
85
+ /**
86
+ * A list of pre-supported public/private key implementations
87
+ */
88
+ cryptos?: Array<Crypto>
89
+
90
+ /**
91
+ * Dynamically load a cryptography implementation
92
+ */
93
+ loadCrypto?: CryptoLoader
94
+
95
+ /**
96
+ * Garbage collection requires preventing blockstore writes during searches
97
+ * for unpinned blocks as DAGs are typically pinned after they've been
98
+ * imported - without locking this could lead to the deletion of blocks while
99
+ * they are being added to the blockstore.
100
+ *
101
+ * By default this lock is held on the current process and other processes
102
+ * will contact this process for access.
103
+ *
104
+ * If Helia is being run in multiple processes, one process must hold the GC
105
+ * lock so use this option to control which process that is.
106
+ *
107
+ * @default true
108
+ */
109
+ holdGcLock?: boolean
110
+
111
+ /**
112
+ * An optional logging component to pass to libp2p. If not specified the
113
+ * default implementation from libp2p will be used.
114
+ */
115
+ logger?: ComponentLogger
116
+
117
+ /**
118
+ * A list of strategies used to fetch blocks when they are not present in
119
+ * the local blockstore
120
+ */
121
+ blockBrokers?: Array<BlockBroker | ((components: any) => BlockBroker)>
122
+
123
+ /**
124
+ * Routers perform operations such as looking up content providers,
125
+ * information about network peers or getting/putting records.
126
+ */
127
+ routers?: Array<Router | ((components: any) => Router)>
128
+
129
+ /**
130
+ * During provider lookups, peers can be returned from routing implementations
131
+ * with no multiaddrs.
132
+ *
133
+ * This can happen when they've been retrieved from network peers that only
134
+ * store multiaddrs for a limited amount of time.
135
+ *
136
+ * When this happens the peer's info has to be looked up with a further query.
137
+ *
138
+ * To not have this query block the yielding of other providers returned with
139
+ * multiaddrs, a separate queue is used to perform this lookup.
140
+ *
141
+ * This config value controls the concurrency of that queue.
142
+ *
143
+ * @default 5
144
+ */
145
+ providerLookupConcurrency?: number
146
+
147
+ /**
148
+ * Components used by subclasses
149
+ */
150
+ components?: Record<string, any>
151
+
152
+ /**
153
+ * An optional DNS implementation used to perform queries for DNS records.
154
+ */
155
+ dns?: DNS
156
+
157
+ /**
158
+ * A metrics object that can be used to collected arbitrary stats about node
159
+ * usage.
160
+ */
161
+ metrics?: Metrics
162
+
163
+ /**
164
+ * Limit the maximum supported size of identity hash digests to this value
165
+ *
166
+ * @default 128
167
+ */
168
+ maxIdentityHashDigestLength?: number
169
+ }
170
+
171
+ interface Components {
172
+ blockstore: Blockstore
173
+ datastore: Datastore
174
+ logger: ComponentLogger
175
+ blockBrokers: BlockBroker[]
176
+ routing: Routing
177
+ dns: DNS
178
+ keychain: Keychain
179
+ metrics?: Metrics
180
+ getCodec: CodecLoader
181
+ getHasher: HasherLoader
182
+ getCrypto: CryptoLoader
183
+ }
184
+
185
+ export class Helia implements HeliaInterface {
186
+ public info: NodeInfo
187
+ public blockstore: BlockStorage
188
+ public datastore: Datastore
189
+ public events: TypedEventEmitter<HeliaEvents<this>>
190
+ public pins: Pins
191
+ public logger: ComponentLogger
192
+ public routing: RoutingClass
193
+ public getCodec: CodecLoader
194
+ public getHasher: HasherLoader
195
+ public getCrypto: CryptoLoader
196
+ public dns: DNS
197
+ public keychain: Keychain
198
+ public metrics?: Metrics
199
+ public status: 'stopped' | 'stopping' | 'starting' | 'started'
200
+ private readonly log: Logger
201
+ private readonly blockBrokers: BlockBroker[]
202
+ private readonly mixins: HeliaMixin[]
203
+
204
+ constructor (init: HeliaInit & { name: string, version: string }) {
205
+ this.info = {
206
+ name: init.name,
207
+ version: init.version
208
+ }
209
+ this.logger = init.logger ?? defaultLogger()
210
+ this.log = this.logger.forComponent('helia')
211
+ this.getHasher = getHasher(init.hashers, init.loadHasher)
212
+ this.getCodec = getCodec(init.codecs, init.loadCodec)
213
+ this.getCrypto = getCrypto(init.cryptos, init.loadCrypto)
214
+ this.dns = init.dns ?? dns()
215
+ this.metrics = init.metrics
216
+ this.events = new TypedEventEmitter<HeliaEvents<typeof this>>()
217
+ this.status = 'stopped'
218
+ this.mixins = []
219
+
220
+ // @ts-expect-error routing and keychain are not set
221
+ const components: Components = {
222
+ blockstore: init.blockstore ?? new MemoryBlockstore(),
223
+ datastore: init.datastore ?? new MemoryDatastore(),
224
+ logger: this.logger,
225
+ blockBrokers: [],
226
+ getHasher: this.getHasher,
227
+ getCodec: this.getCodec,
228
+ getCrypto: this.getCrypto,
229
+ dns: this.dns,
230
+ metrics: this.metrics,
231
+ ...(init.components ?? {})
232
+ }
233
+
234
+ this.keychain = components.keychain = keychain()(components)
235
+
236
+ this.routing = components.routing = new RoutingClass(components, {
237
+ routers: (init.routers ?? []).flatMap((router: Router | ((components: any) => Router)) => {
238
+ if (typeof router === 'function') {
239
+ router = router(components)
240
+ }
241
+
242
+ // if the router itself is a router
243
+ const routers = [
244
+ router
245
+ ]
246
+
247
+ return routers
248
+ }),
249
+ providerLookupConcurrency: init.providerLookupConcurrency
250
+ })
251
+
252
+ this.blockBrokers = components.blockBrokers = (init.blockBrokers ?? []).map((broker) => {
253
+ if (typeof broker === 'function') {
254
+ broker = broker(components)
255
+ }
256
+
257
+ return broker
258
+ })
259
+
260
+ const networkedStorage = new NetworkedStorage(components, init)
261
+ this.pins = new PinsImpl(components.datastore, networkedStorage, this.getCodec)
262
+ this.blockstore = new BlockStorage(networkedStorage, this.pins, this.routing, {
263
+ holdGcLock: init.holdGcLock ?? true
264
+ })
265
+ this.datastore = components.datastore
266
+ }
267
+
268
+ hasRouter (name: string): boolean {
269
+ return this.routing.hasRouter(name)
270
+ }
271
+
272
+ addRouter (router: Router): void {
273
+ this.routing.addRouter(router)
274
+ }
275
+
276
+ hasBlockBroker (name: string): boolean {
277
+ return this.blockBrokers.findIndex(b => b.name === name) !== -1
278
+ }
279
+
280
+ addBlockBroker (blockBroker: BlockBroker): void {
281
+ this.blockBrokers.push(blockBroker)
282
+ }
283
+
284
+ addMixin (mixin: HeliaMixin): void {
285
+ if (this.mixins.find(m => m.name === mixin.name) != null) {
286
+ throw new InvalidConfigurationError(`A mixin with the name "${mixin.name} is already present`)
287
+ }
288
+
289
+ this.mixins.push(mixin)
290
+ }
291
+
292
+ async start (): Promise<this> {
293
+ this.status = 'starting'
294
+
295
+ await assertDatastoreVersionIsCurrent(this.datastore)
296
+ await start(
297
+ this.blockstore,
298
+ this.datastore,
299
+ this.routing,
300
+ ...this.blockBrokers
301
+ )
302
+
303
+ for (const mixin of this.mixins) {
304
+ await mixin.start?.(this)
305
+ }
306
+
307
+ this.status = 'started'
308
+ this.events.dispatchEvent(new CustomEvent('start', { detail: this }))
309
+
310
+ return this
311
+ }
312
+
313
+ async stop (): Promise<this> {
314
+ this.status = 'stopping'
315
+
316
+ for (const mixin of this.mixins) {
317
+ await mixin.stop?.(this)
318
+ }
319
+
320
+ await stop(
321
+ this.blockstore,
322
+ this.datastore,
323
+ this.routing,
324
+ ...this.blockBrokers
325
+ )
326
+
327
+ this.status = 'stopped'
328
+ this.events.dispatchEvent(new CustomEvent('stop', { detail: this }))
329
+
330
+ return this
331
+ }
332
+
333
+ async gc (options: GCOptions = {}): Promise<void> {
334
+ const releaseLock = await this.blockstore.lock.writeLock()
335
+
336
+ try {
337
+ const helia = this
338
+ const blockstore = this.blockstore.unwrap()
339
+
340
+ this.log('gc start')
341
+
342
+ await drain(blockstore.deleteMany((async function * (): AsyncGenerator<CID> {
343
+ for await (const { cid } of blockstore.getAll()) {
344
+ try {
345
+ if (await helia.pins.isPinned(cid, options)) {
346
+ continue
347
+ }
348
+
349
+ yield cid
350
+
351
+ options.onProgress?.(new CustomProgressEvent<CID>('helia:gc:deleted', cid))
352
+ } catch (err: any) {
353
+ helia.log.error('error during gc - %e', err)
354
+ options.onProgress?.(new CustomProgressEvent<Error>('helia:gc:error', err))
355
+ }
356
+ }
357
+ }())))
358
+ } finally {
359
+ releaseLock()
360
+ }
361
+
362
+ this.log('gc finished')
363
+ }
364
+ }
package/src/index.ts CHANGED
@@ -19,15 +19,17 @@
19
19
  * ```
20
20
  */
21
21
 
22
- import { Helia as HeliaClass } from '@helia/utils'
23
- import { heliaDefaults } from './utils/helia-defaults.ts'
24
- import { libp2pDefaults } from './utils/libp2p-defaults.ts'
25
- import type { DefaultLibp2pServices } from './utils/libp2p-defaults.ts'
26
- import type { Libp2pDefaultsOptions } from './utils/libp2p.ts'
22
+ import { withBitswap } from '@helia/bitswap'
23
+ import { withHTTP } from '@helia/http'
24
+ import { withLibp2p } from '@helia/libp2p'
25
+ import * as dagCbor from '@ipld/dag-cbor'
26
+ import * as dagJson from '@ipld/dag-json'
27
+ import * as json from 'multiformats/codecs/json'
28
+ import { sha512 } from 'multiformats/hashes/sha2'
29
+ import { Helia as HeliaClass } from './helia.ts'
30
+ import { name, version } from './version.ts'
31
+ import type { HeliaInit } from './helia.ts'
27
32
  import type { Helia } from '@helia/interface'
28
- import type { HeliaInit } from '@helia/utils'
29
- import type { Libp2p } from '@libp2p/interface'
30
- import type { CID } from 'multiformats/cid'
31
33
 
32
34
  // re-export interface types so people don't have to depend on @helia/interface
33
35
  // if they don't want to
@@ -35,20 +37,6 @@ export * from '@helia/interface'
35
37
 
36
38
  export type { HeliaInit }
37
39
 
38
- export type { DefaultLibp2pServices, Libp2pDefaultsOptions }
39
-
40
- // allow amending the default config
41
- export { libp2pDefaults }
42
- export { heliaDefaults }
43
-
44
- /**
45
- * DAGWalkers take a block and yield CIDs encoded in that block
46
- */
47
- export interface DAGWalker {
48
- codec: number
49
- walk(block: Uint8Array): Generator<CID, void, undefined>
50
- }
51
-
52
40
  /**
53
41
  * Create and return a Helia node
54
42
  *
@@ -70,15 +58,55 @@ export interface DAGWalker {
70
58
  * }
71
59
  * ```
72
60
  */
73
- export async function createHelia <T extends Libp2p> (init: Partial<HeliaInit<T>>): Promise<Helia<T>>
74
- export async function createHelia (init?: Partial<HeliaInit<Libp2p<DefaultLibp2pServices>>>): Promise<Helia<Libp2p<DefaultLibp2pServices>>>
75
- export async function createHelia (init: Partial<HeliaInit> = {}): Promise<Helia> {
76
- const options = await heliaDefaults(init)
77
- const helia = new HeliaClass(options)
61
+ export function createHelia (init: HeliaInit = {}): Helia {
62
+ return withBitswap(withLibp2p(withHTTP(createHeliaLight({
63
+ ...init,
64
+ codecs: [
65
+ dagCbor,
66
+ dagJson,
67
+ json,
68
+ ...(init.codecs ?? [])
69
+ ],
70
+ hashers: [
71
+ sha512,
72
+ ...(init.hashers ?? [])
73
+ ]
74
+ }))))
75
+ }
78
76
 
79
- if (options.start !== false) {
80
- await helia.start()
81
- }
77
+ /**
78
+ * Create and return a Helia node without and routing or block broker config.
79
+ *
80
+ * The only supported codecs are `dag-pb` and `raw`, and the only supported
81
+ * hashes are `sha2-256` and `identity`.
82
+ *
83
+ * This allows more flexible customization and the smallest possible bundle size
84
+ * in web browsers.
85
+ *
86
+ * @example Creating a Helia node
87
+ *
88
+ * ```ts
89
+ * import { createHeliaLight } from 'helia'
90
+ * import { unixfs } from '@helia/unixfs'
91
+ * import { CID } from 'multiformats/cid'
92
+ *
93
+ * const helia = await createHeliaLight()
94
+ * const fs = unixfs(helia)
95
+ * const cid = CID.parse('QmFoo...')
96
+ *
97
+ * for await (const buf of fs.cat(cid, {
98
+ * signal: AbortSignal.timeout(5_000)
99
+ * })) {
100
+ * console.info(buf)
101
+ * }
102
+ * ```
103
+ */
104
+ export function createHeliaLight (init: HeliaInit = {}): Helia {
105
+ const helia = new HeliaClass({
106
+ name,
107
+ version,
108
+ ...init
109
+ })
82
110
 
83
111
  return helia
84
112
  }
@@ -0,0 +1,74 @@
1
+ import { InvalidConfigurationError } from '@helia/utils'
2
+ import { start, stop } from '@libp2p/interface'
3
+ import { SessionStorage } from './session-storage.ts'
4
+ import { Storage } from './storage.ts'
5
+ import type { StorageComponents, StorageInit } from './storage.ts'
6
+ import type { BlockBroker, Blocks, CreateSessionOptions, SessionBlockstore } from '@helia/interface'
7
+ import type { Startable } from '@libp2p/interface'
8
+ import type { AbortOptions } from 'abort-error'
9
+ import type { Blockstore } from 'interface-blockstore'
10
+ import type { CID } from 'multiformats/cid'
11
+
12
+ export interface GetOptions extends AbortOptions {
13
+ progress?(evt: Event): void
14
+ }
15
+
16
+ export type NetworkedStorageComponents = StorageComponents<BlockBroker>
17
+
18
+ /**
19
+ * Networked storage wraps a regular blockstore - when getting blocks if the
20
+ * blocks are not present, the configured BlockBrokers will be used to fetch them.
21
+ */
22
+ export class NetworkedStorage extends Storage<BlockBroker> implements Blocks, Startable {
23
+ private started: boolean
24
+
25
+ /**
26
+ * Create a new BlockStorage
27
+ */
28
+ constructor (components: NetworkedStorageComponents, init: StorageInit = {}) {
29
+ super(components, init)
30
+
31
+ this.started = false
32
+ }
33
+
34
+ isStarted (): boolean {
35
+ return this.started
36
+ }
37
+
38
+ async start (): Promise<void> {
39
+ await start(this.child, ...this.blockBrokers)
40
+ this.started = true
41
+ }
42
+
43
+ async stop (): Promise<void> {
44
+ await stop(this.child, ...this.blockBrokers)
45
+ this.started = false
46
+ }
47
+
48
+ unwrap (): Blockstore {
49
+ return this.child
50
+ }
51
+
52
+ createSession (root: CID, options?: CreateSessionOptions): SessionBlockstore {
53
+ if (this.blockBrokers.length === 0) {
54
+ throw new InvalidConfigurationError('No block brokers configured')
55
+ }
56
+
57
+ const blockBrokers = this.blockBrokers
58
+ .map(broker => broker.createSession?.(options))
59
+ .filter(broker => broker != null)
60
+
61
+ if (blockBrokers.length === 0) {
62
+ throw new InvalidConfigurationError(`No configured block brokers support sessions - tried ${this.blockBrokers.map(b => b.name).join(', ')}`)
63
+ }
64
+
65
+ return new SessionStorage({
66
+ blockstore: this.child,
67
+ blockBrokers,
68
+ getHasher: this.getHasher,
69
+ logger: this.logger
70
+ }, {
71
+ root
72
+ })
73
+ }
74
+ }