https://domlink.deployments.hotsocket.fyi/
at main 3.6 kB view raw
1import * as x from "@/extras.ts"; 2import { AtURI, DID, GetRecord, ListRecords } from "./atproto.ts"; 3import { getUriRecord, MiniDoc } from "./slingshot.ts"; 4import * as Constellation from "./constellation.ts"; 5import { DocProxy } from "./caching.ts"; 6 7export type Issue = { 8 body: string; 9 createdAt: string; 10 issueId: number; 11 owner: DID; 12 ownerHandle: string; 13 repo: string; 14 title: string; 15 uri: AtURI; // not part of actual issue 16}; 17export enum IssueStateValues { 18 Open = "sh.tangled.repo.issue.state.open", 19 Closed = "sh.tangled.repo.issue.state.closed" 20} 21export type IssueState = { 22 issue: AtURI; 23 state: IssueStateValues; 24}; 25 26export type IssueMeta = { 27 issue: Issue; 28 state: IssueState; 29}; 30export type RepoRef = { 31 readonly owner: string; 32 readonly name: string; 33}; 34type RepoCommon = { 35 readonly description: string; 36 readonly name: string; 37 readonly knot: string; 38 readonly spindle: string; 39 readonly createdAt: string; 40} 41type RawRepo = RepoCommon & { 42 readonly owner: string; 43}; 44export type Repo = RepoCommon & { 45 readonly owner: MiniDoc; // The record itself returns a DID, but a MiniDoc is awfully handy. 46 readonly uri: AtURI; 47}; 48 49export async function GetRepo(ref: RepoRef): Promise<Repo> { 50 const repoOwnerDoc = await DocProxy.get(ref.owner); 51 const ownedRepos = await ListRecords<RawRepo>(repoOwnerDoc.did, "sh.tangled.repo", repoOwnerDoc.pds); 52 const repoRecord = ownedRepos.records.find(x=>x.value.name == ref.name)!; 53 return { 54 ...repoRecord.value, 55 owner: repoOwnerDoc, 56 uri: AtURI.fromString(repoRecord.uri) 57 }; 58} 59export async function GetIssues(repo: Repo, timeout: number = 10000) { 60 const allIssueRefs = await x.timeout(timeout, Constellation.getLinks(repo.uri.toString()!, "sh.tangled.repo.issue", ".repo")); 61 const issues = await Promise.all(allIssueRefs.map(async (uri)=>{ 62 try { 63 const issue = (await x.timeout(timeout/5,getUriRecord<Issue>(uri))).value; 64 issue.uri = uri; 65 issue.ownerHandle = (await DocProxy.get(issue.owner)).handle; 66 return issue; 67 } catch { 68 console.log(`issue timed out: ${uri.toString()}`); 69 return null; 70 } 71 })) as unknown as Issue[]; // despite filtering them out, typescript still thinks there could be nulls 72 return issues.filter(x=>x!=null).sort((a,b)=>b.issueId-a.issueId); 73} 74export async function GetIssueState(issue: Issue) { 75 const ref = await Constellation.getLinks(issue.uri.toString()!, "sh.tangled.repo.issue.state", ".issue"); 76 const state = GetRecord<IssueState>(ref[0]); 77 return state; 78} 79export async function GetIssueWithMeta(uri: AtURI) { 80 const issue = (await getUriRecord<Issue>(uri)).value; 81 const state = await GetIssueState(issue); 82 return {issue, state}; 83} 84 85/** Takes a string like `tangled.sh/core` or `https://tangled.sh/@tangled.sh/core` and returns a {@link RepoRef} */ 86export function StringRepoRef(repo: string): RepoRef { 87 // pick out repo info 88 const repoSplat = repo.split("//"); 89 let repoOwner: string; 90 let repoName: string; 91 if (repoSplat.length == 1) { 92 const repoHalves = repo.split("/"); 93 if (repoHalves.length == 1) throw new Error("invalid repo string"); 94 repoOwner = repoHalves[0]; 95 repoName = repoHalves[1]; 96 } else { 97 if (repoSplat[0] == "https:") { 98 const repoUrlSplat = new URL(repo).pathname.split("/"); 99 // [ "", "@tangled.sh", "core" ] 100 if (repoUrlSplat.length < 2) throw new Error("invalid repo url"); 101 repoOwner = repoUrlSplat[1]; 102 repoName = repoUrlSplat[2]; 103 } else { 104 throw new Error("unknown repo uri scheme"); 105 } 106 } 107 if (repoOwner.startsWith("@")) repoOwner = repoOwner.substring(1); 108 return {owner: repoOwner, name: repoName}; 109}