import { NextRequest, NextResponse } from "next/server"; import { auth } from "@/auth"; import { generateHetznerPresignedUploadUrl } from "@/lib/storage"; import { randomUUID } from "crypto"; export const maxDuration = 10; /** * POST /api/batch-upload/presign * Body: { fileName: string } * * Returns a presigned PUT URL for uploading a high-res file directly from * the browser to Hetzner Object Storage, together with the storage key that * must be passed to POST /api/batch-upload/upload (action=update-highres) to * commit the shot record after the direct upload completes. * * This two-phase approach avoids routing large MOV files through the app * server / reverse proxy, removing any client_max_body_size limits. */ export async function POST(req: NextRequest) { const session = await auth(); if (!session?.user) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } let body: unknown; try { body = await req.json(); } catch { return NextResponse.json({ error: "Invalid JSON" }, { status: 400 }); } const { fileName } = body as { fileName?: unknown }; if (!fileName || typeof fileName !== "string") { return NextResponse.json({ error: "fileName is required" }, { status: 400 }); } const ext = fileName.split(".").pop()?.toLowerCase(); const contentType = ext === "mov" ? "video/quicktime" : ext === "mp4" ? "video/mp4" : "application/octet-stream"; const key = `highres/${randomUUID()}-${fileName}`; try { const presignedUrl = await generateHetznerPresignedUploadUrl(key, contentType); return NextResponse.json({ presignedUrl, key }); } catch (err) { console.error("[batch-upload/presign]", err); return NextResponse.json( { error: "Failed to generate upload URL. Check Hetzner storage configuration." }, { status: 500 } ); } }