import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; import { BUCKETS, DATABASE_ID, TABLES, type Attachment } from "@/lib/appwrite/schema"; import { createAdminClient } from "@/lib/appwrite/server"; import { requireTenant } from "@/lib/appwrite/tenant-guard"; export async function GET( _request: NextRequest, { params }: { params: Promise<{ attachmentId: string }> }, ) { const { attachmentId } = await params; let ctx; try { ctx = await requireTenant(); } catch { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const { tablesDB } = createAdminClient(); let attachment: Attachment; try { attachment = (await tablesDB.getRow( DATABASE_ID, TABLES.attachments, attachmentId, )) as unknown as Attachment; } catch { return NextResponse.json({ error: "Not found" }, { status: 404 }); } if (attachment.tenantId !== ctx.tenantId) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } const endpoint = (process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT ?? "").replace(/\/$/, ""); const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID ?? ""; const apiKey = process.env.APPWRITE_API_KEY ?? ""; const fileUrl = `${endpoint}/storage/buckets/${BUCKETS.entityAttachments}/files/${attachment.fileId}/download`; let upstream: Response; try { upstream = await fetch(fileUrl, { headers: { "X-Appwrite-Project": projectId, "X-Appwrite-Key": apiKey, }, }); } catch { return NextResponse.json({ error: "Storage unavailable" }, { status: 502 }); } if (!upstream.ok) { return NextResponse.json({ error: "File not found" }, { status: 404 }); } const contentType = upstream.headers.get("Content-Type") || "application/octet-stream"; const encodedName = encodeURIComponent(attachment.name); return new NextResponse(upstream.body, { headers: { "Content-Type": contentType, "Content-Disposition": `attachment; filename*=UTF-8''${encodedName}`, "Cache-Control": "private, no-store", }, }); }