import * as z from "zod"; import { getAdminSession } from "@/lib/auth/server"; import { getMediaVisibility, getReadyMedia } from "@/lib/media/repository"; import { getMediaStorage } from "@/lib/media/storage"; import { parseByteRange } from "@/lib/media/validation"; async function serveMedia( request: Request, context: { params: Promise<{ id: string }> }, headOnly: boolean, ) { const { id } = await context.params; if (!z.string().uuid().safeParse(id).success) { return new Response("Not found", { status: 404 }); } const record = await getReadyMedia(id); if (!record) return new Response("Not found", { status: 404 }); const visibility = await getMediaVisibility(id); if (!visibility.public && !(await getAdminSession())) { return new Response("Not found", { status: 404 }); } const file = (await getMediaStorage()).file(record.objectKey); let stat: Awaited>; try { stat = await file.stat(); } catch { return new Response("Not found", { status: 404 }); } const rangeHeader = request.headers.get("range"); const range = parseByteRange(rangeHeader, stat.size); if (rangeHeader && !range) { return new Response(null, { status: 416, headers: { "Content-Range": `bytes */${stat.size}` }, }); } const headers = new Headers({ "Accept-Ranges": "bytes", "Content-Type": record.mimeType, "Content-Disposition": `inline; filename*=UTF-8''${encodeURIComponent(record.fileName)}`, "Cache-Control": visibility.public ? "public, max-age=60, must-revalidate" : "private, no-store", ETag: stat.etag, "X-Content-Type-Options": "nosniff", }); if (range) { const length = range.end - range.start + 1; headers.set("Content-Length", String(length)); headers.set("Content-Range", `bytes ${range.start}-${range.end}/${stat.size}`); return new Response( headOnly ? null : file.slice(range.start, range.end + 1).stream(), { status: 206, headers }, ); } headers.set("Content-Length", String(stat.size)); return new Response(headOnly ? null : file.stream(), { status: 200, headers }); } export async function GET( request: Request, context: { params: Promise<{ id: string }> }, ) { return serveMedia(request, context, false); } export async function HEAD( request: Request, context: { params: Promise<{ id: string }> }, ) { return serveMedia(request, context, true); }