import { createReadStream, existsSync, readFileSync, statSync } from "node:fs"; import { createServer } from "node:http"; import { extname, join, relative, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const root = resolve(fileURLToPath(new URL(".", import.meta.url)), "website"); const publicRoot = join(root, "public"); function loadEnvFile(file = ".env") { if (!existsSync(file)) return; const lines = readFileSync(file, "utf8").split(/\r?\n/); lines.forEach((line) => { const trimmed = line.trim(); if (!trimmed || trimmed.startsWith("#")) return; const separatorIndex = trimmed.indexOf("="); if (separatorIndex < 1) return; const key = trimmed.slice(0, separatorIndex).trim(); const value = trimmed.slice(separatorIndex + 1).trim().replace(/^["']|["']$/g, ""); if (!process.env[key]) process.env[key] = value; }); } loadEnvFile(); const port = Number(process.env.PORT || 5173); const types = { ".html": "text/html; charset=utf-8", ".css": "text/css; charset=utf-8", ".js": "text/javascript; charset=utf-8", ".json": "application/json; charset=utf-8", ".svg": "image/svg+xml", ".ico": "image/x-icon", ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".webp": "image/webp" }; function isInsideRoot(parent, file) { const relativePath = relative(parent, file); return Boolean(relativePath) && !relativePath.startsWith("..") && !relativePath.startsWith("/"); } function fileIfReadable(file) { return isInsideRoot(root, file) && existsSync(file) && statSync(file).isFile() ? file : null; } function resolvePath(url) { let requested; try { requested = decodeURIComponent(new URL(url, "http://localhost").pathname); } catch { return null; } const candidate = fileIfReadable(resolve(root, `.${requested}`)); if (candidate) return candidate; const publicCandidate = fileIfReadable(resolve(publicRoot, `.${requested}`)); if (publicCandidate && isInsideRoot(publicRoot, publicCandidate)) return publicCandidate; return join(publicRoot, "index.html"); } const server = createServer((req, res) => { const file = resolvePath(req.url || "/"); if (!file || !existsSync(file)) { res.writeHead(404); res.end("Not found"); return; } res.writeHead(200, { "Content-Type": types[extname(file)] || "application/octet-stream", "Cache-Control": "no-store" }); createReadStream(file).pipe(res); }); server.on("error", (error) => { if (error.code === "EADDRINUSE") { console.error(`Port ${port} is already in use. Set PORT to another value.`); process.exit(1); } console.error(error); process.exit(1); }); server.listen(port, () => { console.log(`Sokko G dev server running at http://localhost:${port}`); });