import { Router } from "express"; import { z } from "zod"; import { db } from "../db/client.js"; import { hashToken } from "../services/tokens.js"; import { syncServerTasks } from "../services/taskSync.js"; export const agentReportRouter = Router(); const reportSchema = z.object({ hostname: z.string().max(255).optional(), os_type: z.string().optional(), reported_at: z.string().optional(), tasks: z.array( z.object({ schedule_type: z.enum(["cron", "systemd_timer"]), name: z.string().min(1), command: z.string().optional(), schedule_expression: z.string().optional(), source: z.string().optional(), enabled: z.boolean().optional(), next_run_at: z.string().optional(), metadata: z.unknown().optional(), }), ), }); agentReportRouter.post("/", async (req, res) => { const authHeader = req.header("authorization") ?? ""; const match = authHeader.match(/^Bearer\s+(.+)$/i); if (!match) { return res.status(401).json({ error: "missing_token" }); } const tokenHash = hashToken(match[1]); const server = await db.query.servers.findFirst({ where: (s, { eq }) => eq(s.apiTokenHash, tokenHash), }); if (!server) { return res.status(401).json({ error: "invalid_token" }); } const parsed = reportSchema.safeParse(req.body); if (!parsed.success) { return res.status(400).json({ error: "invalid_body", details: parsed.error.flatten() }); } await syncServerTasks(server.id, { hostname: parsed.data.hostname, tasks: parsed.data.tasks.map((t) => ({ scheduleType: t.schedule_type, name: t.name, command: t.command, scheduleExpression: t.schedule_expression, source: t.source, enabled: t.enabled, nextRunAt: t.next_run_at, metadata: t.metadata, })), }); res.status(202).json({ ok: true, taskCount: parsed.data.tasks.length }); });