diff --git a/src/app/memories/page.tsx b/src/app/memories/page.tsx index cd0dfd2..5b2cec4 100644 --- a/src/app/memories/page.tsx +++ b/src/app/memories/page.tsx @@ -84,17 +84,26 @@ export default function MemoriesPage() { setUploading(true); try { - // Step 1: Get presigned URL + memoryId + // Step 1: Get key + memoryId from server const initRes = await fetch("/api/upload", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ filename: file.name, contentType: file.type, childId, sizeBytes: file.size }), }); - const { uploadUrl, memoryId, publicUrl, error } = await initRes.json(); + const { key, memoryId, publicUrl, error } = await initRes.json(); if (error) { alert("Error: " + error); return; } - // Step 2: Upload directly to R2 - await fetch(uploadUrl, { method: "PUT", body: file, headers: { "Content-Type": file.type } }); + // Step 2: Upload via server proxy — avoids cross-origin CORS restriction on R2 + const putParams = new URLSearchParams({ key, contentType: file.type }); + const putRes = await fetch(`/api/upload?${putParams}`, { + method: "PUT", + body: file, + headers: { "Content-Type": file.type }, + }); + if (!putRes.ok) { + const e = await putRes.json().catch(() => ({})) as { error?: string }; + throw new Error(e.error ?? `Upload failed (${putRes.status})`); + } // Step 3: Confirm upload → fires thumbnail + vision pipeline await fetch(`/api/memories/${memoryId}/confirm`, { method: "POST" }); @@ -102,7 +111,7 @@ export default function MemoriesPage() { // Optimistic add const optimistic: Memory = { id: memoryId, - key: "", + key, url: publicUrl, thumbnailUrl: null, sizeBytes: file.size,