Blob Opera MIDI / server.js
server.js1.6 KB
// Optional static file server for local development.
//
// The tool is a pure static single page — it needs no backend (the recording
// upload happens in the browser via a CORS relay, see public/app.js). This
// server exists only so ES modules load over http:// during local dev, since
// browsers block module imports from file://. Any static server works just as
// well (e.g. `python3 -m http.server`).
import http from "node:http";
import { readFile } from "node:fs/promises";
import { extname, join, normalize } from "node:path";
import { fileURLToPath } from "node:url";
const ROOT = join(fileURLToPath(new URL(".", import.meta.url)), "public");
const PORT = process.env.PORT || 8080;
const MIME = {
".html": "text/html; charset=utf-8",
".js": "text/javascript; charset=utf-8",
".css": "text/css; charset=utf-8",
".json": "application/json; charset=utf-8",
".svg": "image/svg+xml",
};
const server = http.createServer(async (req, res) => {
let path = decodeURIComponent(new URL(req.url, "http://x").pathname);
if (path === "/") path = "/index.html";
const filePath = normalize(join(ROOT, path));
if (!filePath.startsWith(ROOT)) {
res.writeHead(403).end("forbidden");
return;
}
try {
const data = await readFile(filePath);
res.writeHead(200, {
"content-type": MIME[extname(filePath)] || "application/octet-stream",
"cache-control": "no-store",
});
res.end(data);
} catch {
res.writeHead(404).end("not found");
}
});
server.listen(PORT, () => {
console.log(`Blob Opera MIDI Embed (static) running at http://localhost:${PORT}`);
});
