Files
flipnote-editor/tools/serve.cjs
T
2026-10-29 11:56:15 +00:00

24 lines
1.6 KiB
JavaScript

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}`));