import { z } from "zod";
import { all } from "../db";
import { notFoundError } from "../errors";
import { limitWrite } from "../limits";
import { approveRunRow, cancelRunRow, loadRunByNumber } from "../ci/run-control";
import { listRepoRunners, mintRegistrationToken, removeRepoRunner, repoScope } from "../ci/runner-registration";
import { forkRunsAllowed, setForkRunsAllowed } from "../ci/runner-policy";
import { noContent, readJson, requireScopedRepo } from "./http";
import type { ApiContext } from "./http";
const MAX_RUNS_LISTED = 20;
const MAX_JOBS_LISTED = 200;
const registrationInput = z.object({
scope: z.enum(["repository", "owner"]).default("repository"),
labels: z.array(z.string().trim().min(1).max(32)).max(20).default([]),
});
const policyInput = z.object({ allow_fork_pull_requests: z.boolean() });
export async function createRegistrationToken(ctx: ApiContext, owner: string, name: string): Promise<Response> {
const data = await readJson(ctx.request, registrationInput);
await limitWrite(ctx.viewer);
const { repo } = await requireScopedRepo(ctx, owner, name, "admin", "admin");
const scope = await repoScope(repo, data.scope, ctx.viewer);
const minted = await mintRegistrationToken(scope, ctx.viewer.id, data.labels);
return Response.json({ token: minted.token, expires_at: minted.expiresAt }, { status: 201 });
}
export async function listRunnersApi(ctx: ApiContext, owner: string, name: string): Promise<Response> {
const { repo } = await requireScopedRepo(ctx, owner, name, "admin", "admin");
return Response.json({
runners: await listRepoRunners(repo),
allow_fork_pull_requests: await forkRunsAllowed(repo.id),
});
}
export async function deleteRunnerApi(ctx: ApiContext, owner: string, name: string, id: string): Promise<Response> {
await limitWrite(ctx.viewer);
const { repo } = await requireScopedRepo(ctx, owner, name, "admin", "admin");
if (!(await removeRepoRunner(repo, id, ctx.viewer))) throw notFoundError("Runner not found");