Redirect large/non-inline lesson files to CDN instead of proxying

ZIP/DOCX etc. download natively — no need to force attachment; and the
157 MB Second Brain Vault archive must stream from Caddy with Range,
not through the app. Proxy attachment stays for small inline types (PDF/images).
This commit is contained in:
2026-07-09 11:35:45 +05:00
parent 98cc023709
commit 5d94949810
@@ -29,6 +29,17 @@ function extFromUrl(url: string): string {
return dot >= 0 ? clean.slice(dot + 1).toLowerCase() : ""; return dot >= 0 ? clean.slice(dot + 1).toLowerCase() : "";
} }
// Types a browser renders inline (so the direct link "opens in a tab" instead of
// downloading). Only these need proxying with a forced attachment header. ZIP,
// DOCX, etc. already download natively → redirect straight to the CDN.
const INLINE_EXT = new Set([
"pdf", "png", "jpg", "jpeg", "webp", "gif", "svg", "avif",
"txt", "htm", "html", "mp4", "mov", "webm", "mp3", "wav",
]);
// Above this, don't proxy through the app — redirect so the file streams from
// the CDN/Caddy with Range support (e.g. the 157 MB Second Brain Vault archive).
const PROXY_MAX_BYTES = 50 * 1024 * 1024;
export async function GET( export async function GET(
_req: NextRequest, _req: NextRequest,
{ params }: { params: Promise<{ id: string }> } { params }: { params: Promise<{ id: string }> }
@@ -59,12 +70,26 @@ export async function GET(
} }
} }
const ext = extFromUrl(file.url);
// Non-inline types download natively — send the browser straight to the CDN
// (native download, Range/resume, no app load). Auth is already enforced above.
if (!INLINE_EXT.has(ext)) {
return NextResponse.redirect(file.url, 302);
}
const upstream = await fetch(file.url); const upstream = await fetch(file.url);
if (!upstream.ok || !upstream.body) { if (!upstream.ok || !upstream.body) {
return NextResponse.json({ error: "file_unavailable" }, { status: 502 }); return NextResponse.json({ error: "file_unavailable" }, { status: 502 });
} }
const ext = extFromUrl(file.url); // Guard: a very large inline file still shouldn't stream through the app.
const upstreamLen = Number(upstream.headers.get("content-length") ?? "0");
if (upstreamLen > PROXY_MAX_BYTES) {
await upstream.body.cancel();
return NextResponse.redirect(file.url, 302);
}
const contentType = const contentType =
upstream.headers.get("content-type") ?? upstream.headers.get("content-type") ??
CONTENT_TYPES[ext] ?? CONTENT_TYPES[ext] ??