@@ -45,26 +45,24 @@ 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 {
|
||||
// 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
|
||||
if (!stat.isFile()) {
|
||||
|
||||
Reference in New Issue
Block a user