Spaces:
Running
Running
| 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; | |
| }, | |
| }; | |
| } | |