diff --git a/README.md b/README.md index 7444a746..0dd672b7 100644 --- a/README.md +++ b/README.md @@ -60,15 +60,29 @@ import 'ipld-explorer-components/dist/components/loader/Loader.css' **NOTE:** PRs adding an old IPLDFormat codec would need the old `blockcodec-to-ipld-format` tool which has many out of date deps. We will only accept PRs for adding BlockCodec interface codecs. -To add another codec you will need to: +To add another codec you will need to update all locations containing the comment `// #WhenAddingNewCodec`: -1. Add a dependency on the codec to this package -1. Add the codec in the switch statement in src/lib/codec-importer.ts -1. Add a unit test to src/lib/resolve-ipld-path.test.js and ensure that calling `resolveIpldPath` returns the expected results - * If the default `resolveFn` in src/lib/get-codec-for-cid.ts doesn't resolve your paths correctly, you will need to add a resolver method for your codec to the `codecResolverMap` in src/lib/get-codec-for-cid.ts +1. Add a dependency on the codec to this package (if it's not already in multiformats or other package) +1. Add the codec in the switch statement in [./src/lib/codec-importer.ts](./src/lib/codec-importer.ts) +1. Update [./src/lib/get-codec-name-from-code.ts](./src/lib/get-codec-name-from-code.ts) to return the codec name for your codec +1. Add a unit test to [./src/lib/resolve-ipld-path.test.js](./src/lib/resolve-ipld-path.test.js) and ensure that calling `resolveIpldPath` returns the expected results + * If the default `resolveFn` in [./src/lib/get-codec-for-cid.ts](./src/lib/get-codec-for-cid.ts) doesn't resolve your paths correctly, you will need to add a resolver method for your codec to the `codecResolverMap` in [./src/lib/get-codec-for-cid.ts](./src/lib/get-codec-for-cid.ts) see https://github.com/ipfs/ipld-explorer-components/pull/360#discussion_r1206251817 for history. +### Adding another hasher + +To add another hasher you will need to update all locations containing the comment `// #WhenAddingNewHasher`: + +1. Add a dependency on the hasher to this package (if it's not already in multiformats or other package) +1. Add the hasher in the switch statement in [./src/lib/get-codec-for-cid.ts](./src/lib/get-codec-for-cid.ts) +1. Update [./src/lib/hash-importer.ts](./src/lib/hash-importer.ts) + - Update `SupportedHashers` to include your hasher type + - Update `getHasherForCode` to return your hasher +1. Update the hasher codes used by the `hashers` property passed to Helia init in [./src/lib/init-helia.ts](./src/lib/init-helia.ts) + +see https://github.com/ipfs/ipld-explorer-components/pull/395 for an example. + ### Redux-bundler requirements These components use [redux-bundler](https://reduxbundler.com/) and your app will need to use a redux-bundler provider in order to propogate the properties and selectors. You can find a basic example of this in ./dev/devPage.jsx. diff --git a/package.json b/package.json index bd086798..21c3fc66 100644 --- a/package.json +++ b/package.json @@ -248,6 +248,7 @@ }, "peerDependencies": { "@loadable/component": "^5.14.1", + "blake3-multihash": "^0.0.4", "i18next": "^21.6.16", "i18next-browser-languagedetector": "^6.1.0", "i18next-http-backend": "^1.2.1", diff --git a/src/components/StartExploringPage.jsx b/src/components/StartExploringPage.jsx index 49497443..a05609b9 100644 --- a/src/components/StartExploringPage.jsx +++ b/src/components/StartExploringPage.jsx @@ -59,6 +59,9 @@ const StartExploringPage = ({ t, embed, runTour = false, joyrideCallback }) => ( */} +
  • + +
  • @@ -68,6 +71,9 @@ const StartExploringPage = ({ t, embed, runTour = false, joyrideCallback }) => (
  • +
  • + +
  • diff --git a/src/lib/codec-importer.ts b/src/lib/codec-importer.ts index 00169b92..cb6516d9 100644 --- a/src/lib/codec-importer.ts +++ b/src/lib/codec-importer.ts @@ -15,6 +15,7 @@ export default async function codecImporter> } +// #WhenAddingNewCodec (maybe) const codecResolverMap: Record = { 'dag-pb': async (node, path) => { if (!isPBNode(node)) { diff --git a/src/lib/get-codec-name-from-code.ts b/src/lib/get-codec-name-from-code.ts index b4353d20..3e807658 100644 --- a/src/lib/get-codec-name-from-code.ts +++ b/src/lib/get-codec-name-from-code.ts @@ -2,6 +2,7 @@ * Converts supported codec codes from https://github.com/multiformats/multicodec/blob/master/table.csv to their names. */ export default function getCodecNameFromCode (code: number): string { + // #WhenAddingNewCodec switch (code) { case 113: return 'dag-cbor' diff --git a/src/lib/hash-importer.ts b/src/lib/hash-importer.ts index 7a179514..e152ef8f 100644 --- a/src/lib/hash-importer.ts +++ b/src/lib/hash-importer.ts @@ -3,12 +3,14 @@ import * as sha3 from '@multiformats/sha3' import { type Hasher, from } from 'multiformats/hashes/hasher' import * as sha2 from 'multiformats/hashes/sha2' +// #WhenAddingNewHasher export type SupportedHashers = typeof sha2.sha256 | typeof sha2.sha512 | Hasher<'keccak-256', 27> | Hasher<'sha1', 17> | Hasher<'blake2b-512', 45632> | - Hasher<'sha3-512', 20> + Hasher<'sha3-512', 20> | + Hasher<'blake3', 30> export async function getHashersForCodes (code: number, ...codes: number[]): Promise { return Promise.all(codes.map(getHasherForCode)) @@ -26,6 +28,7 @@ function getBoundHasher (hasher: T): T { } export async function getHasherForCode (code: number): Promise { + // #WhenAddingNewHasher switch (code) { case sha2.sha256.code: return getBoundHasher(sha2.sha256) @@ -36,7 +39,7 @@ export async function getHasherForCode (code: number): Promise return getBoundHasher(from({ name: 'sha1', code, - encode: async (data: Uint8Array) => { + encode: async (data: Uint8Array): Promise => { const crypto = globalThis.crypto ?? (await import('crypto')).webcrypto const hashBuffer = await crypto.subtle.digest('SHA-1', data) return new Uint8Array(hashBuffer) @@ -46,7 +49,15 @@ export async function getHasherForCode (code: number): Promise return getBoundHasher(sha3.sha3512) case sha3.keccak256.code: // keccak-256 return getBoundHasher(sha3.keccak256) - + case 30: + return getBoundHasher(from({ + name: 'blake3', + code, + encode: async (data: Uint8Array): Promise => { + const { digest } = await import('blake3-multihash') + return (await digest(data)).digest + } + })) default: throw new Error(`unknown multihasher code '${code}'`) } diff --git a/src/lib/init-helia.ts b/src/lib/init-helia.ts index 95ced917..0281f358 100644 --- a/src/lib/init-helia.ts +++ b/src/lib/init-helia.ts @@ -59,7 +59,8 @@ export default async function initHelia (kuboGatewayOptions: KuboGatewayOptions) trustlessGateway(), trustlessGateway({ gateways: [`${kuboGatewayOptions.protocol ?? 'http'}://${kuboGatewayOptions.host}:${kuboGatewayOptions.port}`] }) ], - hashers: await getHashersForCodes(17, 18, 19, 20, 27), + // #WhenAddingNewHasher + hashers: await getHashersForCodes(17, 18, 19, 20, 27, 30), datastore, blockstore, // @ts-expect-error - libp2p types are borked right now @@ -71,7 +72,9 @@ export default async function initHelia (kuboGatewayOptions: KuboGatewayOptions) await Promise.allSettled([ addDagNodeToHelia(helia, 'dag-json', { hello: 'world' }), // baguqeerasords4njcts6vs7qvdjfcvgnume4hqohf65zsfguprqphs3icwea addDagNodeToHelia(helia, 'dag-cbor', { hello: 'world' }, 27), // bafyrwigbexamue2ba3hmtai7hwlcmd6ekiqsduyf5avv7oz6ln3radvjde - addDagNodeToHelia(helia, 'json', { hello: 'world' }, 20) // bagaaifcavabu6fzheerrmtxbbwv7jjhc3kaldmm7lbnvfopyrthcvod4m6ygpj3unrcggkzhvcwv5wnhc5ufkgzlsji7agnmofovc2g4a3ui7ja + addDagNodeToHelia(helia, 'json', { hello: 'world' }, 20), // bagaaifcavabu6fzheerrmtxbbwv7jjhc3kaldmm7lbnvfopyrthcvod4m6ygpj3unrcggkzhvcwv5wnhc5ufkgzlsji7agnmofovc2g4a3ui7ja + addDagNodeToHelia(helia, 'json', { hello: 'world' }, 30), // bagaaihraf4oq2kddg6o5ewlu6aol6xab75xkwbgzx2dlot7cdun7iirve23a + addDagNodeToHelia(helia, 'raw', (new TextEncoder()).encode('hello'), 30) // bafkr4ihkr4ld3m4gqkjf4reryxsy2s5tkbxprqkow6fin2iiyvreuzzab4 ]) return helia diff --git a/src/lib/resolve-ipld-path.test.js b/src/lib/resolve-ipld-path.test.js index d2985038..097d850e 100644 --- a/src/lib/resolve-ipld-path.test.js +++ b/src/lib/resolve-ipld-path.test.js @@ -8,6 +8,7 @@ import { addDagNodeToHelia } from './helpers' import resolveIpldPath, { findLinkPath } from './resolve-ipld-path' import { createHeliaMock } from '../../test/unit/heliaMock' +// #WhenAddingNewCodec describe('resolveIpldPath', () => { /** * @type {import('@helia/interface').Helia}