import type { TaskTreeCommand } from "./contracts.ts"; export function createTaskTreeHttpApp(options: { dispatch: (command: TaskTreeCommand) => Promise; close?: () => Promise }) { return { async fetch(request: Request): Promise { const url = new URL(request.url); if (url.pathname === "/health/live") return json(200, { ok: true, serviceId: "hwlab-tasktree-api", status: "live" }); if (url.pathname === "/health/ready") return resultResponse(await options.dispatch({ operation: "health" })); if (url.pathname === "/v1/tasktree/groups" && request.method === "GET") return resultResponse(await options.dispatch({ operation: "group.list" })); if (url.pathname === "/v1/tasktree/groups" && request.method === "POST") { const body = await bodyObject(request); return resultResponse(await options.dispatch({ operation: "group.create", name: text(body.name), description: text(body.description) }), 201); } const timeline = /^\/v1\/tasktree\/groups\/([^/]+)\/timeline$/u.exec(url.pathname); if (timeline && request.method === "GET") return resultResponse(await options.dispatch({ operation: "timeline.get", groupId: decodeURIComponent(timeline[1]) })); if (url.pathname === "/v1/tasktree/commands" && request.method === "POST") { return resultResponse(await options.dispatch(await bodyObject(request) as TaskTreeCommand)); } return json(404, { ok: false, error: { code: "not_found", message: "TaskTree route was not found" } }); }, close: options.close ?? (async () => {}) }; } function resultResponse(result: any, successStatus = 200) { const status = result?.ok === true ? successStatus : result?.error?.code?.includes("not_found") ? 404 : 400; return json(status, result); } async function bodyObject(request: Request): Promise> { 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 text(value: unknown) { return String(value ?? ""); } function json(status: number, body: unknown) { return Response.json(body, { status, headers: { "cache-control": "no-store" } }); }