Files

94 lines
3.7 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAnomalyRouter = createAnomalyRouter;
const express_1 = require("express");
const fs_1 = __importDefault(require("fs"));
function createAnomalyRouter(store, enrichmentService) {
const router = (0, express_1.Router)();
// GET /api/anomalies — list all anomalies (optionally filtered)
router.get('/', (req, res) => {
const sessionId = req.query['sessionId'];
const severity = req.query['severity'];
const anomalies = store.getAllAnomalies(sessionId, severity);
const mapped = anomalies.map((a) => ({
id: a.id,
sessionId: store.findSessionForAnomaly(a.id),
type: a.type,
severity: a.severity,
description: a.description,
timestamp: a.timestamp,
screenshotUrl: a.evidence.screenshotPath
? `/api/anomalies/${a.id}/screenshot`
: undefined,
}));
res.json(mapped);
});
// GET /api/anomalies/:anomalyId — full anomaly detail
router.get('/:anomalyId', (req, res) => {
const anomalyId = req.params['anomalyId'];
const anomaly = store.getAnomaly(anomalyId);
if (!anomaly) {
res.status(404).json({ error: 'Anomaly not found' });
return;
}
res.json({
...anomaly,
sessionId: store.findSessionForAnomaly(anomaly.id),
screenshotUrl: anomaly.evidence.screenshotPath
? `/api/anomalies/${anomaly.id}/screenshot`
: undefined,
});
});
// GET /api/anomalies/:anomalyId/screenshot — serve PNG
router.get('/:anomalyId/screenshot', (req, res) => {
const anomalyId = req.params['anomalyId'];
const filePath = store.screenshotPath(anomalyId);
if (!filePath || !fs_1.default.existsSync(filePath)) {
res.status(404).json({ error: 'Screenshot not found' });
return;
}
res.setHeader('Content-Type', 'image/png');
fs_1.default.createReadStream(filePath).pipe(res);
});
// POST /api/anomalies/:anomalyId/replay — trigger replay
router.post('/:anomalyId/replay', async (req, res) => {
const anomalyId = req.params['anomalyId'];
try {
const replayId = await store.replayAnomaly(anomalyId);
res.json({ replayId, status: 'running' });
}
catch (err) {
const msg = err instanceof Error ? err.message : String(err);
res.status(404).json({ error: msg });
}
});
// POST /api/anomalies/:anomalyId/enrich — AI enrichment
router.post('/:anomalyId/enrich', async (req, res) => {
const anomalyId = req.params['anomalyId'];
const anomaly = store.getAnomaly(anomalyId);
if (!anomaly) {
res.status(404).json({ error: 'Anomaly not found' });
return;
}
if (!enrichmentService?.hasProvider()) {
res.status(503).json({ error: 'No AI provider configured (set ABE_AI_PROVIDER)' });
return;
}
const context = {
domSnapshot: '',
httpLog: anomaly.evidence.httpLog ?? [],
consoleErrors: anomaly.evidence.rawErrors ?? [],
actionTrace: anomaly.actionTrace,
pageTitle: '',
url: anomaly.actionTrace[anomaly.actionTrace.length - 1]?.url ?? '',
};
// Run async — emit WS event when done
void enrichmentService.enrich(anomaly, context);
res.json({ status: 'enriching', anomalyId });
});
return router;
}