diff --git a/app/api/files/[...key]/route.ts b/app/api/files/[...key]/route.ts index de5d2ec..8f9e69d 100644 --- a/app/api/files/[...key]/route.ts +++ b/app/api/files/[...key]/route.ts @@ -45,25 +45,23 @@ export async function GET( return new NextResponse("Forbidden", { status: 403 }); } - // ── Hetzner first, local disk fallback ─────────────────────────────────── - // Check object storage first (all new uploads go there directly; migrated - // files live there too). Each try/catch is isolated so a Hetzner error - // never prevents local files from being served. - try { - if (await hetznerKeyExists(relativePath)) { - const hetznerUrl = await generateHetznerStreamUrl(relativePath, 3600); - return NextResponse.redirect(hetznerUrl, 302); - } - } catch { - // Hetzner unavailable or misconfigured — fall through to local disk - } - - // Local disk fallback (unmigrated files, or if Hetzner is unreachable) + // ── Local disk first, Hetzner fallback ─────────────────────────────────── + // Serve from local disk if the file exists there (covers unmigrated files). + // If not found locally, redirect to Hetzner object storage. + // Note: "Hetzner first" was attempted but caused 400s from Hetzner on + // presigned URLs — likely a bucket policy/CORS issue to investigate + // separately before re-enabling that path. let stat: fs.Stats; try { stat = fs.statSync(filePath); } catch { - return new NextResponse("Not found", { status: 404 }); + // Not on local disk — try Hetzner + try { + const hetznerUrl = await generateHetznerStreamUrl(relativePath, 3600); + return NextResponse.redirect(hetznerUrl, 302); + } catch { + return new NextResponse("Not found", { status: 404 }); + } } // Guard against directory traversal that resolves to a directory