From 7bf0984698e43b9aa2dd879f65951318ed410390 Mon Sep 17 00:00:00 2001 From: Maze <167211895+mazeincoding@users.noreply.github.com> Date: Sat, 31 Jan 2026 00:20:04 +0100 Subject: codebase overhaul (#697) --- apps/web/src/app/api/get-upload-url/route.ts | 128 --------------------------- 1 file changed, 128 deletions(-) delete mode 100644 apps/web/src/app/api/get-upload-url/route.ts (limited to 'apps/web/src/app/api/get-upload-url') diff --git a/apps/web/src/app/api/get-upload-url/route.ts b/apps/web/src/app/api/get-upload-url/route.ts deleted file mode 100644 index dc5b7328..00000000 --- a/apps/web/src/app/api/get-upload-url/route.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import { z } from "zod"; -import { AwsClient } from "aws4fetch"; -import { nanoid } from "nanoid"; -import { env } from "@/env"; -import { baseRateLimit } from "@/lib/rate-limit"; -import { isTranscriptionConfigured } from "@/lib/transcription-utils"; - -const uploadRequestSchema = z.object({ - fileExtension: z.enum(["wav", "mp3", "m4a", "flac"], { - errorMap: () => ({ - message: "File extension must be wav, mp3, m4a, or flac", - }), - }), -}); - -const apiResponseSchema = z.object({ - uploadUrl: z.string().url(), - fileName: z.string().min(1), -}); - -export async function POST(request: NextRequest) { - try { - // Rate limiting - const ip = request.headers.get("x-forwarded-for") ?? "anonymous"; - const { success } = await baseRateLimit.limit(ip); - - if (!success) { - return NextResponse.json({ error: "Too many requests" }, { status: 429 }); - } - - // Check transcription configuration - const transcriptionCheck = isTranscriptionConfigured(); - if (!transcriptionCheck.configured) { - console.error( - "Missing environment variables:", - JSON.stringify(transcriptionCheck.missingVars) - ); - - return NextResponse.json( - { - error: "Transcription not configured", - message: `Auto-captions require environment variables: ${transcriptionCheck.missingVars.join(", ")}. Check README for setup instructions.`, - }, - { status: 503 } - ); - } - - // Parse and validate request body - const rawBody = await request.json().catch(() => null); - if (!rawBody) { - return NextResponse.json( - { error: "Invalid JSON in request body" }, - { status: 400 } - ); - } - - const validationResult = uploadRequestSchema.safeParse(rawBody); - if (!validationResult.success) { - return NextResponse.json( - { - error: "Invalid request parameters", - details: validationResult.error.flatten().fieldErrors, - }, - { status: 400 } - ); - } - - const { fileExtension } = validationResult.data; - - // Initialize R2 client - const client = new AwsClient({ - accessKeyId: env.R2_ACCESS_KEY_ID, - secretAccessKey: env.R2_SECRET_ACCESS_KEY, - }); - - // Generate unique filename with timestamp - const timestamp = Date.now(); - const fileName = `audio/${timestamp}-${nanoid()}.${fileExtension}`; - - // Create presigned URL - const url = new URL( - `https://${env.R2_BUCKET_NAME}.${env.CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com/${fileName}` - ); - - url.searchParams.set("X-Amz-Expires", "3600"); // 1 hour expiry - - const signed = await client.sign(new Request(url, { method: "PUT" }), { - aws: { signQuery: true }, - }); - - if (!signed.url) { - throw new Error("Failed to generate presigned URL"); - } - - // Prepare and validate response - const responseData = { - uploadUrl: signed.url, - fileName, - }; - - const responseValidation = apiResponseSchema.safeParse(responseData); - if (!responseValidation.success) { - console.error( - "Invalid API response structure:", - responseValidation.error - ); - return NextResponse.json( - { error: "Internal response formatting error" }, - { status: 500 } - ); - } - - return NextResponse.json(responseValidation.data); - } catch (error) { - console.error("Error generating upload URL:", error); - return NextResponse.json( - { - error: "Failed to generate upload URL", - message: - error instanceof Error - ? error.message - : "An unexpected error occurred", - }, - { status: 500 } - ); - } -} -- cgit v1.3.1