diff --git a/packages/vinext/src/server/app-page-response.ts b/packages/vinext/src/server/app-page-response.ts index 99062688c..baa24b906 100644 --- a/packages/vinext/src/server/app-page-response.ts +++ b/packages/vinext/src/server/app-page-response.ts @@ -223,6 +223,11 @@ export function buildAppPageRscResponse( const headers = new Headers({ "Content-Type": VINEXT_RSC_CONTENT_TYPE, Vary: VINEXT_RSC_VARY_HEADER, + // Mirror Next.js' edge runtime marker. vinext serves every App Router + // response from a Worker (edge-equivalent runtime), so the test that + // asserts `x-edge-runtime: '1'` on RSC responses must see this header. + // See edge-ssr-app.ts in the Next.js source for the canonical emission. + "x-edge-runtime": "1", }); if (options.params && Object.keys(options.params).length > 0) { @@ -257,6 +262,11 @@ export function buildAppPageHtmlResponse( const headers = new Headers({ "Content-Type": "text/html; charset=utf-8", Vary: VINEXT_RSC_VARY_HEADER, + // Mirror Next.js' edge runtime marker. vinext serves every App Router + // response from a Worker (edge-equivalent runtime), so the test that + // asserts `x-edge-runtime: '1'` on HTML responses must see this header. + // See edge-ssr-app.ts in the Next.js source for the canonical emission. + "x-edge-runtime": "1", }); if (options.policy.cacheControl) { diff --git a/tests/app-page-response.test.ts b/tests/app-page-response.test.ts index e4728fa7a..90a9c9751 100644 --- a/tests/app-page-response.test.ts +++ b/tests/app-page-response.test.ts @@ -388,6 +388,18 @@ describe("app page response helpers", () => { await expect(response.text()).resolves.toBe("flight"); }); + it("emits the `x-edge-runtime: 1` marker on RSC responses (issue #1531)", () => { + // Next.js sets `x-edge-runtime: 1` on edge-runtime app responses (see + // edge-ssr-app.ts in the Next.js source). vinext serves every App Router + // response from a Worker, so the marker must always be present. + const response = buildAppPageRscResponse(createBody("flight"), { + middlewareContext: { headers: null, status: null }, + policy: {}, + }); + + expect(response.headers.get("x-edge-runtime")).toBe("1"); + }); + it("builds RSC responses with the current compatibility ID header", () => { const response = withEnvVar("__VINEXT_RSC_COMPATIBILITY_ID", "compat-a", () => buildAppPageRscResponse(createBody("flight"), { @@ -478,6 +490,18 @@ describe("app page response helpers", () => { expect(setCookies).toContain("mw=1; Path=/"); await expect(response.text()).resolves.toBe("

page

"); }); + + it("emits the `x-edge-runtime: 1` marker on HTML responses (issue #1531)", () => { + // Next.js sets `x-edge-runtime: 1` on edge-runtime app responses (see + // edge-ssr-app.ts in the Next.js source). vinext serves every App Router + // response from a Worker, so the marker must always be present. + const response = buildAppPageHtmlResponse(createBody("

page

"), { + middlewareContext: { headers: null, status: null }, + policy: {}, + }); + + expect(response.headers.get("x-edge-runtime")).toBe("1"); + }); }); describe("mergeMiddlewareResponseHeaders", () => {