import { NextRequest, NextResponse } from "next/server" import { logger } from "@/lib/logger" import { readFile } from "fs/promises" import { join } from "path" import { existsSync } from "fs" export async function GET( request: NextRequest, { params }: { params: Promise<{ filename: string }> } ) { let filename: string | undefined try { filename = (await params).filename // Sanitize filename - only allow alphanumeric, dots, hyphens if (!/^[a-zA-Z0-9._-]+$/.test(filename)) { return NextResponse.json({ error: "Invalid filename" }, { status: 400 }) } // Get the uploads directory const uploadsDir = join(process.cwd(), "public", "uploads") const filepath = join(uploadsDir, filename) // Security: ensure file is within uploads directory (prevent path traversal) if (!filepath.startsWith(uploadsDir)) { return NextResponse.json({ error: "Invalid path" }, { status: 400 }) } // Check if file exists if (!existsSync(filepath)) { logger.warn("File not found", { filepath, filename, cwd: process.cwd(), }) return NextResponse.json({ error: "File not found" }, { status: 404 }) } // Read and serve the file const fileBuffer = await readFile(filepath) // Determine content type from extension const ext = filename.split(".").pop()?.toLowerCase() const contentType = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "png" ? "image/png" : ext === "gif" ? "image/gif" : ext === "webp" ? "image/webp" : "application/octet-stream" return new NextResponse(fileBuffer, { headers: { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable", }, }) } catch (error) { logger.error("Error serving file", { filename: filename || "unknown", error: error instanceof Error ? error : new Error(String(error)), }) return NextResponse.json( { error: "Internal server error" }, { status: 500 } ) } }