import { NextResponse } from "next/server"; import fs from "node:fs/promises"; import path from "node:path"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; const BASE = "/app/files"; function safeJoin(base: string, reqPath: string) { const rel = reqPath.startsWith("/") ? reqPath : `/${reqPath}`; const full = path.resolve(base, "." + rel); if (!full.startsWith(base)) throw new Error("Outside base"); return full; } const CONTENT_MAP: Record = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml", ".txt": "text/plain; charset=utf-8", ".json": "application/json; charset=utf-8", ".pdf": "application/pdf", }; export async function GET(req: Request) { try { const url = new URL(req.url); const reqPath = url.searchParams.get("path"); if (!reqPath) return NextResponse.json({ error: "Missing path" }, { status: 400 }); const full = safeJoin(BASE, reqPath); const stat = await fs.stat(full); if (!stat.isFile()) return NextResponse.json({ error: "Not a file" }, { status: 400 }); const data = await fs.readFile(full); const ext = path.extname(full).toLowerCase(); const type = CONTENT_MAP[ext] ?? "application/octet-stream"; return new NextResponse(data, { status: 200, headers: { "Content-Type": type, "Cache-Control": "public, max-age=300" }, }); } catch (e: any) { return NextResponse.json({ error: e?.message ?? "Unknown" }, { status: 400 }); } }