import type { OAuthUserAgent } from "@atcute/oauth-browser-client"; import { createCob, eraseCob, updateCob, type CobRecord, type CobRef } from "#lib/api/cob.ts"; import { datetimeOf, nsidOf, type Did, type KnotOrigin, type LabelKey } from "#lib/api/syntax.ts"; import type { TicketRecord, TicketState } from "#lib/api/records.ts"; // a pull is a ticket with a target branch export const TICKET_COLLECTION = nsidOf("org.tangled.track.ticket"); export interface TicketProse { title: string; body: string; targetBranch?: string; tangledLabels?: readonly LabelKey[]; } const titleOf = (text: string): TicketRecord["title"] => ({ $type: "org.tangled.markup.markdown#inline", text }); // the knot refuses an empty markdown body, so leave a blank one out const bodyOf = (text: string, current?: TicketRecord["body"]): TicketRecord["body"] => text.trim() ? { ...current, $type: "org.tangled.markup.markdown", text } : undefined; const labelsOf = (keys: readonly LabelKey[]) => keys.length ? keys.map((key) => ({ $type: "org.tangled.label.defs#labelToken" as const, key })) : undefined; export const createTicket = async ( agent: OAuthUserAgent, knot: KnotOrigin, repo: Did, { title, body, targetBranch, tangledLabels }: TicketProse ): Promise> => { const record: TicketRecord = { $type: "org.tangled.track.ticket", title: titleOf(title), body: bodyOf(body), state: "open", targetBranch, ...(tangledLabels ? { tangledLabels: labelsOf(tangledLabels) } : {}), createdAt: datetimeOf(new Date().toISOString()) }; return { ...(await createCob(agent, knot, repo, TICKET_COLLECTION, record)), value: record }; }; // a put replaces everything, so start from the stored record export const editTicket = ( agent: OAuthUserAgent, knot: KnotOrigin, from: CobRef, { title, body, targetBranch, tangledLabels }: TicketProse ): Promise> => updateCob(agent, knot, from, (current) => ({ ...current, title: titleOf(title), body: bodyOf(body, current.body), targetBranch: targetBranch ?? current.targetBranch, ...(tangledLabels ? { tangledLabels: labelsOf(tangledLabels) } : {}) })); export const setTicketState = ( agent: OAuthUserAgent, knot: KnotOrigin, from: CobRef, state: TicketState ): Promise> => updateCob(agent, knot, from, (current) => ({ ...current, state })); export const setTicketLabels = ( agent: OAuthUserAgent, knot: KnotOrigin, from: CobRef, keys: readonly LabelKey[] ): Promise> => updateCob(agent, knot, from, (current) => ({ ...current, tangledLabels: labelsOf(keys) })); export const eraseTicket = (agent: OAuthUserAgent, knot: KnotOrigin, from: CobRef): Promise => eraseCob(agent, knot, from);