import { NextResponse } from "next/server"; import { opsAuth, opsFail } from "../../_lib"; import { readJob } from "../../_jobs"; export const dynamic = "force-dynamic"; // GET /api/ops/job/[?tail=] // // ONE JOB'S STATE, behind the token: its kind, channel, status, times, exit // code and replay flag — from the registry while it is live, from its // `.meta.json` sidecar after — and, while it is queued or running, WHERE it // waits: `queue: {key, position, queued, head}` (0 = running at the head; the // head is the job holding the queue when it is not this one). `?tail=N` adds the // log's last N lines (at most 500), read from the end of the file. // // What `pnpm ops --wait` asks when the log endpoint stops answering, in place of // the `/api/jobs/active` view: that is a UI poll — ungated, a rewrite onto // /api/view/activeJobs that builds the whole live payload (channel stats, the // disk gate, every runner's status) to answer "is job X still there?". This // reads one record and one sidecar, and it can say how the job ended after the // registry forgot it, which the active list never could. // // An id neither the registry nor `.jobs/` knows is a 404 `{ ok: false }`. const MAX_TAIL = 500; export async function GET( request: Request, { params }: { params: Promise<{ id: string }> }, ) { const denied = opsAuth(request); if (denied) return denied; const { id } = await params; // The log route's own id rule: the id names a file under .jobs/. if (!/^[A-Za-z0-9_-]+$/.test(id)) return opsFail(`"${id}" is not a job id`); const url = new URL(request.url); const unknown = [...url.searchParams.keys()].filter((k) => k !== "tail"); if (unknown.length) { return opsFail(`unknown query key(s): ${unknown.join(", ")} — accepted: tail`); } const rawTail = url.searchParams.get("tail"); let tail = 0; if (rawTail !== null) { tail = Number(rawTail); if (!Number.isInteger(tail) || tail <= 0) { return opsFail('"tail" must be a whole number of lines above zero'); } tail = Math.min(tail, MAX_TAIL); } const found = await readJob(id, tail); if (!found) return opsFail(`no job "${id}"`, 404); return NextResponse.json({ ok: true, ...found }); }