import { caseRunAccepted } from "./transport.ts"; export function createHarnessRLHttpApp(options: { service: ReturnType }) { return { async fetch(request: Request) { const url = new URL(request.url); try { if (url.pathname === "/healthz" || url.pathname === "/health/live") return json(200, { ok: true, serviceId: "hwlab-harnessrl-api" }); if (url.pathname === "/readyz" || url.pathname === "/health/ready") return json(200, await options.service.health()); if (url.pathname === "/v1/caserun" && request.method === "GET") return json(200, { ok: true, contractVersion: "hwlab-caserun-web-v1", casesRoute: "/v1/caserun/cases", runsRoute: "/v1/caserun/runs", executionAuthority: "temporal", registryAuthority: "postgresql" }); if (url.pathname === "/v1/caserun/cases" && request.method === "GET") { const cases = await options.service.listCases(); return json(200, { ok: true, contractVersion: "hwlab-caserun-cases-v1", count: cases.length, cases }); } if (url.pathname === "/v1/caserun/runs" && request.method === "POST") { const body = await bodyObject(request); const record = await options.service.submit({ caseId: String(body.caseId ?? ""), runId: body.runId ? String(body.runId) : undefined, runtimeApiUrl: runtimeApiUrl(request) }); return json(202, caseRunAccepted(record)); } const match = /^\/v1\/caserun\/runs\/([^/]+)(?:\/(events|aggregate|cancel))?$/u.exec(url.pathname); if (match) { const runId = decodeURIComponent(match[1]); const suffix = match[2] ?? ""; if (!suffix && request.method === "GET") return json(200, await options.service.getRun(runId)); if (suffix === "events" && request.method === "GET") return json(200, await options.service.events(runId)); if (suffix === "aggregate" && request.method === "GET") return json(200, await options.service.aggregate(runId)); if (suffix === "cancel" && request.method === "POST") return json(202, await options.service.cancel(runId)); return json(405, errorBody("method_not_allowed", suffix === "cancel" ? "POST required" : "GET required")); } return json(404, errorBody("caserun_route_not_found", "CaseRun REST route is not implemented")); } catch (error: any) { const code = error?.code ?? "harnessrl_error"; const status = code.includes("not_found") ? 404 : code.startsWith("invalid_") ? 400 : 500; return json(status, errorBody(code, error?.message ?? String(error), error?.details)); } }, close: () => options.service.close() }; } async function bodyObject(request: Request) { const body = await request.json().catch(() => null); if (!body || typeof body !== "object" || Array.isArray(body)) throw Object.assign(new Error("JSON object body is required"), { code: "invalid_json" }); return body as Record; } function runtimeApiUrl(request: Request) { const url = new URL(request.url); return `${url.protocol}//${url.host}`; } function errorBody(code: string, message: string, details?: unknown) { return { ok: false, error: { code, message, details } }; } function json(status: number, body: unknown) { return Response.json(body, { status, headers: { "cache-control": "no-store" } }); }