import type { Did } from "@atcute/lexicons/syntax"; import type { BobbinContext, XrpcRequestInit } from "#lib/api/client.ts"; import { IdentityCache } from "#lib/api/identity.ts"; import { collect } from "#lib/api/pagination.ts"; export type CollaboratorStanding = "owner" | "collaborator"; export interface CollaboratorView { did: string; handle: string; standing: CollaboratorStanding; since?: string; } const MAX_COLLABORATORS = 200; export const listCollaborators = async ( ctx: BobbinContext, repo: { ownerDid: string; repoDid?: string }, init?: XrpcRequestInit ): Promise => { const identities = new IdentityCache(ctx); const rows: Omit[] = [{ did: repo.ownerDid, standing: "owner" }]; if (repo.repoDid) { const subject = repo.repoDid as Did; const page = { ...init, max: MAX_COLLABORATORS }; const accepted = await collect( ctx, "org.tangled.repo.listCollaborators", { subject, limit: 100 }, page ); const seen = new Set([repo.ownerDid]); for (const item of accepted) { if (seen.has(item.subject)) continue; seen.add(item.subject); rows.push({ did: item.subject, standing: "collaborator", since: item.effectiveSince }); } } const named: CollaboratorView[] = []; for (const row of rows) { const handle = await identities .resolve(row.did, init) .then((doc) => doc.handle) .catch(() => row.did); named.push({ ...row, handle }); } return named; };