import { errorResponse, targetFrom } from "@/lib/annotations/server"; import { readNotes } from "@/lib/annotations/store.mjs"; import { writeNote } from "@/lib/annotations/targets.mjs"; export const dynamic = "force-dynamic"; // Notes on an article or a report-video project (lib/annotations/, docs/notes.md). // // GET ?article=/ | ?project= // { subject, file, token, doc, source, error? } -- doc null when // there are no notes; `source` is what a first write would record. // POST same params, body { token, op: { op: "add" | "edit" | "status" | // "reply" | "delete" | "delete-reply" | "source", ... } } // { doc, token, note }. 409 when `token` is stale or the file on // disk is not a notes doc; 400 for a refused op or target. // // Every write from here is the OPERATOR's. An agent writes through // `umtool notes`, which stamps "agent"; there is no way to claim to be one here. const NO_STORE = { "cache-control": "no-store" }; function params(request: Request) { const url = new URL(request.url); return { article: url.searchParams.get("article"), project: url.searchParams.get("project") }; } export async function GET(request: Request) { try { const target = await targetFrom(params(request)); const read = await readNotes(target.file); const source = read.doc?.source ?? (await target.source()); return Response.json( { subject: target.subject, file: target.file, token: read.token, doc: read.doc, source: source ?? null, ...(read.error ? { error: read.error } : {}) }, { headers: NO_STORE }, ); } catch (err) { return errorResponse(err); } } export async function POST(request: Request) { try { const target = await targetFrom(params(request)); const body = (await request.json().catch(() => null)) as { token?: unknown; op?: unknown } | null; if (!body || typeof body.op !== "object" || body.op === null) return Response.json({ error: "body needs an op" }, { status: 400 }); const token = typeof body.token === "string" ? body.token : null; const out = await writeNote(target, body.op as Record, { by: "operator", token }); return Response.json(out, { headers: NO_STORE }); } catch (err) { return errorResponse(err); } }