signedRecord
A record at did/collection/rkey, as its author's repository signs it: fetched from their PDS with
com.atproto.sync.getRecord, its blocks checked against their CIDs and its commit against the DID's key. A DID,
document or PDS tcm won't ask (guardedFetch, pdsOf), or a proof too big to be one, is NotTheirs; a record
the repository doesn't hold is NoSuchRecord.
import { cappedBytes, guardedFetch, NoSuchRecord, NotTheirs, Refused, signingKey } from "#codebase/tcmts/atproto"; import { verifyRecord } from "@atcute/repo"; export async function signedRecord( did: string, collection: string, rkey: string, ): Promise<{ cid: string; record: unknown }> { // (a DID, a document or a PDS tcm won't ask, as it never will: not theirs, rather than tried again) const theirs = <T>(p: Promise<T>) => p.catch((e: unknown) => { throw e instanceof Refused ? new NotTheirs(e.message) : e; }); const { pds, key } = await theirs(signingKey(did)); const q = new URLSearchParams({ did, collection, rkey }); const res = await theirs( guardedFetch(`${pds}/xrpc/com.atproto.sync.getRecord?${q}`, `${did}'s PDS`), ); if (res.status === 400 || res.status === 404) throw new NoSuchRecord(`${did}'s repository has no ${collection}/${rkey}`); if (!res.ok) throw new Error(`${pds}: getRecord ${res.status}`); // (one record's proof: a commit, the tree's path to it and the record, a few KB) const carBytes = await theirs(cappedBytes(res, 2 * 1024 * 1024, `${did}'s PDS`)); try { return await verifyRecord({ did: did as `did:plc:${string}`, collection, rkey, publicKey: key, carBytes, }); } catch (e) { throw new NotTheirs( `the record doesn't check against ${did}'s signed repository: ${(e as Error).message}`, ); } }
uses
- tcmts.atproto.NoSuchRecord
- tcmts.atproto.NotTheirs
- tcmts.atproto.Refused
- tcmts.atproto.cappedBytes
- tcmts.atproto.guardedFetch
- tcmts.atproto.signingKey