SPB Git forge

spb/voyage2026

Public
1commits 1branches 0releases
32.0 KBsize
maindefault branch
19 days agolast push
HTML 95.5% JavaScript 4.5%
1.7 KB · 53 lines javascript
Raw Blame History
1// Zero-dep static server for the voyage2026 itinerary.2// Usage: node server.mjs [port]  — serves this directory, / -> index, /healthz -> ok3import { createServer } from "node:http";4import { readFile } from "node:fs/promises";5import { join, extname, normalize } from "node:path";6import { fileURLToPath } from "node:url";78const ROOT = fileURLToPath(new URL(".", import.meta.url));9const PORT = Number(process.argv[2] || process.env.PORT || 8060);10const INDEX = "itineraire-toronto-2026.html";1112const MIME = {13  ".html": "text/html; charset=utf-8",14  ".css": "text/css; charset=utf-8",15  ".js": "text/javascript; charset=utf-8",16  ".json": "application/json",17  ".png": "image/png",18  ".jpg": "image/jpeg",19  ".jpeg": "image/jpeg",20  ".webp": "image/webp",21  ".svg": "image/svg+xml",22  ".ico": "image/x-icon",23  ".pdf": "application/pdf",24};2526createServer(async (req, res) => {27  const url = new URL(req.url, "http://x");28  if (url.pathname === "/healthz") {29    res.writeHead(200, { "content-type": "text/plain" });30    return res.end("ok");31  }32  let path = decodeURIComponent(url.pathname);33  if (path === "/" || path === "/index.html") path = "/" + INDEX;34  const file = normalize(join(ROOT, path));35  if (!file.startsWith(ROOT)) {36    res.writeHead(403);37    return res.end("forbidden");38  }39  try {40    const body = await readFile(file);41    res.writeHead(200, {42      "content-type": MIME[extname(file).toLowerCase()] || "application/octet-stream",43      "cache-control": "public, max-age=300",44    });45    res.end(body);46  } catch {47    res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });48    res.end("404 — page introuvable");49  }50}).listen(PORT, "0.0.0.0", () => {51  console.log(`voyage2026 static server on http://0.0.0.0:${PORT} (root: ${ROOT})`);52});53