import { createReadStream } from 'node:fs'; import { stat } from 'node:fs/promises'; import { createServer } from 'node:http'; import { extname, resolve, relative, isAbsolute } from 'node:path'; import { fileURLToPath } from 'node:url'; const root=fileURLToPath(new URL('./build/',import.meta.url)); const mime={'.html':'text/html; charset=utf-8','.css':'text/css; charset=utf-8', '.js':'text/javascript; charset=utf-8','.mjs':'text/javascript; charset=utf-8', '.svg':'image/svg+xml','.png':'image/png'}; const port=Number(process.env.THRESHOLD_PREVIEW_PORT||4176); createServer(async(request,response)=>{ try { const pathname=decodeURIComponent(new URL(request.url,'http://localhost').pathname); const file=resolve(root,pathname==='/'?'index.html':pathname.replace(/^[/\\]+/,'')); const within=relative(root,file); if(within.startsWith('..')||isAbsolute(within)) { response.writeHead(404); response.end('Not found'); return; } if(!['GET','HEAD'].includes(request.method)){response.writeHead(405,{'allow':'GET, HEAD'});response.end();return;} if(!(await stat(file)).isFile()){response.writeHead(404);response.end('Not found');return;} response.writeHead(200,{'content-type':mime[extname(file)]||'application/octet-stream', 'cache-control':'no-store','x-content-type-options':'nosniff', 'content-security-policy':"default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"}); if(request.method==='HEAD') response.end(); else createReadStream(file).on('error',()=>response.destroy()).pipe(response); } catch(error) { response.writeHead(error instanceof URIError?400:404); response.end(error instanceof URIError?'Invalid URL':'Not found'); } }).listen(port,process.env.THRESHOLD_PREVIEW_HOST||'127.0.0.1',()=>console.log('THRESHOLD preview: http://127.0.0.1:'+port));