/** * Simulator Validate Route — UPGRADED * Provider-agnostic validation using LLM Gateway * Full: Schema + NodeRegistry + Graph + Expression + DataFlow + Reliability + Credential */ import { Router } from 'express'; import { z } from 'zod'; import { logger } from '../index'; import { ValidationEngine } from '../agents/validator'; import { createRequestLLM } from '../services/llmClient'; import type { N8nWorkflow, WorkflowGraph } from '../types/workflow'; export const validateRoute: Router = Router(); const ValidateSchema = z.object({ jobId: z.string(), workflow: z.record(z.unknown()), graph: z.record(z.unknown()), llmApiKey: z.string().optional(), openaiApiKey: z.string().optional(), llmModel: z.string().optional(), n8nBaseUrl: z.string(), n8nApiKey: z.string(), final: z.boolean().optional().default(false), }); validateRoute.post('/', async (req, res) => { const parsed = ValidateSchema.safeParse(req.body); if (!parsed.success) { res.status(400).json({ success: false, error: 'Invalid request', details: parsed.error.flatten() }); return; } const { jobId, workflow, graph, n8nBaseUrl, n8nApiKey, final: isFinal } = parsed.data; const apiKey = parsed.data.llmApiKey ?? parsed.data.openaiApiKey ?? process.env['LLM_API_KEY'] ?? process.env['OPENAI_API_KEY'] ?? ''; logger.info({ jobId, final: isFinal }, '[Validate] Starting validation'); try { const llm = createRequestLLM(apiKey); const validator = new ValidationEngine(llm, n8nBaseUrl, n8nApiKey); const validationReport = await validator.validate( jobId, workflow as any as N8nWorkflow, graph as any as WorkflowGraph, ); logger.info({ jobId, valid: validationReport.valid, score: validationReport.overallScore, errors: validationReport.issues.length, }, '[Validate] Complete'); res.json({ success: true, validationReport }); } catch (err) { const message = err instanceof Error ? err.message : 'Validation error'; logger.error({ jobId, err }, '[Validate] Failed'); res.status(500).json({ success: false, error: message, jobId }); } });