Initial import of HEROLL source and design documents
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import http from "node:http";
|
||||
import { readFile, stat } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.resolve(scriptDir, "../..");
|
||||
const port = Number(process.env.HEROLL_MVP_PORT || 4173);
|
||||
const parentPidFlag = process.argv.indexOf("--parent-pid");
|
||||
const parentPid = parentPidFlag >= 0 ? Number(process.argv[parentPidFlag + 1]) : 0;
|
||||
const mime = new Map([
|
||||
[".html", "text/html; charset=utf-8"],
|
||||
[".js", "text/javascript; charset=utf-8"],
|
||||
[".mjs", "text/javascript; charset=utf-8"],
|
||||
[".css", "text/css; charset=utf-8"],
|
||||
[".json", "application/json; charset=utf-8"],
|
||||
[".csv", "text/csv; charset=utf-8"],
|
||||
[".png", "image/png"],
|
||||
[".jpg", "image/jpeg"],
|
||||
[".jpeg", "image/jpeg"],
|
||||
[".svg", "image/svg+xml"],
|
||||
[".wav", "audio/wav"],
|
||||
[".ogg", "audio/ogg"]
|
||||
]);
|
||||
|
||||
function safePath(urlPath) {
|
||||
const decoded = decodeURIComponent(urlPath.split("?")[0] || "/");
|
||||
const relative = decoded === "/" ? "mvp/index.html" : decoded.replace(/^\/+/, "");
|
||||
const resolved = path.resolve(rootDir, relative);
|
||||
if (!resolved.startsWith(rootDir + path.sep) && resolved !== rootDir) return null;
|
||||
return resolved;
|
||||
}
|
||||
|
||||
const server = http.createServer(async (req, res) => {
|
||||
try {
|
||||
let target = safePath(req.url || "/");
|
||||
if (!target) {
|
||||
res.writeHead(403).end("Forbidden");
|
||||
return;
|
||||
}
|
||||
const info = await stat(target);
|
||||
if (info.isDirectory()) target = path.join(target, "index.html");
|
||||
const body = await readFile(target);
|
||||
res.writeHead(200, {
|
||||
"Content-Type": mime.get(path.extname(target).toLowerCase()) || "application/octet-stream",
|
||||
"Cache-Control": "no-store",
|
||||
"Cross-Origin-Resource-Policy": "same-origin"
|
||||
});
|
||||
res.end(body);
|
||||
} catch (error) {
|
||||
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
||||
res.end(`Not found\n${String(error)}`);
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(port, "127.0.0.1", () => {
|
||||
console.log(`HEROLL MVP running at http://127.0.0.1:${port}/mvp/`);
|
||||
console.log("Press Ctrl+C to stop.");
|
||||
});
|
||||
|
||||
if (Number.isInteger(parentPid) && parentPid > 0) {
|
||||
const parentWatch = setInterval(() => {
|
||||
try {
|
||||
process.kill(parentPid, 0);
|
||||
} catch {
|
||||
clearInterval(parentWatch);
|
||||
server.close(() => process.exit(0));
|
||||
}
|
||||
}, 1000);
|
||||
parentWatch.unref();
|
||||
}
|
||||
Reference in New Issue
Block a user