import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import { isPrincipalContext, requirePermission, requireSameOriginOrNonBrowser, } from "../auth/authorization.js"; import { PiManagementError, type PiManagementService } from "../pi/management.js"; export function piManagementRoutes( app: FastifyInstance, deps: { service: PiManagementService }, ): void { app.get("/pi-management/status", async (request, reply) => run(request, reply, deps, () => deps.service.status())); app.post("/pi-management/test", async (request, reply) => run(request, reply, deps, () => deps.service.test())); app.get("/pi-management/logs", async (request, reply) => run(request, reply, deps, () => deps.service.logs())); } async function run( request: FastifyRequest, reply: FastifyReply, deps: { service: PiManagementService }, action: () => Promise, ): Promise { const principal = requirePermission(request, reply, "pi.manage"); if (!isPrincipalContext(principal)) return principal; if (principal.issuer === "local" && isWrite(request.method)) { const csrfDenied = requireSameOriginOrNonBrowser(request, reply); if (csrfDenied) return csrfDenied; } try { return await action(); } catch (error) { if (error instanceof PiManagementError) { return reply.code(503).send({ code: error.code, error: error.message }); } return reply.code(503).send({ code: "pi_management_unavailable", error: "Pi management is unavailable" }); } } function isWrite(method: string): boolean { return method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE"; }