diff --git a/packages/vinext/src/shims/server.ts b/packages/vinext/src/shims/server.ts index 44c09fc2..726c79b9 100644 --- a/packages/vinext/src/shims/server.ts +++ b/packages/vinext/src/shims/server.ts @@ -161,6 +161,9 @@ export class NextRequest extends Request { // NextResponse // --------------------------------------------------------------------------- +/** Valid HTTP redirect status codes, matching Next.js's REDIRECTS set. */ +const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]); + export class NextResponse<_Body = unknown> extends Response { private _cookies: ResponseCookies; @@ -192,6 +195,9 @@ export class NextResponse<_Body = unknown> extends Response { */ static redirect(url: string | URL, init?: number | ResponseInit): NextResponse { const status = typeof init === "number" ? init : (init?.status ?? 307); + if (!REDIRECT_STATUSES.has(status)) { + throw new RangeError(`Failed to execute "redirect" on "response": Invalid status code`); + } const destination = typeof url === "string" ? url : url.toString(); const headers = new Headers(typeof init === "object" ? init?.headers : undefined); headers.set("Location", destination); diff --git a/tests/shims.test.ts b/tests/shims.test.ts index 887dfd94..41c8471f 100644 --- a/tests/shims.test.ts +++ b/tests/shims.test.ts @@ -4748,6 +4748,31 @@ describe("NextResponse.redirect() status codes", () => { const res = NextResponse.redirect(url); expect(res.headers.get("Location")).toBe("https://example.com/target"); }); + + it("supports 303 See Other", async () => { + const { NextResponse } = await import("../packages/vinext/src/shims/server.js"); + const res = NextResponse.redirect("https://example.com", 303); + expect(res.status).toBe(303); + }); + + // Ported from Next.js: packages/next/src/server/web/spec-extension/response.ts + // Next.js validates redirect status codes and throws RangeError for invalid ones. + it("throws RangeError for non-redirect status code 200", async () => { + const { NextResponse } = await import("../packages/vinext/src/shims/server.js"); + expect(() => NextResponse.redirect("https://example.com", 200)).toThrow(RangeError); + }); + + it("throws RangeError for non-redirect status code 418", async () => { + const { NextResponse } = await import("../packages/vinext/src/shims/server.js"); + expect(() => NextResponse.redirect("https://example.com", 418)).toThrow(RangeError); + }); + + it("throws RangeError with descriptive message for invalid status", async () => { + const { NextResponse } = await import("../packages/vinext/src/shims/server.js"); + expect(() => NextResponse.redirect("https://example.com", 200)).toThrow( + /Failed to execute "redirect" on "response": Invalid status code/, + ); + }); }); // ---------------------------------------------------------------------------