import { expect, test } from "bun:test"; import { defaultGatewayHostname, forwardAuthFailure, forwardAuthHeaders, gatewayProxyHeaders, gatewayRestartDelay, } from "../src/gateway.ts"; test("gateway uses platform-safe hostname defaults", () => { expect(defaultGatewayHostname("development")).toBe("127.0.0.1"); expect(defaultGatewayHostname("production")).toBe("0.0.0.0"); }); test("gateway disables compression for its internal proxy hop", () => { const request = new Request("http://localhost:3000/path", { headers: { host: "web.localhost:3000", "accept-encoding": "gzip, deflate" }, }); const headers = gatewayProxyHeaders(request, new URL(request.url), "127.0.0.1", true); expect(headers.get("accept-encoding")).toBe("identity"); expect(headers.get("x-forwarded-host")).toBe("web.localhost:3000"); expect(headers.get("x-forwarded-proto")).toBe("http"); expect(headers.get("x-forwarded-for")).toBe("127.0.0.1"); }); test("forward auth preserves intentional verifier redirects", () => { const redirected = forwardAuthFailure( new Response(null, { status: 302, headers: { location: "/login?returnTo=%2Fadmin" } }), "http://sso.localhost:3000/api/verify", ); const denied = forwardAuthFailure(new Response(null, { status: 401 }), "http://sso.localhost"); expect(redirected.status).toBe(302); expect(redirected.headers.get("location")).toBe( "http://sso.localhost:3000/login?returnTo=%2Fadmin", ); expect(denied.status).toBe(401); expect(denied.headers.has("location")).toBe(false); }); test("forward auth describes the original gateway request", () => { const headers = forwardAuthHeaders( new Request("https://admin.example.test/settings?tab=security", { headers: { host: "admin.example.test", cookie: "session=abc", authorization: "Bearer token", }, }), ); expect(headers.get("x-forwarded-host")).toBe("admin.example.test"); expect(headers.get("x-forwarded-proto")).toBe("https"); expect(headers.get("x-original-method")).toBe("GET"); expect(headers.get("x-original-uri")).toBe("/settings?tab=security"); expect(headers.get("cookie")).toBe("session=abc"); expect(headers.get("authorization")).toBe("Bearer token"); }); test("gateway respawns development apps after an HMR restart exit", () => { expect(gatewayRestartDelay("development", 97, null)).toBe(0); expect(gatewayRestartDelay("development", 1, null)).toBe(1200); expect(gatewayRestartDelay("development", 0, null)).toBeNull(); expect(gatewayRestartDelay("development", 97, "SIGTERM")).toBeNull(); expect(gatewayRestartDelay("production", 97, null)).toBeNull(); });