From 42fc143ee3e65f367bc715c50e444a6afdca2428 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Tue, 6 Oct 2026 01:09:28 +0000 Subject: [PATCH] fix: absolute redirect to /invite-only (relative one was a 500 in production) Next.js answers "TypeError: Invalid URL" (500) when the proxy returns a relative Location, so / and /pricing failed for everyone who is not an admin after #261. Build it from the request URL, as the legal-mode /pricing redirect does. The test now pins the absolute URL. Co-Authored-By: Claude Opus 5.5 --- src/lib/site-offline.test.ts | 3 ++- src/lib/site-offline.ts | 6 ++++-- src/proxy.ts | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lib/site-offline.test.ts b/src/lib/site-offline.test.ts index 90783639..164c2a4a 100644 --- a/src/lib/site-offline.test.ts +++ b/src/lib/site-offline.test.ts @@ -15,7 +15,8 @@ describe('bittorrented.com offline, invite only', () => { for (const path of ['/', '/search?q=x', '/dht', '/torrents/abc', '/pricing', '/account']) { const res = await get(path); expect(res.status).toBe(307); - expect(res.headers.get('location')).toMatch(/\/invite-only$/); + // Absolute, or Next.js answers 500 "Invalid URL" in production. + expect(res.headers.get('location')).toBe('https://bittorrented.com/invite-only'); } }); diff --git a/src/lib/site-offline.ts b/src/lib/site-offline.ts index deb0f18d..fbbd338f 100644 --- a/src/lib/site-offline.ts +++ b/src/lib/site-offline.ts @@ -38,7 +38,7 @@ export function openWhileInviteOnly(pathname: string): boolean { * Pages go to the invite-only screen; the API answers 503 so clients and search * engines treat it as temporary. */ -export function offlineResponse(pathname: string): Response { +export function offlineResponse(pathname: string, requestUrl: string | URL): Response { const headers = { 'cache-control': 'no-store' }; if (pathname.startsWith('/api/')) { return Response.json( @@ -46,5 +46,7 @@ export function offlineResponse(pathname: string): Response { { status: 503, headers: { ...headers, 'retry-after': '86400' } } ); } - return new Response(null, { status: 307, headers: { ...headers, location: INVITE_ONLY_PAGE } }); + // Absolute: Next.js answers 500 "Invalid URL" for a relative Location from the proxy. + const location = new URL(INVITE_ONLY_PAGE, requestUrl).toString(); + return new Response(null, { status: 307, headers: { ...headers, location } }); } diff --git a/src/proxy.ts b/src/proxy.ts index b8459f3f..d01b8a9f 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -556,7 +556,7 @@ export async function proxy(request: NextRequest): Promise { !openWhileInviteOnly(request.nextUrl.pathname) && !(await isAdmin()) ) { - return asNext(offlineResponse(request.nextUrl.pathname)); + return asNext(offlineResponse(request.nextUrl.pathname, request.url)); } // --- 0b. Legal mode: only reviewed features are served (see src/lib/legal-mode.ts) ---