Files
pikasTech-HWLAB/internal/tasktree/http.ts
T
2026-07-18 10:10:05 +02:00

36 lines
2.3 KiB
TypeScript

import type { TaskTreeCommand } from "./contracts.ts";
export function createTaskTreeHttpApp(options: { dispatch: (command: TaskTreeCommand) => Promise<any>; close?: () => Promise<void> }) {
return {
async fetch(request: Request): Promise<Response> {
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<Record<string, any>> {
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<string, any>;
}
function text(value: unknown) { return String(value ?? ""); }
function json(status: number, body: unknown) { return Response.json(body, { status, headers: { "cache-control": "no-store" } }); }