ipfs-car
Version:
Convert files to content-addressed archives (.car) and back
51 lines (44 loc) • 1.47 kB
JavaScript
import { CID } from 'multiformats/cid'
import { sha256 } from 'multiformats/hashes/sha2'
import { decode as blockDecode } from 'multiformats/block'
import { Codecs } from './codec.js'
/**
* @param {import('@ipld/car/api').CarReader} reader
* @param {object} [opts]
* @param {string} [opts.root]
*/
export async function getRoots (reader, opts = {}) {
let roots = opts.root ? [CID.parse(opts.root)] : await reader.getRoots()
if (!roots.length) {
roots = await findImplicitRoots(reader.blocks())
}
if (roots.length > 1) {
console.error(`Multiple roots found, use --root to specify which one to use:\n${roots.join('\n')}`)
process.exit(1)
}
return roots
}
/** @param {AsyncIterable<import('@ipld/car/api').Block>} blocks */
export async function findImplicitRoots (blocks) {
const notRoots = new Set()
const roots = new Set()
for await (const { cid, bytes } of blocks) {
if (!notRoots.has(cid.toString())) {
roots.add(cid.toString())
}
const decoder = Codecs[cid.code]
/* c8 ignore next 4 */
if (!decoder) {
console.error(`Missing decoder: ${cid.code}`)
process.exit(1)
}
const block = await blockDecode({ bytes, codec: decoder, hasher: sha256 })
for (const [, linkCID] of block.links()) {
if (roots.has(linkCID.toString())) {
roots.delete(linkCID.toString())
}
notRoots.add(cid.toString())
}
}
return Array.from(roots).map(s => CID.parse(s))
}