This repository has no description
1

Configure Feed

Select the types of activity you want to include in your feed.

at main 4.0 kB View raw
1// Builders for the Tangled AT Protocol records we create. 2// 3// Shapes verified against tangled.org/core lexicons + generated Go types 4// (see docs/lexicon-spec.md). Notable realities: 5// • pull patch is a GZIPPED BLOB in rounds[].patchBlob — there is no `patch` string. 6// • comments are `sh.tangled.feed.comment` with a `markup.markdown` body object; 7// images ride in body.blobs[] and are referenced from body.text. 8// • repos are keyed by DID (v1.14): target.repo / issue.repo = target repo DID, 9// while createRecord.repo = the AUTHORING account DID. 10 11export const NSID = { 12 pull: "sh.tangled.repo.pull", 13 issue: "sh.tangled.repo.issue", 14 comment: "sh.tangled.feed.comment", 15 markdown: "sh.tangled.markup.markdown", 16} as const; 17 18/** atproto blob ref object as returned by uploadBlob; embedded verbatim in records. */ 19export interface BlobRef { 20 $type: "blob"; 21 ref: { $link: string }; 22 mimeType: string; 23 size: number; 24} 25 26/** com.atproto.repo.strongRef — uri + cid of a record. */ 27export interface StrongRef { 28 uri: string; 29 cid: string; 30} 31 32// --- pull ------------------------------------------------------------------- 33 34export interface BuildPullArgs { 35 targetRepoDid: string; // target repository DID 36 targetBranch: string; 37 title: string; 38 body: string; 39 patchBlob: BlobRef; // gzipped git format-patch, already uploaded 40 createdAt: string; 41 sourceBranch?: string; // optional; omit for patch-only PRs 42 sourceRepoDid?: string; 43} 44 45export function buildPullRecord(a: BuildPullArgs) { 46 const record: Record<string, unknown> = { 47 $type: NSID.pull, 48 title: a.title, 49 body: a.body, 50 target: { repo: a.targetRepoDid, branch: a.targetBranch }, 51 rounds: [{ patchBlob: a.patchBlob, createdAt: a.createdAt }], 52 createdAt: a.createdAt, 53 }; 54 if (a.sourceBranch) { 55 record.source = a.sourceRepoDid 56 ? { branch: a.sourceBranch, repo: a.sourceRepoDid } 57 : { branch: a.sourceBranch }; 58 } 59 return record; 60} 61 62// --- issue ------------------------------------------------------------------ 63 64export interface BuildIssueArgs { 65 targetRepoDid: string; 66 title: string; 67 body: string; 68 createdAt: string; 69} 70 71export function buildIssueRecord(a: BuildIssueArgs) { 72 return { 73 $type: NSID.issue, 74 repo: a.targetRepoDid, 75 title: a.title, 76 body: a.body, 77 createdAt: a.createdAt, 78 }; 79} 80 81// --- comment (feed.comment with markdown body) ------------------------------ 82 83export interface MarkdownBody { 84 $type: typeof NSID.markdown; 85 text: string; 86 original: string; 87 blobs?: BlobRef[]; 88} 89 90export function buildMarkdown(text: string, blobs?: BlobRef[]): MarkdownBody { 91 const body: MarkdownBody = { $type: NSID.markdown, text, original: text }; 92 if (blobs && blobs.length) body.blobs = blobs; 93 return body; 94} 95 96export interface BuildCommentArgs { 97 subject: StrongRef; // the issue/pull record being commented on 98 body: MarkdownBody; 99 createdAt: string; 100 replyTo?: StrongRef; 101 /** Required when subject is a pull — which round the comment is on (0-based). */ 102 pullRoundIdx?: number; 103} 104 105export function buildCommentRecord(a: BuildCommentArgs) { 106 const record: Record<string, unknown> = { 107 $type: NSID.comment, 108 subject: a.subject, 109 body: a.body, 110 createdAt: a.createdAt, 111 }; 112 if (a.replyTo) record.replyTo = a.replyTo; 113 if (a.pullRoundIdx !== undefined) record.pullRoundIdx = a.pullRoundIdx; 114 return record; 115} 116 117// --- helpers ---------------------------------------------------------------- 118 119/** Standard markdown image embedding an uploaded blob by its CDN url. */ 120export function imageMarkdown(blobUrl: string, alt: string): string { 121 return `![${alt}](${blobUrl})`; 122} 123 124/** com.atproto.sync.getBlob CDN url for a blob (used to embed in markdown text). */ 125export function blobCdnUrl(service: string, did: string, cid: string): string { 126 return `${service.replace(/\/$/, "")}/xrpc/com.atproto.sync.getBlob?did=${encodeURIComponent( 127 did, 128 )}&cid=${encodeURIComponent(cid)}`; 129}