helia 2.0.3 → 2.1.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 (67) hide show
  1. package/README.md +17 -8
  2. package/dist/index.min.js +40 -41
  3. package/dist/src/block-brokers/bitswap.d.ts +19 -0
  4. package/dist/src/block-brokers/bitswap.d.ts.map +1 -0
  5. package/dist/src/block-brokers/bitswap.js +48 -0
  6. package/dist/src/block-brokers/bitswap.js.map +1 -0
  7. package/dist/src/block-brokers/index.d.ts +3 -0
  8. package/dist/src/block-brokers/index.d.ts.map +1 -0
  9. package/dist/src/block-brokers/index.js +3 -0
  10. package/dist/src/block-brokers/index.js.map +1 -0
  11. package/dist/src/block-brokers/trustless-gateway/broker.d.ts +14 -0
  12. package/dist/src/block-brokers/trustless-gateway/broker.d.ts.map +1 -0
  13. package/dist/src/block-brokers/trustless-gateway/broker.js +55 -0
  14. package/dist/src/block-brokers/trustless-gateway/broker.js.map +1 -0
  15. package/dist/src/block-brokers/trustless-gateway/index.d.ts +9 -0
  16. package/dist/src/block-brokers/trustless-gateway/index.d.ts.map +1 -0
  17. package/dist/src/block-brokers/trustless-gateway/index.js +15 -0
  18. package/dist/src/block-brokers/trustless-gateway/index.js.map +1 -0
  19. package/dist/src/block-brokers/trustless-gateway/trustless-gateway.d.ts +31 -0
  20. package/dist/src/block-brokers/trustless-gateway/trustless-gateway.d.ts.map +1 -0
  21. package/dist/src/block-brokers/trustless-gateway/trustless-gateway.js +114 -0
  22. package/dist/src/block-brokers/trustless-gateway/trustless-gateway.js.map +1 -0
  23. package/dist/src/helia.d.ts +0 -1
  24. package/dist/src/helia.d.ts.map +1 -1
  25. package/dist/src/helia.js +19 -25
  26. package/dist/src/helia.js.map +1 -1
  27. package/dist/src/index.d.ts +13 -9
  28. package/dist/src/index.d.ts.map +1 -1
  29. package/dist/src/index.js +6 -8
  30. package/dist/src/index.js.map +1 -1
  31. package/dist/src/storage.d.ts +7 -2
  32. package/dist/src/storage.d.ts.map +1 -1
  33. package/dist/src/storage.js +14 -0
  34. package/dist/src/storage.js.map +1 -1
  35. package/dist/src/utils/default-hashers.d.ts +3 -0
  36. package/dist/src/utils/default-hashers.d.ts.map +1 -0
  37. package/dist/src/utils/default-hashers.js +11 -0
  38. package/dist/src/utils/default-hashers.js.map +1 -0
  39. package/dist/src/utils/libp2p-defaults.browser.d.ts +1 -0
  40. package/dist/src/utils/libp2p-defaults.browser.d.ts.map +1 -1
  41. package/dist/src/utils/libp2p-defaults.browser.js +2 -4
  42. package/dist/src/utils/libp2p-defaults.browser.js.map +1 -1
  43. package/dist/src/utils/libp2p-defaults.d.ts +1 -0
  44. package/dist/src/utils/libp2p-defaults.d.ts.map +1 -1
  45. package/dist/src/utils/libp2p-defaults.js +3 -4
  46. package/dist/src/utils/libp2p-defaults.js.map +1 -1
  47. package/dist/src/utils/networked-storage.d.ts +17 -9
  48. package/dist/src/utils/networked-storage.d.ts.map +1 -1
  49. package/dist/src/utils/networked-storage.js +109 -15
  50. package/dist/src/utils/networked-storage.js.map +1 -1
  51. package/dist/src/version.d.ts +1 -1
  52. package/dist/src/version.js +1 -1
  53. package/dist/typedoc-urls.json +10 -6
  54. package/package.json +32 -6
  55. package/src/block-brokers/bitswap.ts +78 -0
  56. package/src/block-brokers/index.ts +2 -0
  57. package/src/block-brokers/trustless-gateway/broker.ts +65 -0
  58. package/src/block-brokers/trustless-gateway/index.ts +28 -0
  59. package/src/block-brokers/trustless-gateway/trustless-gateway.ts +126 -0
  60. package/src/helia.ts +20 -30
  61. package/src/index.ts +14 -9
  62. package/src/storage.ts +19 -2
  63. package/src/utils/default-hashers.ts +12 -0
  64. package/src/utils/libp2p-defaults.browser.ts +3 -4
  65. package/src/utils/libp2p-defaults.ts +4 -4
  66. package/src/utils/networked-storage.ts +134 -23
  67. package/src/version.ts +1 -1
