diff --git a/packages/block-brokers/src/bitswap.ts b/packages/block-brokers/src/bitswap.ts index d73331c7..072594fc 100644 --- a/packages/block-brokers/src/bitswap.ts +++ b/packages/block-brokers/src/bitswap.ts @@ -10,7 +10,7 @@ import type { ProgressOptions } from 'progress-events' interface BitswapComponents { libp2p: Libp2p blockstore: Blockstore - hashers: MultihashHasher[] + hashers: Record } export interface BitswapInit extends BitswapOptions { @@ -29,9 +29,15 @@ ProgressOptions this.bitswap = createBitswap(libp2p, blockstore, { hashLoader: { getHasher: async (codecOrName: string | number): Promise> => { - const hasher = hashers.find(hasher => { - return hasher.code === codecOrName || hasher.name === codecOrName - }) + let hasher: MultihashHasher | undefined + + if (typeof codecOrName === 'string') { + hasher = Object.values(hashers).find(hasher => { + return hasher.name === codecOrName + }) + } else { + hasher = hashers[codecOrName] + } if (hasher != null) { return hasher diff --git a/packages/car/package.json b/packages/car/package.json index 24737316..6a91ff7f 100644 --- a/packages/car/package.json +++ b/packages/car/package.json @@ -141,9 +141,7 @@ "dependencies": { "@helia/interface": "^3.0.1", "@ipld/car": "^5.1.1", - "@ipld/dag-pb": "^4.0.6", "@libp2p/interfaces": "^3.3.1", - "cborg": "^4.0.3", "it-drain": "^3.0.5", "it-map": "^3.0.3", "multiformats": "^13.0.0", @@ -153,6 +151,7 @@ }, "devDependencies": { "@helia/unixfs": "^2.0.1", + "@ipld/dag-pb": "^4.0.8", "aegir": "^42.1.0", "blockstore-core": "^4.3.10", "interface-blockstore": "^5.2.9", diff --git a/packages/car/src/index.ts b/packages/car/src/index.ts index a699fa32..40dc2189 100644 --- a/packages/car/src/index.ts +++ b/packages/car/src/index.ts @@ -62,7 +62,7 @@ import drain from 'it-drain' import map from 'it-map' import defer from 'p-defer' import PQueue from 'p-queue' -import { cborWalker, dagPbWalker, jsonWalker, rawWalker } from './utils/dag-walkers.js' +import type { DAGWalker } from '@helia/interface' import type { Blocks, GetBlockProgressEvents, PutManyBlocksProgressEvents } from '@helia/interface/blocks' import type { CarReader, CarWriter } from '@ipld/car' import type { AbortOptions } from '@libp2p/interfaces' @@ -71,23 +71,7 @@ import type { ProgressOptions } from 'progress-events' export interface CarComponents { blockstore: Blocks -} - -export interface CarInit { - /** - * In order to export CIDs that correspond to a DAG, it's necessary to know - * how to traverse that DAG. DAGWalkers take a block and yield any CIDs - * encoded within that block. - */ - dagWalkers?: DAGWalker[] -} - -/** - * DAGWalkers take a block and yield CIDs encoded in that block - */ -export interface DAGWalker { - codec: number - walk(block: Uint8Array): AsyncGenerator + dagWalkers: Record } /** @@ -146,27 +130,13 @@ export interface Car { export(root: CID | CID[], writer: Pick, options?: AbortOptions & ProgressOptions): Promise } -const DEFAULT_DAG_WALKERS = [ - rawWalker, - dagPbWalker, - cborWalker, - jsonWalker -] - const DAG_WALK_QUEUE_CONCURRENCY = 1 class DefaultCar implements Car { private readonly components: CarComponents - private dagWalkers: Record - constructor (components: CarComponents, init: CarInit) { + constructor (components: CarComponents, init: any) { this.components = components - - this.dagWalkers = {} - - ;[...DEFAULT_DAG_WALKERS, ...(init.dagWalkers ?? [])].forEach(dagWalker => { - this.dagWalkers[dagWalker.codec] = dagWalker - }) } async import (reader: Pick, options?: AbortOptions & ProgressOptions): Promise { @@ -188,7 +158,7 @@ class DefaultCar implements Car { deferred.resolve() }) queue.on('error', (err) => { - deferred.resolve(err) + deferred.reject(err) }) for (const root of roots) { @@ -212,7 +182,7 @@ class DefaultCar implements Car { * and update the pin count for them */ async #walkDag (cid: CID, queue: PQueue, withBlock: (cid: CID, block: Uint8Array) => Promise, options?: AbortOptions & ProgressOptions): Promise { - const dagWalker = this.dagWalkers[cid.code] + const dagWalker = this.components.dagWalkers[cid.code] if (dagWalker == null) { throw new Error(`No dag walker found for cid codec ${cid.code}`) @@ -234,6 +204,6 @@ class DefaultCar implements Car { /** * Create a {@link Car} instance for use with {@link https://github.com/ipfs/helia Helia} */ -export function car (helia: { blockstore: Blocks }, init: CarInit = {}): Car { +export function car (helia: { blockstore: Blocks, dagWalkers: Record }, init: any = {}): Car { return new DefaultCar(helia, init) } diff --git a/packages/car/src/utils/dag-walkers.ts b/packages/car/src/utils/dag-walkers.ts deleted file mode 100644 index 80cc25b7..00000000 --- a/packages/car/src/utils/dag-walkers.ts +++ /dev/null @@ -1,176 +0,0 @@ -/* eslint max-depth: ["error", 7] */ - -import * as dagPb from '@ipld/dag-pb' -import * as cborg from 'cborg' -import { Type, Token } from 'cborg' -import * as cborgJson from 'cborg/json' -import { base64 } from 'multiformats/bases/base64' -import { CID } from 'multiformats/cid' -import * as raw from 'multiformats/codecs/raw' - -/** - * DAGWalkers take a block and yield CIDs encoded in that block - */ -export interface DAGWalker { - codec: number - walk(block: Uint8Array): AsyncGenerator -} - -/** - * Dag walker for dag-pb CIDs - */ -export const dagPbWalker: DAGWalker = { - codec: dagPb.code, - async * walk (block) { - const node = dagPb.decode(block) - - yield * node.Links.map(l => l.Hash) - } -} - -/** - * Dag walker for raw CIDs - */ -export const rawWalker: DAGWalker = { - codec: raw.code, - async * walk () { - // no embedded CIDs in a raw block - } -} - -// https://github.com/ipfs/go-ipfs/issues/3570#issuecomment-273931692 -const CID_TAG = 42 - -/** - * Dag walker for dag-cbor CIDs. Does not actually use dag-cbor since - * all we are interested in is extracting the the CIDs from the block - * so we can just use cborg for that. - */ -export const cborWalker: DAGWalker = { - codec: 0x71, - async * walk (block) { - const cids: CID[] = [] - const tags: cborg.TagDecoder[] = [] - tags[CID_TAG] = (bytes) => { - if (bytes[0] !== 0) { - throw new Error('Invalid CID for CBOR tag 42; expected leading 0x00') - } - - const cid = CID.decode(bytes.subarray(1)) // ignore leading 0x00 - - cids.push(cid) - - return cid - } - - cborg.decode(block, { - tags - }) - - yield * cids - } -} - -/** - * Borrowed from @ipld/dag-json - */ -class DagJsonTokenizer extends cborgJson.Tokenizer { - private readonly tokenBuffer: cborg.Token[] - - constructor (data: Uint8Array, options?: cborg.DecodeOptions) { - super(data, options) - - this.tokenBuffer = [] - } - - done (): boolean { - return this.tokenBuffer.length === 0 && super.done() - } - - _next (): cborg.Token { - if (this.tokenBuffer.length > 0) { - // @ts-expect-error https://github.com/Microsoft/TypeScript/issues/30406 - return this.tokenBuffer.pop() - } - return super.next() - } - - /** - * Implements rules outlined in https://github.com/ipld/specs/pull/356 - */ - next (): cborg.Token { - const token = this._next() - - if (token.type === Type.map) { - const keyToken = this._next() - if (keyToken.type === Type.string && keyToken.value === '/') { - const valueToken = this._next() - if (valueToken.type === Type.string) { // *must* be a CID - const breakToken = this._next() // swallow the end-of-map token - if (breakToken.type !== Type.break) { - throw new Error('Invalid encoded CID form') - } - this.tokenBuffer.push(valueToken) // CID.parse will pick this up after our tag token - return new Token(Type.tag, 42, 0) - } - if (valueToken.type === Type.map) { - const innerKeyToken = this._next() - if (innerKeyToken.type === Type.string && innerKeyToken.value === 'bytes') { - const innerValueToken = this._next() - if (innerValueToken.type === Type.string) { // *must* be Bytes - for (let i = 0; i < 2; i++) { - const breakToken = this._next() // swallow two end-of-map tokens - if (breakToken.type !== Type.break) { - throw new Error('Invalid encoded Bytes form') - } - } - const bytes = base64.decode(`m${innerValueToken.value}`) - return new Token(Type.bytes, bytes, innerValueToken.value.length) - } - this.tokenBuffer.push(innerValueToken) // bail - } - this.tokenBuffer.push(innerKeyToken) // bail - } - this.tokenBuffer.push(valueToken) // bail - } - this.tokenBuffer.push(keyToken) // bail - } - return token - } -} - -/** - * Dag walker for dag-json CIDs. Does not actually use dag-json since - * all we are interested in is extracting the the CIDs from the block - * so we can just use cborg/json for that. - */ -export const jsonWalker: DAGWalker = { - codec: 0x0129, - async * walk (block) { - const cids: CID[] = [] - const tags: cborg.TagDecoder[] = [] - tags[CID_TAG] = (string) => { - const cid = CID.parse(string) - - cids.push(cid) - - return cid - } - - cborgJson.decode(block, { - tags, - tokenizer: new DagJsonTokenizer(block, { - tags, - allowIndefinite: true, - allowUndefined: true, - allowNaN: true, - allowInfinity: true, - allowBigInt: true, - strict: false, - rejectDuplicateMapKeys: false - }) - }) - - yield * cids - } -} diff --git a/packages/car/test/index.spec.ts b/packages/car/test/index.spec.ts index 9fba0ed4..3f93e200 100644 --- a/packages/car/test/index.spec.ts +++ b/packages/car/test/index.spec.ts @@ -2,31 +2,58 @@ import { type UnixFS, unixfs } from '@helia/unixfs' import { CarReader } from '@ipld/car' +import * as dagPb from '@ipld/dag-pb' import { expect } from 'aegir/chai' import { MemoryBlockstore } from 'blockstore-core' import { fixedSize } from 'ipfs-unixfs-importer/chunker' import toBuffer from 'it-to-buffer' +import * as raw from 'multiformats/codecs/raw' import { car, type Car } from '../src/index.js' import { largeFile, smallFile } from './fixtures/files.js' import { memoryCarWriter } from './fixtures/memory-car.js' +import type { DAGWalker } from '@helia/interface' import type { Blockstore } from 'interface-blockstore' +/** + * Dag walker for dag-pb CIDs + */ +const dagPbWalker: DAGWalker = { + codec: dagPb.code, + * walk (block) { + const node = dagPb.decode(block) + + yield * node.Links.map(l => l.Hash) + } +} + +const rawWalker: DAGWalker = { + codec: raw.code, + * walk () { + // no embedded CIDs in a raw block + } +} + describe('import', () => { let blockstore: Blockstore let c: Car let u: UnixFS + let dagWalkers: Record beforeEach(async () => { blockstore = new MemoryBlockstore() + dagWalkers = { + [dagPb.code]: dagPbWalker, + [raw.code]: rawWalker + } - c = car({ blockstore }) + c = car({ blockstore, dagWalkers }) u = unixfs({ blockstore }) }) it('exports and imports a car file', async () => { const otherBlockstore = new MemoryBlockstore() const otherUnixFS = unixfs({ blockstore: otherBlockstore }) - const otherCar = car({ blockstore: otherBlockstore }) + const otherCar = car({ blockstore: otherBlockstore, dagWalkers }) const cid = await otherUnixFS.addBytes(smallFile) const writer = memoryCarWriter(cid) @@ -46,7 +73,7 @@ describe('import', () => { const otherBlockstore = new MemoryBlockstore() const otherUnixFS = unixfs({ blockstore: otherBlockstore }) - const otherCar = car({ blockstore: otherBlockstore }) + const otherCar = car({ blockstore: otherBlockstore, dagWalkers }) const cid1 = await otherUnixFS.addBytes(fileData1) const cid2 = await otherUnixFS.addBytes(fileData2) const cid3 = await otherUnixFS.addBytes(fileData3) @@ -66,7 +93,7 @@ describe('import', () => { it('exports and imports a multiple block car file', async () => { const otherBlockstore = new MemoryBlockstore() const otherUnixFS = unixfs({ blockstore: otherBlockstore }) - const otherCar = car({ blockstore: otherBlockstore }) + const otherCar = car({ blockstore: otherBlockstore, dagWalkers }) const cid = await otherUnixFS.addBytes(largeFile, { chunker: fixedSize({ chunkSize: 1024 @@ -90,7 +117,7 @@ describe('import', () => { const otherBlockstore = new MemoryBlockstore() const otherUnixFS = unixfs({ blockstore: otherBlockstore }) - const otherCar = car({ blockstore: otherBlockstore }) + const otherCar = car({ blockstore: otherBlockstore, dagWalkers }) const cid1 = await otherUnixFS.addBytes(fileData1, { chunker: fixedSize({ chunkSize: 2 diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index e3ecf978..c2911e7a 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -105,37 +105,48 @@ export interface HeliaInit { components?: Record } +interface Components { + blockstore: Blockstore + datastore: Datastore + hashers: Record + dagWalkers: Record + logger: ComponentLogger + blockBrokers: BlockBroker[] +} + export class Helia implements HeliaInterface { public blockstore: BlockStorage public datastore: Datastore public pins: Pins public logger: ComponentLogger public routing: Routing + public dagWalkers: Record + public hashers: Record private readonly log: Logger constructor (init: HeliaInit) { this.logger = init.logger ?? defaultLogger() this.log = this.logger.forComponent('helia') - const hashers = defaultHashers(init.hashers) + this.hashers = defaultHashers(init.hashers) + this.dagWalkers = defaultDagWalkers(init.dagWalkers) - const components = { + const components: Components = { blockstore: init.blockstore, datastore: init.datastore, - hashers, + hashers: this.hashers, + dagWalkers: this.dagWalkers, logger: this.logger, + blockBrokers: [], ...(init.components ?? {}) } - const blockBrokers = init.blockBrokers.map((fn) => { + components.blockBrokers = init.blockBrokers.map((fn) => { return fn(components) }) - const networkedStorage = new NetworkedStorage(components, { - blockBrokers, - hashers - }) + const networkedStorage = new NetworkedStorage(components) - this.pins = new PinsImpl(init.datastore, networkedStorage, defaultDagWalkers(init.dagWalkers)) + this.pins = new PinsImpl(init.datastore, networkedStorage, this.dagWalkers) this.blockstore = new BlockStorage(networkedStorage, this.pins, { holdGcLock: init.holdGcLock ?? true diff --git a/packages/core/src/pins.ts b/packages/core/src/pins.ts index 2187bfa0..72ff7093 100644 --- a/packages/core/src/pins.ts +++ b/packages/core/src/pins.ts @@ -5,21 +5,12 @@ import { base36 } from 'multiformats/bases/base36' import { CID, type Version } from 'multiformats/cid' import { CustomProgressEvent, type ProgressOptions } from 'progress-events' import { equals as uint8ArrayEquals } from 'uint8arrays/equals' -import { dagCborWalker, dagJsonWalker, dagPbWalker, jsonWalker, rawWalker } from './utils/dag-walkers.js' import type { DAGWalker } from '@helia/interface' import type { GetBlockProgressEvents } from '@helia/interface/blocks' import type { AddOptions, AddPinEvents, IsPinnedOptions, LsOptions, Pin, Pins, RmOptions } from '@helia/interface/pins' import type { AbortOptions } from '@libp2p/interface' import type { Blockstore } from 'interface-blockstore' -const DEFAULT_DAG_WALKERS = [ - rawWalker, - dagPbWalker, - dagCborWalker, - dagJsonWalker, - jsonWalker -] - interface DatastorePin { /** * 0 for a direct pin or an arbitrary (+ve, whole) number or Infinity @@ -68,16 +59,12 @@ function toDSKey (cid: CID): Key { export class PinsImpl implements Pins { private readonly datastore: Datastore private readonly blockstore: Blockstore - private dagWalkers: Record + private readonly dagWalkers: Record - constructor (datastore: Datastore, blockstore: Blockstore, dagWalkers: DAGWalker[]) { + constructor (datastore: Datastore, blockstore: Blockstore, dagWalkers: Record) { this.datastore = datastore this.blockstore = blockstore - this.dagWalkers = {} - - ;[...DEFAULT_DAG_WALKERS, ...dagWalkers].forEach(dagWalker => { - this.dagWalkers[dagWalker.codec] = dagWalker - }) + this.dagWalkers = dagWalkers } async * add (cid: CID, options: AddOptions = {}): AsyncGenerator { diff --git a/packages/core/src/utils/dag-walkers.ts b/packages/core/src/utils/dag-walkers.ts index 966be534..b6f726f5 100644 --- a/packages/core/src/utils/dag-walkers.ts +++ b/packages/core/src/utils/dag-walkers.ts @@ -180,12 +180,19 @@ export const jsonWalker: DAGWalker = { * walk () {} } -export function defaultDagWalkers (walkers: DAGWalker[] = []): DAGWalker[] { - return [ +export function defaultDagWalkers (walkers: DAGWalker[] = []): Record { + const output: Record = {} + + ;[ dagPbWalker, rawWalker, dagCborWalker, dagJsonWalker, + jsonWalker, ...walkers - ] + ].forEach(dagWalker => { + output[dagWalker.codec] = dagWalker + }) + + return output } diff --git a/packages/core/src/utils/default-hashers.ts b/packages/core/src/utils/default-hashers.ts index 9352e870..1e579099 100644 --- a/packages/core/src/utils/default-hashers.ts +++ b/packages/core/src/utils/default-hashers.ts @@ -2,11 +2,17 @@ import { identity } from 'multiformats/hashes/identity' import { sha256, sha512 } from 'multiformats/hashes/sha2' import type { MultihashHasher } from 'multiformats/hashes/interface' -export function defaultHashers (hashers: MultihashHasher[] = []): MultihashHasher[] { - return [ +export function defaultHashers (hashers: MultihashHasher[] = []): Record { + const output: Record = {} + + ;[ sha256, sha512, identity, ...hashers - ] + ].forEach(hasher => { + output[hasher.code] = hasher + }) + + return output } diff --git a/packages/core/src/utils/networked-storage.ts b/packages/core/src/utils/networked-storage.ts index cb539532..bf98500f 100644 --- a/packages/core/src/utils/networked-storage.ts +++ b/packages/core/src/utils/networked-storage.ts @@ -11,11 +11,6 @@ import type { AwaitIterable } from 'interface-store' import type { CID } from 'multiformats/cid' import type { MultihashHasher } from 'multiformats/hashes/interface' -export interface NetworkedStorageStorageInit { - blockBrokers?: BlockBroker[] - hashers?: MultihashHasher[] -} - export interface GetOptions extends AbortOptions { progress?(evt: Event): void } @@ -31,6 +26,8 @@ function isBlockAnnouncer (b: any): b is BlockAnnouncer { export interface NetworkedStorageComponents { blockstore: Blockstore logger: ComponentLogger + blockBrokers?: BlockBroker[] + hashers?: Record } /** @@ -41,19 +38,19 @@ export class NetworkedStorage implements Blocks, Startable { private readonly child: Blockstore private readonly blockRetrievers: BlockRetriever[] private readonly blockAnnouncers: BlockAnnouncer[] - private readonly hashers: MultihashHasher[] + private readonly hashers: Record private started: boolean private readonly log: Logger /** * Create a new BlockStorage */ - constructor (components: NetworkedStorageComponents, init: NetworkedStorageStorageInit) { + constructor (components: NetworkedStorageComponents) { this.log = components.logger.forComponent('helia:networked-storage') this.child = components.blockstore - this.blockRetrievers = (init.blockBrokers ?? []).filter(isBlockRetriever) - this.blockAnnouncers = (init.blockBrokers ?? []).filter(isBlockAnnouncer) - this.hashers = init.hashers ?? [] + this.blockRetrievers = (components.blockBrokers ?? []).filter(isBlockRetriever) + this.blockAnnouncers = (components.blockBrokers ?? []).filter(isBlockAnnouncer) + this.hashers = components.hashers ?? {} this.started = false } @@ -127,7 +124,7 @@ export class NetworkedStorage implements Blocks, Startable { if (options.offline !== true && !(await this.child.has(cid))) { // we do not have the block locally, get it from a block provider options.onProgress?.(new CustomProgressEvent('blocks:get:providers:get', cid)) - const block = await raceBlockRetrievers(cid, this.blockRetrievers, this.hashers, { + const block = await raceBlockRetrievers(cid, this.blockRetrievers, this.hashers[cid.multihash.code], { ...options, log: this.log }) @@ -158,7 +155,7 @@ export class NetworkedStorage implements Blocks, Startable { if (options.offline !== true && !(await this.child.has(cid))) { // we do not have the block locally, get it from a block provider options.onProgress?.(new CustomProgressEvent('blocks:get-many:providers:get', cid)) - const block = await raceBlockRetrievers(cid, this.blockRetrievers, this.hashers, { + const block = await raceBlockRetrievers(cid, this.blockRetrievers, this.hashers[cid.multihash.code], { ...options, log: this.log }) @@ -205,9 +202,7 @@ export class NetworkedStorage implements Blocks, Startable { } } -export const getCidBlockVerifierFunction = (cid: CID, hashers: MultihashHasher[]): Required['validateFn'] => { - const hasher = hashers.find(hasher => hasher.code === cid.multihash.code) - +export const getCidBlockVerifierFunction = (cid: CID, hasher: MultihashHasher): Required['validateFn'] => { if (hasher == null) { throw new CodeError(`No hasher configured for multihash code 0x${cid.multihash.code.toString(16)}, please configure one. You can look up which hash this is at https://github.com/multiformats/multicodec/blob/master/table.csv`, 'ERR_UNKNOWN_HASH_ALG') } @@ -227,8 +222,8 @@ export const getCidBlockVerifierFunction = (cid: CID, hashers: MultihashHasher[] * Race block providers cancelling any pending requests once the block has been * found. */ -async function raceBlockRetrievers (cid: CID, providers: BlockRetriever[], hashers: MultihashHasher[], options: AbortOptions & LoggerOptions): Promise { - const validateFn = getCidBlockVerifierFunction(cid, hashers) +async function raceBlockRetrievers (cid: CID, providers: BlockRetriever[], hasher: MultihashHasher, options: AbortOptions & LoggerOptions): Promise { + const validateFn = getCidBlockVerifierFunction(cid, hasher) const controller = new AbortController() const signal = anySignal([controller.signal, options.signal]) diff --git a/packages/core/test/block-broker.spec.ts b/packages/core/test/block-broker.spec.ts index 55887d32..1cef6c47 100644 --- a/packages/core/test/block-broker.spec.ts +++ b/packages/core/test/block-broker.spec.ts @@ -35,8 +35,7 @@ describe('block-broker', () => { gatewayBlockBroker = stubInterface() storage = new NetworkedStorage({ blockstore, - logger: defaultLogger() - }, { + logger: defaultLogger(), blockBrokers: [ bitswapBlockBroker, gatewayBlockBroker @@ -125,8 +124,7 @@ describe('block-broker', () => { const block = blocks[1].block storage = new NetworkedStorage({ blockstore, - logger: defaultLogger() - }, { + logger: defaultLogger(), blockBrokers: [ gatewayBlockBroker ], diff --git a/packages/core/test/utils/networked-storage.spec.ts b/packages/core/test/utils/networked-storage.spec.ts index b4072738..46a7d4ad 100644 --- a/packages/core/test/utils/networked-storage.spec.ts +++ b/packages/core/test/utils/networked-storage.spec.ts @@ -33,8 +33,7 @@ describe('networked-storage', () => { bitswap = stubInterface() storage = new NetworkedStorage({ blockstore, - logger: defaultLogger() - }, { + logger: defaultLogger(), blockBrokers: [ bitswap ], diff --git a/packages/interface/src/index.ts b/packages/interface/src/index.ts index 3e62158a..a12024cc 100644 --- a/packages/interface/src/index.ts +++ b/packages/interface/src/index.ts @@ -19,6 +19,7 @@ import type { Pins } from './pins.js' import type { Routing } from './routing.js' import type { AbortOptions, ComponentLogger } from '@libp2p/interface' import type { Datastore } from 'interface-datastore' +import type { MultihashHasher } from 'multiformats' import type { CID } from 'multiformats/cid' import type { ProgressEvent, ProgressOptions } from 'progress-events' @@ -54,6 +55,18 @@ export interface Helia { */ routing: Routing + /** + * DAGWalkers are codec-specific implementations that know how to yield all + * CIDs contained within a block that corresponds to that codec. + */ + dagWalkers: Record + + /** + * Hashers can be used to hash a piece of data with the specified hashing + * algorithm. + */ + hashers: Record + /** * Starts the Helia node */