publishSite
Publish a standard.site site as the signed-in account (its repository must be the site's): its publication and a
document for each post written where they differ from what's there, and the documents of its publication for posts
it no longer has removed. With dryRun, only what it would do. tell hears each record as it goes.
import type { Session } from "#codebase/tcmts/atproto"; import { canonicalJson, recordsIn } from "#codebase/tcmts/cli/publish"; import type { StandardRecord, StandardSite } from "#codebase/tcmts/content"; export async function publishSite( s: Session, site: StandardSite, o: { dryRun?: boolean; tell?: (what: "new" | "updated" | "removed", uri: string) => void } = {}, ): Promise<{ added: number; updated: number; removed: number; same: number }> { if (s.did !== site.did) throw new Error(`the site's records are ${site.did}'s, not ${s.did}'s`); const counts = { added: 0, updated: 0, removed: 0, same: 0 }; const send = async (method: string, body: Record<string, unknown>, uri: string) => { if (o.dryRun) return; const res = await s.fetch(`/xrpc/com.atproto.repo.${method}`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ repo: s.did, ...body }), }); if (!res.ok) { const e = (await res.json().catch(() => ({}))) as { error?: string; message?: string }; throw new Error(`writing ${uri}: ${res.status} ${e.message ?? e.error ?? ""}`.trim()); } }; const write = async (r: StandardRecord, there: Map<string, { cid: string; value: unknown }>) => { const old = there.get(r.rkey); if (old && canonicalJson(old.value) === canonicalJson(r.record)) { counts.same++; return; } await send( "putRecord", { collection: r.collection, rkey: r.rkey, record: r.record, ...(old ? { swapRecord: old.cid } : {}), }, r.uri, ); if (old) counts.updated++; else counts.added++; o.tell?.(old ? "updated" : "new", r.uri); }; await write(site.publication, await recordsIn(s, site.publication.collection)); const documents = await recordsIn(s, "site.standard.document"); for (const d of site.documents) await write(d, documents); // (a post gone: its document, of this publication) const kept = new Set(site.documents.map((d) => d.rkey)); for (const [rkey, { value }] of documents) { if ((value as { site?: unknown }).site !== site.publication.uri || kept.has(rkey)) continue; const uri = `at://${s.did}/site.standard.document/${rkey}`; await send("deleteRecord", { collection: "site.standard.document", rkey }, uri); counts.removed++; o.tell?.("removed", uri); } return counts; }
uses
- tcmts.atproto.Session
- tcmts.cli.publish.canonicalJson
- tcmts.cli.publish.recordsIn
- tcmts.content.StandardRecord
- tcmts.content.StandardSite