Vectrum
Sign In
44 lines · 2.1 KB · TypeScript
import "server-only";
import { getViewer } from "@/lib/auth";
import { getOrg, orgRole, roleAtLeast, type OrgRole } from "@/lib/orgs";
import { canWrite, findRepo, findRepoById, repoAccess, type Access } from "@/lib/repos";

export class ActionError extends Error {}

export async function viewerOrThrow() {
  const viewer = await getViewer();
  if (!viewer) throw new ActionError("You must be signed in to do that.");
  return viewer;
}

/** Loads a repository for a server action and checks the viewer's access level. */
export async function repoForAction(owner: string, name: string, need: "read" | "write" | "admin") {
  const viewer = await viewerOrThrow();
  const repo = await findRepo(owner, name);
  const access: Access = repo ? await repoAccess(repo, viewer.id) : null;
  if (!repo || !access) throw new ActionError("Repository not found.");
  if (need === "write" && !canWrite(access)) throw new ActionError("You don't have push access to this repository.");
  if (need === "admin" && access !== "admin") throw new ActionError("Only the owner can change these settings.");
  return { repo, viewer, access };
}

/** Loads an organization for a server action and checks that the viewer has at least the role `need` in it. */
export async function orgForAction(name: string, need: OrgRole) {
  const viewer = await viewerOrThrow();
  const org = await getOrg(name);
  const role = org ? await orgRole(org.id, viewer.id) : null;
  if (!org || !role) throw new ActionError("Organization not found.");
  if (!roleAtLeast(role, need)) throw new ActionError("Only the organization's owners can do that.");
  return { org, viewer, role };
}

/** Of the repositories picked in a form, the ones the viewer may hand to a token or app with `permission`. */
export async function grantableRepoIds(viewerId: string, ids: string[], permission: "read" | "write") {
  const out: string[] = [];
  for (const id of new Set(ids)) {
    const repo = await findRepoById(id);
    const access = repo ? await repoAccess(repo, viewerId) : null;
    if (access && (permission === "read" || canWrite(access))) out.push(id);
  }
  return out;
}