import type { Did } from "@atcute/lexicons/syntax";
import { error } from "@sveltejs/kit";
import type { BobbinContext, XrpcRequestInit } from "#lib/api/client.ts";
import { items } from "#lib/api/pagination.ts";
export type RepoRole = "owner" | "collaborator" | "none";
export interface RepoAccess {
readonly role: RepoRole;
readonly canPush: boolean;
readonly canAdminister: boolean;
}
export const NO_ACCESS: RepoAccess = { role: "none", canPush: false, canAdminister: false };
export const accessFor = (role: RepoRole): RepoAccess => ({
role,
canPush: role !== "none",
canAdminister: role === "owner"
});
export interface RepoIdentity {
readonly ownerDid: string;
readonly repoDid?: string;
}
const COLLABORATOR_PAGES = 5;
export const resolveRepoAccess = async (
ctx: BobbinContext,
repo: RepoIdentity,
viewerDid: string | undefined,
init?: XrpcRequestInit
): Promise<RepoAccess> => {
if (!viewerDid) return NO_ACCESS;
if (viewerDid === repo.ownerDid) return accessFor("owner");
if (!repo.repoDid) return NO_ACCESS;
for await (const collaborator of items(
ctx,
"org.tangled.repo.listCollaborators",
{ subject: repo.repoDid as Did, limit: 100 },
{ ...init, maxPages: COLLABORATOR_PAGES }
)) {
if (collaborator.subject === viewerDid) return accessFor("collaborator");
}
return NO_ACCESS;
};
export const requireRepoAdmin = (access: RepoAccess): void => {
if (!access.canAdminister) error(403, "Only the repository owner can change this");
};