import { Hono } from 'hono'; import type { Bindings } from '../types'; import { graphSchema } from '../lib/schemas'; import { recordTelemetry } from '../lib/telemetry'; export const validateRouter = new Hono<{ Bindings: Bindings }>(); // POST /validate — 驗證圖定義(不執行) validateRouter.post('/validate', async (c) => { const start = Date.now(); const apiKey = c.req.header('X-Arcrun-API-Key'); const userAgent = c.req.header('User-Agent') ?? undefined; const body = await c.req.json(); const parsed = graphSchema.safeParse(body); if (!parsed.success) { recordTelemetry(c.env, apiKey, { event_type: 'validation_error', error_code: 'schema_failed', duration_ms: Date.now() - start, agent_user_agent: userAgent, }, c.executionCtx); return c.json({ valid: false, errors: parsed.error.issues }, 400); } const nodeIds = new Set(parsed.data.nodes.map(n => n.id)); const invalidEdges = parsed.data.edges.filter(e => !nodeIds.has(e.from) || !nodeIds.has(e.to)); if (invalidEdges.length > 0) { recordTelemetry(c.env, apiKey, { event_type: 'validation_error', error_code: 'edge_node_missing', duration_ms: Date.now() - start, agent_user_agent: userAgent, }, c.executionCtx); return c.json({ valid: false, errors: invalidEdges.map(e => `邊 ${e.from} → ${e.to} 指向不存在的節點`), }, 400); } return c.json({ valid: true, nodeCount: parsed.data.nodes.length, edgeCount: parsed.data.edges.length }); });