Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133import type { OAuthUserAgent } from "@atcute/oauth-browser-client";import { awaitDeletedRecord, awaitIndexedOrSaved } from "$lib/api/awaitRecord";import { createBobbinClient, type BobbinContext, type XrpcRequestInit } from "$lib/api/client";import { createCob, eraseCob, readCob } from "$lib/api/cob";import type * as OrgTangledLabelDefinition from "$lib/api/lexicons/types/org/tangled/label/definition";import type * as OrgTangledLabelDefs from "$lib/api/lexicons/types/org/tangled/label/defs";import { collect } from "$lib/api/pagination";import { atUriOf, datetimeOf, didOf, labelKeyOf, nsidOf, recordKeyOf, type AtUri, type Did, type KnotOrigin, type LabelKey} from "$lib/api/syntax";
export type LabelDefinition = OrgTangledLabelDefinition.Main;export type LabelToken = OrgTangledLabelDefs.LabelToken;
const LABEL_DEFINITION_NSID = "org.tangled.label.definition";const LABEL_DEFINITION_COLLECTION = nsidOf(LABEL_DEFINITION_NSID);
export const BASIC_LABEL_VALUE = "null";
export const DEFAULT_LABEL_OWNER = "did:plc:wshs7t2adsemcrrd4snkeqli";export const DEFAULT_LABELS = [ `at://${DEFAULT_LABEL_OWNER}/sh.tangled.label.definition/wontfix`, `at://${DEFAULT_LABEL_OWNER}/sh.tangled.label.definition/good-first-issue`, `at://${DEFAULT_LABEL_OWNER}/sh.tangled.label.definition/duplicate`, `at://${DEFAULT_LABEL_OWNER}/sh.tangled.label.definition/documentation`, `at://${DEFAULT_LABEL_OWNER}/sh.tangled.label.definition/assignee`].map(atUriOf);
export interface LabelView { uri: string; value: LabelDefinition;}
export const listLabelDefinitions = async ( ctx: BobbinContext, repoDid: string, init?: XrpcRequestInit): Promise<LabelView[]> => { const items = await collect( ctx, "sh.tangled.label.listDefinitions", { subject: didOf(repoDid), limit: 100 }, { ...init, maxPages: 5 } ); return items.map((item) => ({ uri: item.uri, value: item.value as LabelDefinition }));};
export interface CustomLabelInput { name: string; color: string;}
// the knot wants a slug as a label def's rkey and refuses a tidconst labelSlugOf = (name: string): LabelKey => labelKeyOf( name .trim() .toLowerCase() .replace(/[^a-z0-9._~-]+/g, "-") .replace(/^-+|-+$/g, "") .slice(0, 64) );
// only the owner can make these, and an erased key can't be used againexport const createRepoLabel = async ( agent: OAuthUserAgent, knot: KnotOrigin, repoDid: Did, bobbinUrl: string, { name, color }: CustomLabelInput): Promise<LabelView> => { const value: LabelDefinition = { $type: "org.tangled.label.definition", name, color, createdAt: datetimeOf(new Date().toISOString()) }; const written = await createCob( agent, knot, repoDid, LABEL_DEFINITION_COLLECTION, value, recordKeyOf(labelSlugOf(name)) ); await awaitIndexedOrSaved(createBobbinClient({ serviceUrl: bobbinUrl }), written); return { uri: written.uri, value };};
export const deleteRepoLabel = async ( agent: OAuthUserAgent, knot: KnotOrigin, bobbinUrl: string, uri: string): Promise<void> => { const current = await readCob<LabelDefinition>(knot, atUriOf(uri)); await eraseCob(agent, knot, current); await awaitDeletedRecord(createBobbinClient({ serviceUrl: bobbinUrl }), current.uri);};
export type AppliedLabels = Record<string, string[]>;
export interface SubjectLabels { definitions: LabelView[]; applied: AppliedLabels;}
export const NO_SUBJECT_LABELS: SubjectLabels = { definitions: [], applied: {} };
export const labelDefinitionUri = (repoDid: string, key: string): AtUri => atUriOf(`at://${repoDid}/${LABEL_DEFINITION_NSID}/${key}`);
export const loadSubjectLabels = async ( ctx: BobbinContext, repoDid: string, tokens: readonly LabelToken[], init?: XrpcRequestInit): Promise<SubjectLabels> => ({ definitions: await listLabelDefinitions(ctx, repoDid, init), applied: Object.fromEntries( tokens.map((token) => [labelDefinitionUri(repoDid, token.key), [BASIC_LABEL_VALUE]]) )});