announceRelease
Write a release's record to the signed-in account's repository. A version is one record: announced again, it's left as it is when it says the same, has its sources replaced when only they differ, and is refused when it names something else.
import { pdsFetch } from "#codebase/tcmts/atproto"; import type { OAuthSession } from "#codebase/tcmts/atproto"; import { UsageError } from "#codebase/tcmts/cli/ui"; import { recordKey, RELEASE_COLLECTION } from "#codebase/tcmts/records"; import type { ReleaseRecord } from "#codebase/tcmts/records"; export async function announceRelease( s: OAuthSession, record: ReleaseRecord, ): Promise<{ uri: string; was: "new" | "same" | "updated" }> { const rkey = recordKey(record); const uri = `at://${s.did}/${RELEASE_COLLECTION}/${rkey}`; const q = new URLSearchParams({ repo: s.did, collection: RELEASE_COLLECTION, rkey }); const got = await fetch(`${s.pds}/xrpc/com.atproto.repo.getRecord?${q}`, { headers: { accept: "application/json" }, }); const old = got.ok ? ((await got.json()) as { cid: string; value: ReleaseRecord }) : undefined; if (!old && got.status !== 400 && got.status !== 404) throw new Error(`reading ${uri}: ${got.status} ${await got.text().catch(() => "")}`); const same = (a: ReleaseRecord, b: ReleaseRecord, keys: (keyof ReleaseRecord)[]) => keys.every((k) => JSON.stringify(a[k]) === JSON.stringify(b[k])); if (old) { if (!same(old.value, record, ["package", "version", "namespace", "entry", "hashFormat"])) throw new UsageError( `${uri} already announces ${record.package}@${record.version} as #${old.value.namespace}, not #${record.namespace}: a version names one release`, ); if (same(old.value, record, ["notes", "sources", "createdAt"])) return { uri, was: "same" }; } const write = (method: string, body: Record<string, unknown>) => pdsFetch(s, `/xrpc/com.atproto.repo.${method}`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ repo: s.did, collection: RELEASE_COLLECTION, rkey, record, ...body }), }); const res = old ? await write("putRecord", { swapRecord: old.cid }) : await write("createRecord", {}); 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()); } return { uri, was: old ? "updated" : "new" }; }
uses
- tcmts.atproto.OAuthSession
- tcmts.atproto.pdsFetch
- tcmts.cli.ui.UsageError
- tcmts.records.RELEASE_COLLECTION
- tcmts.records.ReleaseRecord
- tcmts.records.recordKey