import { readFile, stat } from "fs/promises"; import path from "path"; import { auth } from "@/lib/auth"; const PIPELINE_ROOT = process.env.PIPELINE_ROOT || path.join(process.cwd(), "pipeline"); const CONTENT_TYPES: Record = { ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".mp4": "video/mp4", ".webm": "video/webm", ".html": "text/html", ".json": "application/json", ".md": "text/markdown", ".txt": "text/plain", ".css": "text/css", ".js": "text/javascript", ".svg": "image/svg+xml", }; export async function GET( request: Request, { params }: { params: Promise<{ path: string[] }> } ) { const session = await auth(); if (!session) { return new Response("Unauthorized", { status: 401 }); } const { path: segments } = await params; const filePath = path.join(PIPELINE_ROOT, ...segments); // Security: prevent path traversal const resolved = path.resolve(filePath); if (!resolved.startsWith(path.resolve(PIPELINE_ROOT))) { return new Response("Forbidden", { status: 403 }); } try { const fileStat = await stat(resolved); const ext = path.extname(resolved).toLowerCase(); const contentType = CONTENT_TYPES[ext] || "application/octet-stream"; const fileSize = fileStat.size; // Handle range requests (needed for video seeking/thumbnails) const range = request.headers.get("range"); if (range) { const match = range.match(/bytes=(\d+)-(\d*)/); if (match) { const start = parseInt(match[1], 10); const end = match[2] ? parseInt(match[2], 10) : fileSize - 1; const buffer = await readFile(resolved); const chunk = buffer.subarray(start, end + 1); return new Response(chunk, { status: 206, headers: { "Content-Type": contentType, "Content-Range": `bytes ${start}-${end}/${fileSize}`, "Content-Length": String(chunk.length), "Accept-Ranges": "bytes", "Cache-Control": "no-cache", }, }); } } const buffer = await readFile(resolved); return new Response(buffer, { headers: { "Content-Type": contentType, "Content-Length": String(fileSize), "Accept-Ranges": "bytes", "Cache-Control": "no-cache", }, }); } catch { return new Response("Not found", { status: 404 }); } }