summaryrefslogtreecommitdiff
path: root/apps/web/src/app/api/get-upload-url
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/app/api/get-upload-url')
-rw-r--r--apps/web/src/app/api/get-upload-url/route.ts128
1 files changed, 0 insertions, 128 deletions
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 }
- );
- }
-}