export default { async fetch(request, env) { const url = new URL(request.url); let pathname = url.pathname.replace(/\/{2,}/g, "/"); // Serve admin UI at root / if (pathname === "/") { return serveFromKV(env, "admin", "index.html"); } // Normalize /site -> /site/ if (!pathname.endsWith("/") && pathname.split("/").length === 2) { const redirectUrl = new URL(url); redirectUrl.pathname = pathname + "/"; return Response.redirect(redirectUrl.toString(), 301); } // Split path const parts = pathname.replace(/^\/+/, "").split("/"); if (!parts[0]) { return new Response("Not Found", { status: 404 }); } const site = parts[0]; const filePath = parts.length === 1 || parts[1] === "" ? "index.html" : parts.slice(1).join("/"); return serveFromKV(env, site, filePath); }, }; async function serveFromKV(env, site, filePath) { const key = `site:${site}:${filePath}`; const content = await env.PAGES_KV.get(key, { type: "arrayBuffer", }); if (!content) { return new Response("Not Found", { status: 404 }); } return new Response(content, { headers: { "Content-Type": contentType(filePath), "Cache-Control": "public, max-age=300", }, }); } function contentType(path) { if (path.endsWith(".html")) return "text/html; charset=utf-8"; if (path.endsWith(".css")) return "text/css; charset=utf-8"; if (path.endsWith(".js")) return "application/javascript; charset=utf-8"; if (path.endsWith(".json")) return "application/json; charset=utf-8"; if (path.endsWith(".png")) return "image/png"; if (path.endsWith(".jpg") || path.endsWith(".jpeg")) return "image/jpeg"; if (path.endsWith(".svg")) return "image/svg+xml"; if (path.endsWith(".ico")) return "image/x-icon"; if (path.endsWith(".woff")) return "font/woff"; if (path.endsWith(".woff2")) return "font/woff2"; return "application/octet-stream"; }