import { MAX_REQUESTS } from './config/env.js'; const sseClients = new Set(); const requests = []; export function registerSse(req, res, initialStatus = {}) { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Cache-Control', 'no-transform'); res.setHeader('Connection', 'keep-alive'); // Disable proxy buffering in Nginx res.setHeader('X-Accel-Buffering', 'no'); res.flushHeaders?.(); res.write(`event: hello\n`); res.write(`data: {"ok":true}\n\n`); if (initialStatus && Object.keys(initialStatus).length) { res.write(`event: status\n`); res.write(`data: ${JSON.stringify(initialStatus)}\n\n`); } sseClients.add(res); // Heartbeat to keep proxies/load balancers from timing out idle SSE // Send a comment line every 20s const hb = setInterval(() => { try { res.write(`: ping\n\n`); } catch { /* ignore */ } }, 20000); req.on('close', () => { clearInterval(hb); sseClients.delete(res); }); } export function pushRequest(rec) { requests.push(rec); while (requests.length > MAX_REQUESTS) requests.shift(); const payload = `data: ${JSON.stringify(rec)}\n\n`; for (const res of sseClients) { try { res.write(payload); } catch { /* ignore */ } } } export function broadcastStatus(payload) { const ev = `event: status\n` + `data: ${JSON.stringify(payload)}\n\n`; for (const res of sseClients) { try { res.write(ev); } catch { /* ignore */ } } } export function clearRequests() { requests.length = 0; const payload = `event: clear\n` + `data: {"ok":true}\n\n`; for (const res of sseClients) { try { res.write(payload); } catch { /* ignore */ } } } export function getRecentRequests() { return requests.slice(-MAX_REQUESTS); }