const http = require('node:http'); const fs = require('node:fs'); const path = require('node:path'); const root = path.resolve(__dirname, '..'); const port = Number(process.env.PORT || 8090); if (!Number.isInteger(port) || port < 1024 || port > 65535) throw new Error('Choose a port between 1024 and 65535.'); const types = {'.html':'text/html; charset=utf-8','.js':'text/javascript; charset=utf-8','.css':'text/css; charset=utf-8', '.json':'application/json; charset=utf-8','.png':'image/png','.webp':'image/webp','.svg':'image/svg+xml', '.ttf':'font/ttf','.otf':'font/otf','.woff2':'font/woff2','.wav':'audio/wav'}; http.createServer((req,res) => { try { if (!['GET','HEAD'].includes(req.method)) {res.writeHead(405,{'Allow':'GET, HEAD'}).end();return;} const pathname = decodeURIComponent(new URL(req.url,'http://localhost').pathname); const relative = pathname.replace(/^\/+/, '') || 'index.html'; const target = path.resolve(root,relative); if (path.relative(root,target).startsWith('..') || path.isAbsolute(path.relative(root,target)) || relative.split(/[\\/]/).some(part=>part.startsWith('.'))) {res.writeHead(404).end();return;} const stat = fs.statSync(target); if (!stat.isFile()) {res.writeHead(404).end();return;} res.writeHead(200,{'Content-Type':types[path.extname(target)]||'application/octet-stream', 'Content-Length':stat.size,'X-Content-Type-Options':'nosniff','Cache-Control':'no-cache'}); if (req.method==='HEAD')res.end();else fs.createReadStream(target).pipe(res); } catch {res.writeHead(404).end();} }).listen(port,'127.0.0.1',()=>console.log(`Flipnote Editor: http://localhost:${port}`));