import * as http from 'node:http'; import * as fs from 'node:fs'; import sirv from 'sirv'; export function createServer(options) { let currentManifest = options.manifest; let currentFileMapping = options.fileMapping; const staticHandler = sirv(options.bundlePath, { single: true }); const requestHandler = (req, res) => { const url = req.url || '/'; const method = req.method || 'GET'; // Route 1: GET /dashboard-manifest.json if (method === 'GET' && url === '/dashboard-manifest.json') { const body = JSON.stringify(currentManifest); res.writeHead(200, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body), }); res.end(body); return; } // Route 2: GET /dashboards/{dirName}/{fileName} if (method === 'GET' && url.startsWith('/dashboards/')) { const pathSegment = url.slice('/dashboards/'.length); const absolutePath = currentFileMapping[pathSegment]; if (!absolutePath) { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Not found' })); return; } try { const content = fs.readFileSync(absolutePath, 'utf-8'); res.writeHead(200, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(content), }); res.end(content); } catch { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Not found' })); } return; } // Route 3: All other paths → delegate to sirv static handler staticHandler(req, res); }; const server = http.createServer(requestHandler); return { start() { return new Promise((resolve, reject) => { const onError = (err) => { if (err.code === 'EADDRINUSE') { reject(new Error(`Port ${options.port} is already in use`)); } else { reject(err); } }; server.once('error', onError); server.listen(options.port, () => { server.removeListener('error', onError); resolve(); }); }); }, stop() { return new Promise((resolve, reject) => { server.close((err) => { if (err) { reject(err); } else { resolve(); } }); }); }, updateManifest(manifest, fileMapping) { currentManifest = manifest; currentFileMapping = fileMapping; }, }; }