From bdd2d3967bb0416efe13c12a4102654975705360 Mon Sep 17 00:00:00 2001 From: Mannu Date: Sun, 10 May 2026 14:41:18 +0530 Subject: [PATCH] Clean up upload API --- src/app/api/upload/route.ts | 53 ++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/app/api/upload/route.ts b/src/app/api/upload/route.ts index f71af15..95fbacc 100644 --- a/src/app/api/upload/route.ts +++ b/src/app/api/upload/route.ts @@ -1,4 +1,4 @@ -import { S3Client, PutObjectCommand, ListObjectsV2Command, GetObjectCommand } from "@aws-sdk/client-s3"; +import { S3Client, PutObjectCommand, ListObjectsV2Command, ListBucketsCommand } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import { NextRequest, NextResponse } from "next/server"; @@ -8,24 +8,22 @@ function getR2() { const secretKey = process.env.R2_SECRET_ACCESS_KEY; const bucket = process.env.R2_BUCKET_NAME; - // Debug: log what's available - console.log("R2 envs:", { accountId: !!accountId, accessKeyId: !!accessKeyId, secretKey: !!secretKey, bucket: !!bucket }); - if (!accountId || !accessKeyId || !secretKey || !bucket) { - throw new Error(`Missing R2 config: accountId=${!!accountId}, accessKeyId=${!!accessKeyId}, secretKey=${!!secretKey}, bucket=${!!bucket}`); + throw new Error(`Missing R2 config: ${!!accountId} ${!!accessKeyId} ${!!secretKey} ${!!bucket}`); } - // Use public development URL (from R2 bucket settings) - const pubBaseUrl = `https://pub-37a76fd657c94d1dbc521a109c087a11.r2.dev/tia`; + // S3 API endpoint includes bucket name: https://.r2.cloudflarestorage.com/ + const endpoint = `https://${accountId}.r2.cloudflarestorage.com/${bucket}`; return { client: new S3Client({ region: "auto", - endpoint: `https://${accountId}.r2.cloudflarestorage.com/tia`, + endpoint, credentials: { accessKeyId, secretAccessKey: secretKey }, }), bucket, - baseUrl: pubBaseUrl, + // Public URL uses pub- subdomain format + baseUrl: `https://pub-37a76fd657c94d1dbc521a109c087a11.r2.dev/tia`, }; } @@ -33,23 +31,23 @@ function getR2() { export async function GET(req: NextRequest) { try { const { client, bucket, baseUrl } = getR2(); - const { searchParams } = new URL(req.url); - const prefix = searchParams.get("childId") || "default"; + const childId = req.nextUrl.searchParams.get("childId") || "default"; + + // List all memories for this child + const command = new ListObjectsV2Command({ + Bucket: bucket, + Prefix: `memories/${childId}`, + MaxKeys: 50 + }); - // List all objects with memories/ prefix - const command = new ListObjectsV2Command({ Bucket: bucket, Prefix: "memories/", MaxKeys: 50 }); const res = await client.send(command); - if (!res.Contents || res.Contents.length === 0) { - return NextResponse.json({ memories: [], debug: "no files found" }); - } - - const objects = res.Contents.map((obj) => ({ + const objects = (res.Contents || []).map((obj) => ({ key: obj.Key, url: `${baseUrl}/${obj.Key}`, size: obj.Size, lastModified: obj.LastModified?.toISOString(), - })).sort((a, b) => new Date(b.lastModified!).getTime() - new Date(a.lastModified!).getTime()); + })); return NextResponse.json({ memories: objects }); } catch (error) { @@ -58,7 +56,7 @@ export async function GET(req: NextRequest) { } } -// POST: Upload (proxy through server to avoid CORS) +// POST: Get upload URL export async function POST(req: NextRequest) { let body; try { @@ -76,19 +74,15 @@ export async function POST(req: NextRequest) { const { client, bucket, baseUrl } = getR2(); const ext = filename.split(".").pop() || "jpg"; - const key = `memories/${childId || "default"}/${Date.now()}-${Math.random().toString(36).slice(2)}.${ext}`; + const key = `memories/${childId || "default"}/${Date.now()}-${Math.random().toString(36).slice(2, 8)}.${ext}`; - // Instead of presigned URL, we're using PUT to our own server - // The frontend willPOST the file here directly const command = new PutObjectCommand({ Bucket: bucket, Key: key, ContentType: contentType, }); - // Generate short-lived presigned URL that bypasses CORS issues - // R2 needs proper signing - let's use direct put with our server as proxy - const url = await getSignedUrl(client, command, { expiresIn: 3600 }); // 1 hour + const url = await getSignedUrl(client, command, { expiresIn: 3600 }); return NextResponse.json({ uploadUrl: url, @@ -101,13 +95,12 @@ export async function POST(req: NextRequest) { } } -// PUT: Direct upload from file content +// PUT: Direct upload export async function PUT(req: NextRequest) { try { const { client, bucket, baseUrl } = getR2(); - const { searchParams } = new URL(req.url); - const key = searchParams.get("key"); - const contentType = searchParams.get("contentType") || "image/jpeg"; + const key = req.nextUrl.searchParams.get("key"); + const contentType = req.nextUrl.searchParams.get("contentType") || "image/jpeg"; if (!key) { return NextResponse.json({ error: "Missing key" }, { status: 400 });