import 'server-only' import { fileId, fileRepository } from '@/entities/file' import { blob, db } from '@/shared/api' import { currentVisitor } from '@/shared/lib/visitor-session' function notFound(): Response { return new Response('not found', { status: 404 }) } /** * The bytes of one attachment, for the visitor who attached it. The platform's * blob URL needs the deployment token, which the browser does not have, so the * app downloads server-side and streams the bytes back. Anything that is not * the visitor's own attachment answers 404, never 403. */ export async function downloadAttachment(id: string): Promise { const parsed = fileId.safeParse(id) if (!parsed.success) return notFound() const visitor = await currentVisitor() if (!visitor) return notFound() const file = await fileRepository(db()).get(parsed.data, visitor) if (!file) return notFound() const upstream = await blob().download(file.url) if (!upstream.body) return notFound() return new Response(upstream.body, { headers: { 'content-type': file.contentType, // RFC 5987: the name is percent-encoded, so quotes and CR/LF cannot inject. 'content-disposition': `attachment; filename*=UTF-8''${encodeURIComponent(file.name)}`, }, }) } /** `GET /files/`: the route handler the app router re-exports. */ export async function GET(_request: Request, context: { params: Promise<{ id: string }> }): Promise { return downloadAttachment((await context.params).id) }