"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createFindingsRouter = createFindingsRouter; const express_1 = require("express"); const MarkdownExporter_1 = require("../exporters/MarkdownExporter"); const JSONExporter_1 = require("../exporters/JSONExporter"); const PlaywrightScriptExporter_1 = require("../exporters/PlaywrightScriptExporter"); const path_1 = __importDefault(require("path")); function createFindingsRouter(deps) { const router = (0, express_1.Router)(); const markdownExporter = new MarkdownExporter_1.MarkdownExporter(); const jsonExporter = new JSONExporter_1.JSONExporter(); const playwrightExporter = new PlaywrightScriptExporter_1.PlaywrightScriptExporter(); // GET /api/findings — list findings with filters router.get('/', async (req, res) => { const { sessionId, severity, type, status, search } = req.query; const result = await deps.listFindings.execute({ sessionId, severity, type, status, search }); if (!result.ok) { res.status(500).json({ error: result.error }); return; } const { findings, total } = result.value; res.json({ findings: findings.map(f => toDTO(f)), total, }); }); // GET /api/findings/stats — aggregate stats router.get('/stats', async (req, res) => { const { sessionId } = req.query; const result = await deps.findingStats.execute({ sessionId }); if (!result.ok) { res.status(500).json({ error: result.error }); return; } res.json(result.value); }); // GET /api/findings/:id — finding detail (includes actionTrace) router.get('/:id', async (req, res) => { const findingId = req.params['id']; const result = await deps.getFinding.execute({ findingId }); if (!result.ok) { res.status(404).json({ error: result.error }); return; } const f = result.value; res.json({ ...toDTO(f), actionTrace: f.actionTrace }); }); // PATCH /api/findings/:id/status — update status router.patch('/:id/status', async (req, res) => { const findingId = req.params['id']; const { action } = req.body; if (!action || !['resolve', 'close', 'investigate'].includes(action)) { res.status(400).json({ error: 'action must be one of: resolve, close, investigate' }); return; } const result = await deps.resolveFinding.execute({ findingId, action }); if (!result.ok) { res.status(404).json({ error: result.error }); return; } res.json(result.value); }); // POST /api/findings/:id/enrich — trigger AI enrichment router.post('/:id/enrich', async (req, res) => { const findingId = req.params['id']; const result = await deps.enrichFinding.execute({ findingId }); if (!result.ok) { res.status(422).json({ error: result.error }); return; } res.json(result.value); }); // GET /api/findings/:id/export/markdown — download as Markdown router.get('/:id/export/markdown', async (req, res) => { const findingId = req.params['id']; const result = await deps.getFinding.execute({ findingId }); if (!result.ok) { res.status(404).json({ error: result.error }); return; } const outputDir = path_1.default.join(process.cwd(), 'reports', findingId); const filePath = await markdownExporter.export(result.value, outputDir); res.download(filePath, `finding-${findingId}.md`); }); // GET /api/findings/:id/export/json — download as JSON router.get('/:id/export/json', async (req, res) => { const findingId = req.params['id']; const result = await deps.getFinding.execute({ findingId }); if (!result.ok) { res.status(404).json({ error: result.error }); return; } const outputDir = path_1.default.join(process.cwd(), 'reports', findingId); const filePath = await jsonExporter.export(result.value, outputDir); res.download(filePath, `finding-${findingId}.json`); }); // GET /api/findings/:id/export/playwright — download Playwright script router.get('/:id/export/playwright', async (req, res) => { const findingId = req.params['id']; const result = await deps.getFinding.execute({ findingId }); if (!result.ok) { res.status(404).json({ error: result.error }); return; } const script = playwrightExporter.generate(result.value); res.setHeader('Content-Type', 'text/javascript'); res.setHeader('Content-Disposition', `attachment; filename="finding-${findingId}.spec.js"`); res.send(script); }); return router; } function toDTO(f) { return { id: f.id.toString(), sessionId: f.sessionId, type: f.type.value, severity: f.severity.value, description: f.description, status: f.status.value, browser: f.browser, browserVersion: f.browserVersion, actionTraceLength: f.actionTrace.length, evidence: f.evidence.toJSON(), aiEnrichment: f.aiEnrichment ?? null, createdAt: f.createdAt.toISOString(), resolvedAt: f.resolvedAt?.toISOString() ?? null, }; }