Files
rednote-tool-studio/app/api/projects/[id]/preview/[[...path]]/route.ts
T
2026-09-17 21:54:33 +08:00

24 lines
1.5 KiB
TypeScript

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<string, string> = { ".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); }
}