@@ -0,0 +1,78 @@
1
+ import { createBitswap } from 'ipfs-bitswap'
2
+ import type { BlockAnnouncer, BlockBroker, BlockRetrievalOptions, BlockRetriever } from '@helia/interface/blocks'
3
+ import type { Libp2p } from '@libp2p/interface'
4
+ import type { Startable } from '@libp2p/interface/startable'
5
+ import type { Blockstore } from 'interface-blockstore'
6
+ import type { Bitswap, BitswapNotifyProgressEvents, BitswapOptions, BitswapWantBlockProgressEvents } from 'ipfs-bitswap'
7
+ import type { CID } from 'multiformats/cid'
8
+ import type { MultihashHasher } from 'multiformats/hashes/interface'
9
+ import type { ProgressOptions } from 'progress-events'
10
+
11
+ interface BitswapComponents {
12
+ libp2p: Libp2p
13
+ blockstore: Blockstore
14
+ hashers: MultihashHasher[]
15
+ }
16
+
17
+ export interface BitswapInit extends BitswapOptions {
18
+
19
+ }
20
+
21
+ class BitswapBlockBroker implements BlockAnnouncer<ProgressOptions<BitswapNotifyProgressEvents>>, BlockRetriever<
22
+ ProgressOptions<BitswapWantBlockProgressEvents>
23
+ >, Startable {
24
+ private readonly bitswap: Bitswap
25
+ private started: boolean
26
+
27
+ constructor (components: BitswapComponents, init: BitswapInit = {}) {
28
+ const { libp2p, blockstore, hashers } = components
29
+
30
+ this.bitswap = createBitswap(libp2p, blockstore, {
31
+ hashLoader: {
32
+ getHasher: async (codecOrName: string | number): Promise<MultihashHasher<number>> => {
33
+ const hasher = hashers.find(hasher => {
34
+ return hasher.code === codecOrName || hasher.name === codecOrName
35
+ })
36
+
37
+ if (hasher != null) {
38
+ return hasher
39
+ }
40
+
41
+ throw new Error(`Could not load hasher for code/name "${codecOrName}"`)
42
+ }
43
+ },
44
+ ...init
45
+ })
46
+ this.started = false
47
+ }
48
+
49
+ isStarted (): boolean {
50
+ return this.started
51
+ }
52
+
53
+ async start (): Promise<void> {
54
+ await this.bitswap.start()
55
+ this.started = true
56
+ }
57
+
58
+ async stop (): Promise<void> {
59
+ await this.bitswap.stop()
60
+ this.started = false
61
+ }
62
+
63
+ announce (cid: CID, block: Uint8Array, options?: ProgressOptions<BitswapNotifyProgressEvents>): void {
64
+ this.bitswap.notify(cid, block, options)
65
+ }
66
+
67
+ async retrieve (cid: CID, { validateFn, ...options }: BlockRetrievalOptions<ProgressOptions<BitswapWantBlockProgressEvents>> = {}): Promise<Uint8Array> {
68
+ return this.bitswap.want(cid, options)
69
+ }
70
+ }
71
+
72
+ /**
73
+ * A helper factory for users who want to override Helia `blockBrokers` but
74
+ * still want to use the default `BitswapBlockBroker`.
75
+ */
76
+ export function bitswap (init: BitswapInit = {}): (components: BitswapComponents) => BlockBroker {
77
+ return (components) => new BitswapBlockBroker(components, init)
78
+ }
@@ -0,0 +1,2 @@
1
+ export { bitswap } from './bitswap.js'
2
+ export { trustlessGateway } from './trustless-gateway/index.js'
@@ -0,0 +1,65 @@
1
+ import { logger } from '@libp2p/logger'
2
+ import { TrustlessGateway } from './trustless-gateway.js'
3
+ import { DEFAULT_TRUSTLESS_GATEWAYS } from './index.js'
4
+ import type { TrustlessGatewayBlockBrokerInit, TrustlessGatewayGetBlockProgressEvents } from './index.js'
5
+ import type { BlockRetrievalOptions, BlockRetriever } from '@helia/interface/blocks'
6
+ import type { CID } from 'multiformats/cid'
7
+ import type { ProgressOptions } from 'progress-events'
8
+
9
+ const log = logger('helia:trustless-gateway-block-broker')
10
+
11
+ /**
12
+ * A class that accepts a list of trustless gateways that are queried
13
+ * for blocks.
14
+ */
15
+ export class TrustlessGatewayBlockBroker implements BlockRetriever<
16
+ ProgressOptions<TrustlessGatewayGetBlockProgressEvents>
17
+ > {
18
+ private readonly gateways: TrustlessGateway[]
19
+
20
+ constructor (init: TrustlessGatewayBlockBrokerInit = {}) {
21
+ this.gateways = (init.gateways ?? DEFAULT_TRUSTLESS_GATEWAYS)
22
+ .map((gatewayOrUrl) => {
23
+ return new TrustlessGateway(gatewayOrUrl)
24
+ })
25
+ }
26
+
27
+ async retrieve (cid: CID, options: BlockRetrievalOptions<ProgressOptions<TrustlessGatewayGetBlockProgressEvents>> = {}): Promise<Uint8Array> {
28
+ // Loop through the gateways until we get a block or run out of gateways
29
+ // TODO: switch to toSorted when support is better
30
+ const sortedGateways = this.gateways.sort((a, b) => b.reliability() - a.reliability())
31
+ const aggregateErrors: Error[] = []
32
+
33
+ for (const gateway of sortedGateways) {
34
+ log('getting block for %c from %s', cid, gateway.url)
35
+ try {
36
+ const block = await gateway.getRawBlock(cid, options.signal)
37
+ log.trace('got block for %c from %s', cid, gateway.url)
38
+ try {
39
+ await options.validateFn?.(block)
40
+ } catch (err) {
41
+ log.error('failed to validate block for %c from %s', cid, gateway.url, err)
42
+ gateway.incrementInvalidBlocks()
43
+
44
+ throw new Error(`unable to validate block for CID ${cid} from gateway ${gateway.url}`)
45
+ }
46
+
47
+ return block
48
+ } catch (err: unknown) {
49
+ log.error('failed to get block for %c from %s', cid, gateway.url, err)
50
+ if (err instanceof Error) {
51
+ aggregateErrors.push(err)
52
+ } else {
53
+ aggregateErrors.push(new Error(`unable to fetch raw block for CID ${cid} from gateway ${gateway.url}`))
54
+ }
55
+ // if signal was aborted, exit the loop
56
+ if (options.signal?.aborted === true) {
57
+ log.trace('request aborted while fetching raw block for CID %c from gateway %s', cid, gateway.url)
58
+ break
59
+ }
60
+ }
61
+ }
62
+
63
+ throw new AggregateError(aggregateErrors, `unable to fetch raw block for CID ${cid} from any gateway`)
64
+ }
65
+ }
@@ -0,0 +1,28 @@
1
+ import { TrustlessGatewayBlockBroker } from './broker.js'
2
+ import type { BlockRetriever } from '@helia/interface/src/blocks.js'
3
+ import type { ProgressEvent } from 'progress-events'
4
+
5
+ export const DEFAULT_TRUSTLESS_GATEWAYS = [
6
+ // 2023-10-03: IPNS, Origin, and Block/CAR support from https://ipfs-public-gateway-checker.on.fleek.co/
7
+ 'https://dweb.link',
8
+
9
+ // 2023-10-03: IPNS, Origin, and Block/CAR support from https://ipfs-public-gateway-checker.on.fleek.co/
10
+ 'https://cf-ipfs.com',
11
+
12
+ // 2023-10-03: IPNS, Origin, and Block/CAR support from https://ipfs-public-gateway-checker.on.fleek.co/
13
+ 'https://4everland.io',
14
+
15
+ // 2023-10-03: IPNS, Origin, and Block/CAR support from https://ipfs-public-gateway-checker.on.fleek.co/
16
+ 'https://w3s.link'
17
+ ]
18
+
19
+ export type TrustlessGatewayGetBlockProgressEvents =
20
+ ProgressEvent<'trustless-gateway:get-block:fetch', URL>
21
+
22
+ export interface TrustlessGatewayBlockBrokerInit {
23
+ gateways?: Array<string | URL>
24
+ }
25
+
26
+ export function trustlessGateway (init: TrustlessGatewayBlockBrokerInit = {}): () => BlockRetriever {
27
+ return () => new TrustlessGatewayBlockBroker(init)
28
+ }
@@ -0,0 +1,126 @@
1
+ import type { CID } from 'multiformats/cid'
2
+
3
+ /**
4
+ * A `TrustlessGateway` keeps track of the number of attempts, errors, and
5
+ * successes for a given gateway url so that we can prioritize gateways that
6
+ * have been more reliable in the past, and ensure that requests are distributed
7
+ * across all gateways within a given `TrustlessGatewayBlockBroker` instance.
8
+ */
9
+ export class TrustlessGateway {
10
+ public readonly url: URL
11
+ /**
12
+ * The number of times this gateway has been attempted to be used to fetch a
13
+ * block. This includes successful, errored, and aborted attempts. By counting
14
+ * even aborted attempts, slow gateways that are out-raced by others will be
15
+ * considered less reliable.
16
+ */
17
+ #attempts = 0
18
+
19
+ /**
20
+ * The number of times this gateway has errored while attempting to fetch a
21
+ * block. This includes `response.ok === false` and any other errors that
22
+ * throw while attempting to fetch a block. This does not include aborted
23
+ * attempts.
24
+ */
25
+ #errors = 0
26
+
27
+ /**
28
+ * The number of times this gateway has returned an invalid block. A gateway
29
+ * that returns the wrong blocks for a CID should be considered for removal
30
+ * from the list of gateways to fetch blocks from.
31
+ */
32
+ #invalidBlocks = 0
33
+
34
+ /**
35
+ * The number of times this gateway has successfully fetched a block.
36
+ */
37
+ #successes = 0
38
+
39
+ constructor (url: URL | string) {
40
+ this.url = url instanceof URL ? url : new URL(url)
41
+ }
42
+
43
+ /**
44
+ * Fetch a raw block from `this.url` following the specification defined at
45
+ * https://specs.ipfs.tech/http-gateways/trustless-gateway/
46
+ */
47
+ async getRawBlock (cid: CID, signal?: AbortSignal): Promise<Uint8Array> {
48
+ const gwUrl = this.url
49
+ gwUrl.pathname = `/ipfs/${cid.toString()}`
50
+
51
+ // necessary as not every gateway supports dag-cbor, but every should support
52
+ // sending raw block as-is
53
+ gwUrl.search = '?format=raw'
54
+
55
+ if (signal?.aborted === true) {
56
+ throw new Error(`Signal to fetch raw block for CID ${cid} from gateway ${this.url} was aborted prior to fetch`)
57
+ }
58
+
59
+ try {
60
+ this.#attempts++
61
+ const res = await fetch(gwUrl.toString(), {
62
+ signal,
63
+ headers: {
64
+ // also set header, just in case ?format= is filtered out by some
65
+ // reverse proxy
66
+ Accept: 'application/vnd.ipld.raw'
67
+ },
68
+ cache: 'force-cache'
69
+ })
70
+ if (!res.ok) {
71
+ this.#errors++
72
+ throw new Error(`unable to fetch raw block for CID ${cid} from gateway ${this.url}`)
73
+ }
74
+ this.#successes++
75
+ return new Uint8Array(await res.arrayBuffer())
76
+ } catch (cause) {
77
+ // @ts-expect-error - TS thinks signal?.aborted can only be false now
78
+ // because it was checked for true above.
79
+ if (signal?.aborted === true) {
80
+ throw new Error(`fetching raw block for CID ${cid} from gateway ${this.url} was aborted`)
81
+ }
82
+ this.#errors++
83
+ throw new Error(`unable to fetch raw block for CID ${cid}`)
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Encapsulate the logic for determining whether a gateway is considered
89
+ * reliable, for prioritization. This is based on the number of successful attempts made
90
+ * and the number of errors encountered.
91
+ *
92
+ * Unused gateways have 100% reliability; They will be prioritized over
93
+ * gateways with a 100% success rate to ensure that we attempt all gateways.
94
+ */
95
+ reliability (): number {
96
+ /**
97
+ * if we have never tried to use this gateway, it is considered the most
98
+ * reliable until we determine otherwise (prioritize unused gateways)
99
+ */
100
+ if (this.#attempts === 0) {
101
+ return 1
102
+ }
103
+
104
+ if (this.#invalidBlocks > 0) {
105
+ // this gateway may not be trustworthy..
106
+ return -Infinity
107
+ }
108
+
109
+ /**
110
+ * We have attempted the gateway, so we need to calculate the reliability
111
+ * based on the number of attempts, errors, and successes. Gateways that
112
+ * return a single error should drop their reliability score more than a
113
+ * single success increases it.
114
+ *
115
+ * Play around with the below reliability function at https://www.desmos.com/calculator/d6hfhf5ukm
116
+ */
117
+ return this.#successes / (this.#attempts + (this.#errors * 3))
118
+ }
119
+
120
+ /**
121
+ * Increment the number of invalid blocks returned by this gateway.
122
+ */
123
+ incrementInvalidBlocks (): void {
124
+ this.#invalidBlocks++
125
+ }
126
+ }
package/src/helia.ts CHANGED
@@ -1,12 +1,12 @@
1
+ import { start, stop } from '@libp2p/interface/startable'
1
2
  import { logger } from '@libp2p/logger'
2
- import { type Bitswap, createBitswap } from 'ipfs-bitswap'
3
3
  import drain from 'it-drain'
4
- import { identity } from 'multiformats/hashes/identity'
5
- import { sha256, sha512 } from 'multiformats/hashes/sha2'
6
4
  import { CustomProgressEvent } from 'progress-events'
5
+ import { bitswap, trustlessGateway } from './block-brokers/index.js'
7
6
  import { PinsImpl } from './pins.js'
8
7
  import { BlockStorage } from './storage.js'
9
8
  import { assertDatastoreVersionIsCurrent } from './utils/datastore-version.js'
9
+ import { defaultHashers } from './utils/default-hashers.js'
10
10
  import { NetworkedStorage } from './utils/networked-storage.js'
11
11
  import type { HeliaInit } from '.'
12
12
  import type { GCOptions, Helia } from '@helia/interface'
@@ -15,7 +15,6 @@ import type { Libp2p } from '@libp2p/interface'
15
15
  import type { Blockstore } from 'interface-blockstore'
16
16
  import type { Datastore } from 'interface-datastore'
17
17
  import type { CID } from 'multiformats/cid'
18
- import type { MultihashHasher } from 'multiformats/hashes/interface'
19
18
 
20
19
  const log = logger('helia')
21
20
 
@@ -31,34 +30,26 @@ export class HeliaImpl implements Helia {
31
30
  public datastore: Datastore
32
31
  public pins: Pins
33
32
 
34
- #bitswap?: Bitswap
35
-
36
33
  constructor (init: HeliaImplInit) {
37
- const hashers: MultihashHasher[] = [
38
- sha256,
39
- sha512,
40
- identity,
41
- ...(init.hashers ?? [])
42
- ]
43
-
44
- this.#bitswap = createBitswap(init.libp2p, init.blockstore, {
45
- hashLoader: {
46
- getHasher: async (codecOrName: string | number): Promise<MultihashHasher<number>> => {
47
- const hasher = hashers.find(hasher => {
48
- return hasher.code === codecOrName || hasher.name === codecOrName
49
- })
34
+ const hashers = defaultHashers(init.hashers)
50
35
 
51
- if (hasher != null) {
52
- return hasher
53
- }
36
+ const components = {
37
+ blockstore: init.blockstore,
38
+ datastore: init.datastore,
39
+ libp2p: init.libp2p,
40
+ hashers
41
+ }
54
42
 
55
- throw new Error(`Could not load hasher for code/name "${codecOrName}"`)
56
- }
57
- }
58
- })
43
+ const blockBrokers = init.blockBrokers?.map((fn) => {
44
+ return fn(components)
45
+ }) ?? [
46
+ bitswap()(components),
47
+ trustlessGateway()()
48
+ ]
59
49
 
60
50
  const networkedStorage = new NetworkedStorage(init.blockstore, {
61
- bitswap: this.#bitswap
51
+ blockBrokers,
52
+ hashers
62
53
  })
63
54
 
64
55
  this.pins = new PinsImpl(init.datastore, networkedStorage, init.dagWalkers ?? [])
@@ -72,14 +63,13 @@ export class HeliaImpl implements Helia {
72
63
 
73
64
  async start (): Promise<void> {
74
65
  await assertDatastoreVersionIsCurrent(this.datastore)
75
-
76
- await this.#bitswap?.start()
66
+ await start(this.blockstore)
77
67
  await this.libp2p.start()
78
68
  }
79
69
 
80
70
  async stop (): Promise<void> {
81
71
  await this.libp2p.stop()
82
- await this.#bitswap?.stop()
72
+ await stop(this.blockstore)
83
73
  }
84
74
 
85
75
  async gc (options: GCOptions = {}): Promise<void> {
package/src/index.ts CHANGED
@@ -1,22 +1,20 @@
1
1
  /**
2
2
  * @packageDocumentation
3
3
  *
4
- * Create a Helia node.
4
+ * Exports a `createHelia` function that returns an object that implements the {@link Helia} API.
5
+ *
6
+ * Pass it to other modules like {@link https://www.npmjs.com/package/@helia/unixfs | @helia/unixfs} to make files available on the distributed web.
5
7
  *
6
8
  * @example
7
9
  *
8
10
  * ```typescript
9
- * import { MemoryDatastore } from 'datastore-core'
10
- * import { MemoryBlockstore } from 'blockstore-core'
11
11
  * import { createHelia } from 'helia'
12
12
  * import { unixfs } from '@helia/unixfs'
13
13
  * import { CID } from 'multiformats/cid'
14
14
  *
15
- * const node = await createHelia({
16
- * blockstore: new MemoryBlockstore(),
17
- * datastore: new MemoryDatastore()
18
- * })
19
- * const fs = unixfs(node)
15
+ * const helia = await createHelia()
16
+ *
17
+ * const fs = unixfs(helia)
20
18
  * fs.cat(CID.parse('bafyFoo'))
21
19
  * ```
22
20
  */
@@ -29,6 +27,7 @@ import { createLibp2p } from './utils/libp2p.js'
29
27
  import { name, version } from './version.js'
30
28
  import type { DefaultLibp2pServices } from './utils/libp2p-defaults.js'
31
29
  import type { Helia } from '@helia/interface'
30
+ import type { BlockBroker } from '@helia/interface/blocks'
32
31
  import type { Libp2p } from '@libp2p/interface'
33
32
  import type { Blockstore } from 'interface-blockstore'
34
33
  import type { Datastore } from 'interface-datastore'
@@ -49,7 +48,7 @@ const log = logger('helia')
49
48
  */
50
49
  export interface DAGWalker {
51
50
  codec: number
52
- walk: (block: Uint8Array) => AsyncGenerator<CID, void, undefined>
51
+ walk(block: Uint8Array): AsyncGenerator<CID, void, undefined>
53
52
  }
54
53
 
55
54
  /**
@@ -91,6 +90,12 @@ export interface HeliaInit<T extends Libp2p = Libp2p> {
91
90
  */
92
91
  dagWalkers?: DAGWalker[]
93
92
 
93
+ /**
94
+ * A list of strategies used to fetch blocks when they are not present in
95
+ * the local blockstore
96
+ */
97
+ blockBrokers?: Array<(components: any) => BlockBroker>
98
+
94
99
  /**
95
100
  * Pass `false` to not start the Helia node
96
101
  */
package/src/storage.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { start, stop, type Startable } from '@libp2p/interface/startable'
1
2
  import createMortice from 'mortice'
2
3
  import type { Blocks, Pair, DeleteManyBlocksProgressEvents, DeleteBlockProgressEvents, GetBlockProgressEvents, GetManyBlocksProgressEvents, PutManyBlocksProgressEvents, PutBlockProgressEvents, GetAllBlocksProgressEvents, GetOfflineOptions } from '@helia/interface/blocks'
3
4
  import type { Pins } from '@helia/interface/pins'
@@ -13,7 +14,7 @@ export interface BlockStorageInit {
13
14
  }
14
15
 
15
16
  export interface GetOptions extends AbortOptions {
16
- progress?: (evt: Event) => void
17
+ progress?(evt: Event): void
17
18
  }
18
19
 
19
20
  /**
@@ -21,10 +22,11 @@ export interface GetOptions extends AbortOptions {
21
22
  * blockstore (that may be on disk, s3, or something else). If the blocks are
22
23
  * not present Bitswap will be used to fetch them from network peers.
23
24
  */
24
- export class BlockStorage implements Blocks {
25
+ export class BlockStorage implements Blocks, Startable {
25
26
  public lock: Mortice
26
27
  private readonly child: Blockstore
27
28
  private readonly pins: Pins
29
+ private started: boolean
28
30
 
29
31
  /**
30
32
  * Create a new BlockStorage
@@ -35,6 +37,21 @@ export class BlockStorage implements Blocks {
35
37
  this.lock = createMortice({
36
38
  singleProcess: options.holdGcLock
37
39
  })
40
+ this.started = false
41
+ }
42
+
43
+ isStarted (): boolean {
44
+ return this.started
45
+ }
46
+
47
+ async start (): Promise<void> {
48
+ await start(this.child)
49
+ this.started = true
50
+ }
51
+
52
+ async stop (): Promise<void> {
53
+ await stop(this.child)
54
+ this.started = false
38
55
  }
39
56
 
40
57
  unwrap (): Blockstore {
@@ -0,0 +1,12 @@
1
+ import { identity } from 'multiformats/hashes/identity'
2
+ import { sha256, sha512 } from 'multiformats/hashes/sha2'
3
+ import type { MultihashHasher } from 'multiformats/hashes/interface'
4
+
5
+ export function defaultHashers (hashers: MultihashHasher[] = []): MultihashHasher[] {
6
+ return [
7
+ sha256,
8
+ sha512,
9
+ identity,
10
+ ...hashers
11
+ ]
12
+ }
@@ -1,8 +1,8 @@
1
1
  import { gossipsub } from '@chainsafe/libp2p-gossipsub'
2
2
  import { noise } from '@chainsafe/libp2p-noise'
3
3
  import { yamux } from '@chainsafe/libp2p-yamux'
4
+ import { createDelegatedRoutingV1HttpApiClient } from '@helia/delegated-routing-v1-http-api-client'
4
5
  import { bootstrap } from '@libp2p/bootstrap'
5
- import { ipniContentRouting } from '@libp2p/ipni-content-routing'
6
6
  import { type DualKadDHT, kadDHT } from '@libp2p/kad-dht'
7
7
  import { mplex } from '@libp2p/mplex'
8
8
  import { webRTC, webRTCDirect } from '@libp2p/webrtc'
@@ -21,6 +21,7 @@ import type { Libp2pOptions } from 'libp2p'
21
21
 
22
22
  export interface DefaultLibp2pServices extends Record<string, unknown> {
23
23
  dht: DualKadDHT
24
+ delegatedRouting: unknown
24
25
  pubsub: PubSub
25
26
  identify: IdentifyService
26
27
  autoNAT: unknown
@@ -54,14 +55,12 @@ export function libp2pDefaults (): Libp2pOptions<DefaultLibp2pServices> {
54
55
  peerDiscovery: [
55
56
  bootstrap(bootstrapConfig)
56
57
  ],
57
- contentRouters: [
58
- ipniContentRouting('https://cid.contact')
59
- ],
60
58
  services: {
61
59
  identify: identifyService(),
62
60
  autoNAT: autoNATService(),
63
61
  pubsub: gossipsub(),
64
62
  dcutr: dcutrService(),
63
+ delegatedRouting: () => createDelegatedRoutingV1HttpApiClient('https://delegated-ipfs.dev'),
65
64
  dht: kadDHT({
66
65
  clientMode: true,
67
66
  validators: {
@@ -1,8 +1,8 @@
1
1
  import { gossipsub } from '@chainsafe/libp2p-gossipsub'
2
2
  import { noise } from '@chainsafe/libp2p-noise'
3
3
  import { yamux } from '@chainsafe/libp2p-yamux'
4
+ import { createDelegatedRoutingV1HttpApiClient } from '@helia/delegated-routing-v1-http-api-client'
4
5
  import { bootstrap } from '@libp2p/bootstrap'
5
- import { ipniContentRouting } from '@libp2p/ipni-content-routing'
6
6
  import { type DualKadDHT, kadDHT } from '@libp2p/kad-dht'
7
7
  import { mdns } from '@libp2p/mdns'
8
8
  import { mplex } from '@libp2p/mplex'
@@ -23,6 +23,7 @@ import type { Libp2pOptions } from 'libp2p'
23
23
 
24
24
  export interface DefaultLibp2pServices extends Record<string, unknown> {
25
25
  dht: DualKadDHT
26
+ delegatedRouting: unknown
26
27
  pubsub: PubSub
27
28
  relay: CircuitRelayService
28
29
  identify: IdentifyService
@@ -37,6 +38,7 @@ export function libp2pDefaults (): Libp2pOptions<DefaultLibp2pServices> {
37
38
  addresses: {
38
39
  listen: [
39
40
  '/ip4/0.0.0.0/tcp/0',
41
+ '/ip6/::/tcp/0',
40
42
  '/webrtc'
41
43
  ]
42
44
  },
@@ -60,15 +62,13 @@ export function libp2pDefaults (): Libp2pOptions<DefaultLibp2pServices> {
60
62
  mdns(),
61
63
  bootstrap(bootstrapConfig)
62
64
  ],
63
- contentRouters: [
64
- ipniContentRouting('https://cid.contact')
65
- ],
66
65
  services: {
67
66
  identify: identifyService(),
68
67
  autoNAT: autoNATService(),
69
68
  upnp: uPnPNATService(),
70
69
  pubsub: gossipsub(),
71
70
  dcutr: dcutrService(),
71
+ delegatedRouting: () => createDelegatedRoutingV1HttpApiClient('https://delegated-ipfs.dev'),
72
72
  dht: kadDHT({
73
73
  validators: {
74
74
  ipns: ipnsValidator