import { z } from "zod"; import { getDb } from "@tline/db"; import { presignGetObjectUrl } from "@tline/minio"; export const runtime = "nodejs"; const paramsSchema = z.object({ id: z.string().uuid() }); const variantSchema = z.enum(["original", "thumb_small", "thumb_med", "poster"]); export async function GET( request: Request, context: { params: Promise<{ id: string }> } ): Promise { const rawParams = await context.params; const paramsParsed = paramsSchema.safeParse(rawParams); if (!paramsParsed.success) { return Response.json( { error: "invalid_params", issues: paramsParsed.error.issues }, { status: 400 }, ); } const params = paramsParsed.data; const url = new URL(request.url); const variantParsed = variantSchema.safeParse(url.searchParams.get("variant") ?? "original"); if (!variantParsed.success) { return Response.json( { error: "invalid_query", issues: variantParsed.error.issues }, { status: 400 }, ); } const variant = variantParsed.data; const db = getDb(); const rows = await db< { bucket: string; active_key: string; thumb_small_key: string | null; thumb_med_key: string | null; poster_key: string | null; mime_type: string; }[] >` select bucket, active_key, thumb_small_key, thumb_med_key, poster_key, mime_type from assets where id = ${params.id} limit 1 `; const asset = rows[0]; if (!asset) { return Response.json({ error: "not_found" }, { status: 404 }); } const key = variant === "original" ? asset.active_key : variant === "thumb_small" ? asset.thumb_small_key : variant === "thumb_med" ? asset.thumb_med_key : asset.poster_key; if (!key) { return Response.json( { error: "variant_not_available", variant }, { status: 404 } ); } // Hint the browser; especially helpful for Range playback. const responseContentType = variant === "original" ? asset.mime_type : "image/jpeg"; const responseContentDisposition = variant === "original" && asset.mime_type.startsWith("video/") ? "inline" : undefined; const signed = await presignGetObjectUrl({ bucket: asset.bucket, key, responseContentType, responseContentDisposition, }); return Response.json(signed, { headers: { "Cache-Control": "no-store" } }); }