import type { BobbinContext, XrpcRequestInit } from "#lib/api/client.ts"; import { jsonGet } from "#lib/api/_request.ts"; import type * as OrgTangledActorGetProfileActivity from "#lib/api/lexicons/types/org/tangled/actor/getProfileActivity.ts"; import type * as OrgTangledActorProfile from "#lib/api/lexicons/types/org/tangled/actor/profile.ts"; import type * as OrgTangledFeedStar from "#lib/api/lexicons/types/org/tangled/feed/star.ts"; import type * as OrgTangledGraphVouch from "#lib/api/lexicons/types/org/tangled/graph/vouch.ts"; import type * as OrgTangledRepoManifest from "#lib/api/lexicons/types/org/tangled/repo/manifest.ts"; import type * as OrgTangledReviewPatch from "#lib/api/lexicons/types/org/tangled/review/patch.ts"; import type * as OrgTangledSnippetString from "#lib/api/lexicons/types/org/tangled/snippet/string.ts"; import type * as OrgTangledTrackGetTicketView from "#lib/api/lexicons/types/org/tangled/track/getTicketView.ts"; import type * as OrgTangledTrackTicket from "#lib/api/lexicons/types/org/tangled/track/ticket.ts"; export interface RecordView { uri: string; cid?: string; value: V; } export interface RecordList { items: RecordView[]; } export type RepoRecord = OrgTangledRepoManifest.Main; export type ProfileRecord = OrgTangledActorProfile.Main; export type TicketRecord = OrgTangledTrackTicket.Main; export type TicketState = OrgTangledTrackTicket.Main["state"]; export type StringRecord = OrgTangledSnippetString.Main; export type StarRecord = OrgTangledFeedStar.Main; export type VouchRecord = OrgTangledGraphVouch.Main; export type ProfileActivityOutput = OrgTangledActorGetProfileActivity.$output; export type ProfileActivityRepoRef = OrgTangledActorGetProfileActivity.RepoRef; export const BULK_LIMIT = 50; // absent when the repo doesn't support git at all export interface GitInfo { defaultBranch: string; isEmpty: boolean; } export type RepoView = RecordView & { knot?: string; git?: GitInfo }; export const getRepo = (ctx: BobbinContext, repo: string, init?: XrpcRequestInit) => jsonGet(ctx, "org.tangled.repo.getRepo", { repo }, init); export const getRepoByRepoDid = (ctx: BobbinContext, repoDid: string, init?: XrpcRequestInit) => jsonGet(ctx, "org.tangled.repo.getRepoByRepoDid", { repoDid }, init); export const getRepoByName = ( ctx: BobbinContext, owner: string, name: string, init?: XrpcRequestInit ) => jsonGet(ctx, "org.tangled.temp.repo.getRepoByName", { owner, name }, init); export interface RepoListPage { cursor?: string | null; items: RecordView[]; } export const listRepos = ( ctx: BobbinContext, subject: string, filter: { limit?: number; cursor?: string; order?: "asc" | "desc" } = {}, init?: XrpcRequestInit ) => jsonGet(ctx, "org.tangled.repo.listRepos", { subject, ...filter }, init); export const getProfile = (ctx: BobbinContext, did: string, init?: XrpcRequestInit) => jsonGet>( ctx, "org.tangled.actor.getProfile", { actor: `at://${did}/org.tangled.actor.profile/self` }, init ); export type TicketViewDetailed = OrgTangledTrackGetTicketView.$output; export const getTicketView = (ctx: BobbinContext, uri: string, init?: XrpcRequestInit) => jsonGet(ctx, "org.tangled.track.getTicketView", { uri }, init); export type PatchRecord = OrgTangledReviewPatch.Main; export const listPatches = (ctx: BobbinContext, ticket: string, init?: XrpcRequestInit) => jsonGet>( ctx, "org.tangled.temp.review.listPatches", { ticket, order: "asc", limit: 500 }, init ); export interface PullListItem { cid?: string; commentCount: number; state: TicketState; stateUpdatedAt?: string; uri: string; value: TicketRecord; } export interface PullListPage { cursor?: string | null; total?: number; items: PullListItem[]; } export interface ListPullsFilter { status?: TicketState; author?: string; limit?: number; cursor?: string; order?: "asc" | "desc"; } export const listPulls = ( ctx: BobbinContext, subject: string, filter: ListPullsFilter = {}, init?: XrpcRequestInit ) => jsonGet(ctx, "org.tangled.repo.listPulls", { subject, ...filter }, init); export const getRepos = (ctx: BobbinContext, repos: readonly string[], init?: XrpcRequestInit) => jsonGet>(ctx, "org.tangled.repo.getRepos", { repos }, init); export const getReposByRepoDids = ( ctx: BobbinContext, dids: readonly string[], init?: XrpcRequestInit ) => jsonGet>(ctx, "org.tangled.repo.getReposByRepoDids", { dids }, init); export const getProfileActivity = ( ctx: BobbinContext, actor: string, months = 7, init?: XrpcRequestInit ) => jsonGet( ctx, "org.tangled.actor.getProfileActivity", { actor, months }, init ); export const getProfiles = ( ctx: BobbinContext, actors: readonly string[], init?: XrpcRequestInit ) => jsonGet>(ctx, "org.tangled.actor.getProfiles", { actors }, init); // one uri outside org.tangled.track.ticket fails the whole batch with a 400 export const getTickets = async ( ctx: BobbinContext, uris: readonly string[], init?: XrpcRequestInit ): Promise> => { const pages = await Promise.all( Array.from({ length: Math.ceil(uris.length / BULK_LIMIT) }, (_, index) => jsonGet>( ctx, "org.tangled.track.getTickets", { uris: uris.slice(index * BULK_LIMIT, (index + 1) * BULK_LIMIT) }, init ) ) ); return { items: pages.flatMap((page) => page.items) }; }; export interface StarListPage { cursor?: string | null; total?: number; items: RecordView[]; } export const listStars = ( ctx: BobbinContext, subject: string, filter: { limit?: number; cursor?: string; offset?: number; order?: "asc" | "desc" } = {}, init?: XrpcRequestInit ) => jsonGet(ctx, "org.tangled.feed.listStars", { subject, ...filter }, init); export const getString = (ctx: BobbinContext, uri: string, init?: XrpcRequestInit) => jsonGet>(ctx, "org.tangled.string.getString", { uri }, init);