import fs from "node:fs/promises"; import path from "node:path"; import { NextResponse } from "next/server"; import { buildProject } from "../../../../../../lib/build"; import { errorResponse } from "../../../../../../lib/http"; import { projectRoot, touchProject } from "../../../../../../lib/storage"; export const runtime = "nodejs"; const CONTENT_TYPES: Record = { ".html": "text/html; charset=utf-8", ".css": "text/css; charset=utf-8", ".js": "text/javascript; charset=utf-8", ".json": "application/json", ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml", ".woff": "font/woff", ".woff2": "font/woff2" }; export async function GET(_: Request, context: { params: Promise<{ id: string; path?: string[] }> }) { try { const params = await context.params; await touchProject(params.id); const segments = params.path?.length ? params.path : ["index.html"]; const dist = path.join(projectRoot(params.id), "dist"); let target = path.resolve(dist, ...segments); if (!target.startsWith(`${dist}${path.sep}`)) throw new Error("Invalid preview path"); try { await fs.access(target); } catch { await buildProject(params.id); target = path.resolve(dist, ...segments); } return new NextResponse(await fs.readFile(target), { headers: { "Content-Type": CONTENT_TYPES[path.extname(target)] || "application/octet-stream", "Cache-Control": "no-store" } }); } catch (error) { return errorResponse(error); } }