import { NextResponse } from "next/server"; import { auth } from "@/auth"; import { getInventoryScan } from "@/lib/inventory-scans"; // Streams the scan's photo on demand straight from Telegram's file storage // — see prisma/schema.prisma's InventoryScan.photoFileId comment for why // this app doesn't keep its own copy on disk. Telegram's getFile file_path // is short-lived, so this re-resolves it on every request rather than // caching a URL. export async function GET( request: Request, { params }: { params: { id: string } } ): Promise { const session = await auth(); if (!session) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const scan = await getInventoryScan(params.id); if (!scan || !scan.photo_file_id) { return NextResponse.json({ error: "No photo for this scan" }, { status: 404 }); } const botToken = process.env.BOT_TOKEN; if (!botToken) { return NextResponse.json({ error: "BOT_TOKEN not configured" }, { status: 500 }); } const fileResp = await fetch( `https://api.telegram.org/bot${botToken}/getFile?file_id=${encodeURIComponent(scan.photo_file_id)}` ); const fileJson = await fileResp.json(); if (!fileJson.ok) { return NextResponse.json({ error: "Telegram getFile failed" }, { status: 502 }); } const filePath = fileJson.result.file_path as string; const imageResp = await fetch(`https://api.telegram.org/file/bot${botToken}/${filePath}`); if (!imageResp.ok || !imageResp.body) { return NextResponse.json({ error: "Failed to fetch photo from Telegram" }, { status: 502 }); } // Telegram serves file content as generic application/octet-stream // regardless of the actual file type, which makes browsers download // instead of display it inline — derive the real content type from the // file_path extension instead of trusting imageResp's header. const extension = filePath.split(".").pop()?.toLowerCase(); const contentType = extension === "png" ? "image/png" : extension === "webp" ? "image/webp" : "image/jpeg"; return new NextResponse(imageResp.body, { status: 200, headers: { "Content-Type": contentType, "Content-Disposition": "inline", "Cache-Control": "private, max-age=3600", }, }); }