import { stat } from "fs/promises"; import { createReadStream } from "fs"; import path from "path"; export const dynamic = "force-dynamic"; export const revalidate = 0; const ROOT = process.env.FILES_ROOT || "/app/files"; function safeJoin(root: string, p: string) { const raw = path.normalize("/" + (p || "/")); const abs = path.resolve(root, "." + raw); if (!abs.startsWith(path.resolve(root))) throw new Error("Invalid path"); return abs; } export async function GET(req: Request) { try { const { searchParams } = new URL(req.url); const p = searchParams.get("path"); if (!p) return new Response(JSON.stringify({ error: "Missing path" }), { status: 400 }); const abs = safeJoin(ROOT, p); const s = await stat(abs); if (s.isDirectory()) { return new Response(JSON.stringify({ error: "Is a directory" }), { status: 400 }); } const stream = createReadStream(abs); const fileName = path.basename(abs); return new Response(stream as any, { headers: { "Content-Type": "application/octet-stream", "Content-Length": String(s.size), "Content-Disposition": `attachment; filename*=UTF-8''${encodeURIComponent(fileName)}`, "Cache-Control": "no-store", } }); } catch (e: any) { const msg = e?.message || "Not found"; const code = msg === "Invalid path" ? 400 : 404; return new Response(JSON.stringify({ error: msg }), { status: code, headers: { "Cache-Control": "no-store" } }); } }