feat: add screenshot list and file serving endpoints for debug viewer

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
ValueOn AG 2026-02-18 22:00:33 +01:00
parent c93bce1b8b
commit 23cb8c890f

View file

@ -1,5 +1,7 @@
import express, { Express, Request, Response } from 'express'; import express, { Express, Request, Response } from 'express';
import { Server } from 'http'; import { Server } from 'http';
import path from 'path';
import fs from 'fs';
import { logger } from '../utils/logger'; import { logger } from '../utils/logger';
import { config } from '../config'; import { config } from '../config';
import { runAuthTests, runSingleVariant, getVariantIds } from '../bot/authTestProcedure'; import { runAuthTests, runSingleVariant, getVariantIds } from '../bot/authTestProcedure';
@ -184,5 +186,61 @@ export class HttpServer {
res.status(500).json({ error: (error as Error).message }); res.status(500).json({ error: (error as Error).message });
} }
}); });
// List screenshots for a session
// Filename format: {sessionId}-{step}-{timestamp}.png
this._app.get('/api/bot/screenshots/:sessionId', (req: Request, res: Response) => {
try {
const { sessionId } = req.params;
const screenshotDir = config.screenshotDir;
if (!fs.existsSync(screenshotDir)) {
res.json({ screenshots: [] });
return;
}
const files = fs.readdirSync(screenshotDir)
.filter(f => f.startsWith(`${sessionId}-`) && f.endsWith('.png'))
.sort();
const screenshots = files.map(name => {
const stats = fs.statSync(path.join(screenshotDir, name));
const withoutExt = name.replace('.png', '');
const parts = withoutExt.split('-');
// sessionId is a UUID (5 parts joined by -), step follows, timestamp is last
const timestamp = parseInt(parts[parts.length - 1], 10) || 0;
const step = parts.slice(5, -1).join('-');
return { name, step, timestamp, sizeBytes: stats.size };
});
res.json({ screenshots });
} catch (error) {
logger.error('Error listing screenshots:', error);
res.status(500).json({ error: (error as Error).message });
}
});
// Serve a single screenshot file
this._app.get('/api/bot/screenshots/file/:filename', (req: Request, res: Response) => {
try {
const { filename } = req.params;
if (!filename.endsWith('.png') || filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
res.status(400).json({ error: 'Invalid filename' });
return;
}
const filepath = path.join(config.screenshotDir, filename);
if (!fs.existsSync(filepath)) {
res.status(404).json({ error: 'Screenshot not found' });
return;
}
res.type('image/png').sendFile(path.resolve(filepath));
} catch (error) {
logger.error('Error serving screenshot:', error);
res.status(500).json({ error: (error as Error).message });
}
});
} }
} }