// Local-only review server. Serves model evidence and proxies the existing app's real engine/GIS assets. // Nothing from this tool is copied into the production web build. import http from 'node:http' import { createReadStream, existsSync, statSync } from 'node:fs' import { dirname, resolve, extname, sep } from 'node:path' import { fileURLToPath } from 'node:url' const root = dirname(fileURLToPath(import.meta.url)) const upstream = new URL(process.env.COCKPIT_BASE || 'http://127.0.0.1:8001') const port = Number(process.env.MODEL_REVIEW_PORT || 8092) const mime = { '.html': 'text/html; charset=utf-8', '.json': 'application/json', '.glb': 'model/gltf-binary', '.png': 'image/png', } const server = http.createServer((req, res) => { const url = new URL(req.url, 'http://localhost') if (url.pathname === '/' || url.pathname === '/preview.html' || url.pathname.startsWith('/review-assets/')) { const relative = url.pathname.startsWith('/review-assets/') ? decodeURIComponent(url.pathname.slice(15)) : 'preview.html' const file = resolve(root, relative) if (!file.startsWith(root + sep) || !existsSync(file) || !statSync(file).isFile()) { res.writeHead(404) res.end() return } res.writeHead(200, { 'Content-Type': mime[extname(file)] || 'application/octet-stream', 'Cache-Control': 'no-store', }) createReadStream(file).pipe(res) return } const proxy = http.request( new URL(req.url, upstream), { method: req.method, headers: { ...req.headers, host: upstream.host } }, (response) => { res.writeHead(response.statusCode, response.headers) response.pipe(res) } ) proxy.on('error', () => { res.writeHead(502) res.end('Local cockpit preview server unavailable') }) req.pipe(proxy) }) server.listen(port, '127.0.0.1', () => console.log(`Model review: http://127.0.0.1:${port}/preview.html (engine/GIS: ${upstream.origin})`) )