// Static preview of the prebuilt frontend. No API or backend services.
const http = require('node:http');
const fs = require('node:fs');
const path = require('node:path');
const root = path.join(__dirname, 'dist');
const port = Number(process.env.PORT || process.argv[2] || 5175);
const types = { '.html':'text/html; charset=utf-8', '.js':'text/javascript; charset=utf-8', '.css':'text/css; charset=utf-8', '.svg':'image/svg+xml', '.png':'image/png', '.jpg':'image/jpeg', '.woff2':'font/woff2' };
if (!fs.existsSync(path.join(root, 'index.html'))) { console.error('Build files are missing. Run npm install and npm run build first.'); process.exit(1); }
const server = http.createServer((request, response) => {
if (!['GET','HEAD'].includes(request.method)) { response.writeHead(405); response.end(); return; }
let pathname;
try { pathname = decodeURIComponent(new URL(request.url, 'http://localhost').pathname); } catch { response.writeHead(400); response.end(); return; }
const file = path.resolve(root, '.' + pathname + (pathname.endsWith('/') ? 'index.html' : ''));
if (!file.startsWith(root + path.sep)) { response.writeHead(403); response.end(); return; }
fs.stat(file, (error, stat) => {
if (error || !stat.isFile()) { response.writeHead(404); response.end('Not found'); return; }
response.writeHead(200, { 'Content-Type':types[path.extname(file)] || 'application/octet-stream', 'Cache-Control':'no-store', 'X-Content-Type-Options':'nosniff' });
if (request.method === 'HEAD') response.end(); else fs.createReadStream(file).pipe(response);
});
});
server.on('error', error => { console.error(error.code === 'EADDRINUSE' ? `Port ${port} is already in use. Close the existing preview, or set a different PORT.` : error.message); process.exit(1); });
server.listen(port, '127.0.0.1', () => console.log(`CCIL Test Studio: http://127.0.0.1:${port}/\nKeep this terminal open. Press Ctrl+C to stop.`));
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)