import { readFile } from "node:fs/promises"; import path from "node:path"; import { PUBLIC_DIR, REPO_DIR, safeJoin } from "./paths"; /* Read-only file serving from the portfolio checkout, so the preview iframe * can load the site's real stylesheets and the post's images. */ const TYPES: Record = { ".css": "text/css; charset=utf-8", ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml", ".ico": "image/x-icon", ".mp4": "video/mp4", }; /** Stylesheets the preview may load, keyed by their /site/... path. */ const SITE_CSS = new Set(["app/globals.css", "styles/markdown-container.css", "styles/blog.css"]); async function send(file: string): Promise { const type = TYPES[path.extname(file).toLowerCase()]; if (!type) return new Response("not found", { status: 404 }); try { const body = await readFile(file); return new Response(new Uint8Array(body), { headers: { "content-type": type, "cache-control": "no-cache" }, }); } catch { return new Response("not found", { status: 404 }); } } /** /site/ -> repo file; /site/ -> repo public/. */ export function serveSitePath(segments: string[]): Promise { const rel = segments.join("/"); if (SITE_CSS.has(rel)) return send(path.join(REPO_DIR, rel)); return send(safeJoin(PUBLIC_DIR, ...segments)); } export function servePublic(segments: string[]): Promise { return send(safeJoin(PUBLIC_DIR, ...segments)); }