// com.atproto.sync.getRecord — build the proof CAR for ONE record.
//
// WHY THIS EXISTS AT ALL. The membrane served getRepo (the whole repo) and repo.getRecord (hydrated
// JSON: no commit, no signature, no MST proof, therefore unverifiable) but NOT the proof-carrying
// single-record read in between. So no client could verify one of our records without pulling the
// entire repo — including our own favela inbound lens, which got a 404 pointing at us. A gap in our
// federation surface, found by aiming our own verifier at ourselves.
//
// WHAT A CONSUMER DOES WITH IT. Load the commit, check its signature against the DID document's key,
// walk the covering path to <collection>/<rkey>, and confirm the record block hashes to the CID the
// proof arrives at. That is only possible if we ship the commit + the path + the record — which is
// exactly what this slices out of the full repo CAR.
//
// EXISTENCE *OR* NON-EXISTENCE. Per the lexicon this proves either. An absent record is NOT a 404: it
// returns the same commit + covering path with no record block, which proves the key is genuinely not
// in the tree. A 404 would be indistinguishable from "the repo is not here".
//
// Separated from server-bare.js so it is testable under plain node — that file imports bare-http1 and
// so can only run under bare.
import { readCar, writeCar, loadCommit, getBlock } from 'atproto-repo/lib/repo.js'
import { nodeStoreFromBlocks, findRpathProof } from 'atproto-repo/lib/mst.js'
// carBytes: the full repo CAR (front.getRepo()). Returns { carBytes, found } or throws.
export async function buildRecordProofCar (repoCarBytes, collection, rkey) {
const car = await readCar(repoCarBytes)
const commit = loadCommit(car)
const ns = nodeStoreFromBlocks(car.blocks)
const { value: recordCid, proof } = findRpathProof(ns, commit.value.data, `${collection}/${rkey}`)
// The signed commit is the root and the anchor for every other check.
const blocks = [{ cid: commit.cid, bytes: getBlock(car, commit.cid).bytes }]
// The covering path — the MST nodes a verifier walks from the signed root down to the key. Without
// these the record block is unattached to anything signed.
for (const cidStr of proof) {
const b = car.blocks.get(cidStr)
if (b) blocks.push({ cid: b.cid, bytes: b.bytes })
}
if (recordCid) {
const rb = car.blocks.get(recordCid.toString())
if (rb) blocks.push({ cid: rb.cid, bytes: rb.bytes })
}
return { carBytes: await writeCar(commit.cid, blocks), found: !!recordCid }
}