vinext 0.0.52 → 0.0.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/build/clean-output.d.ts +14 -0
- package/dist/build/clean-output.js +36 -0
- package/dist/build/clean-output.js.map +1 -0
- package/dist/build/inline-css.d.ts +7 -0
- package/dist/build/inline-css.js +50 -0
- package/dist/build/inline-css.js.map +1 -0
- package/dist/build/prerender.d.ts +6 -2
- package/dist/build/prerender.js +51 -12
- package/dist/build/prerender.js.map +1 -1
- package/dist/build/run-prerender.js +10 -1
- package/dist/build/run-prerender.js.map +1 -1
- package/dist/build/static-export.d.ts +5 -0
- package/dist/build/static-export.js +8 -3
- package/dist/build/static-export.js.map +1 -1
- package/dist/check.js +4 -0
- package/dist/check.js.map +1 -1
- package/dist/cli.js +19 -4
- package/dist/cli.js.map +1 -1
- package/dist/client/instrumentation-client-inject.d.ts +34 -0
- package/dist/client/instrumentation-client-inject.js +57 -0
- package/dist/client/instrumentation-client-inject.js.map +1 -0
- package/dist/client/navigation-runtime.d.ts +16 -2
- package/dist/client/navigation-runtime.js +16 -1
- package/dist/client/navigation-runtime.js.map +1 -1
- package/dist/client/vinext-next-data.d.ts +2 -1
- package/dist/client/vinext-next-data.js.map +1 -1
- package/dist/client/window-next.d.ts +17 -2
- package/dist/client/window-next.js.map +1 -1
- package/dist/cloudflare/tpr.js +1 -1
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/config-matchers.js +2 -1
- package/dist/config/config-matchers.js.map +1 -1
- package/dist/config/next-config.d.ts +95 -4
- package/dist/config/next-config.js +173 -14
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.js +42 -7
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.d.ts +11 -1
- package/dist/entries/app-browser-entry.js +16 -6
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +12 -3
- package/dist/entries/app-rsc-entry.js +41 -8
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +21 -1
- package/dist/entries/app-rsc-manifest.js +6 -4
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/pages-client-entry.d.ts +4 -1
- package/dist/entries/pages-client-entry.js +40 -3
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +292 -34
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/entries/runtime-entry-module.d.ts +1 -10
- package/dist/entries/runtime-entry-module.js +2 -12
- package/dist/entries/runtime-entry-module.js.map +1 -1
- package/dist/index.js +91 -10
- package/dist/index.js.map +1 -1
- package/dist/plugins/fonts.js +25 -2
- package/dist/plugins/fonts.js.map +1 -1
- package/dist/plugins/remove-console.d.ts +16 -0
- package/dist/plugins/remove-console.js +176 -0
- package/dist/plugins/remove-console.js.map +1 -0
- package/dist/routing/app-route-graph.d.ts +24 -1
- package/dist/routing/app-route-graph.js +52 -4
- package/dist/routing/app-route-graph.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -2
- package/dist/routing/app-router.js +2 -2
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +21 -1
- package/dist/routing/file-matcher.js +39 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.d.ts +1 -1
- package/dist/routing/pages-router.js +10 -3
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/route-trie.js +13 -18
- package/dist/routing/route-trie.js.map +1 -1
- package/dist/routing/utils.d.ts +11 -1
- package/dist/routing/utils.js +15 -1
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.js +19 -10
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-browser-action-result.d.ts +16 -1
- package/dist/server/app-browser-action-result.js +15 -1
- package/dist/server/app-browser-action-result.js.map +1 -1
- package/dist/server/app-browser-entry.js +47 -28
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-navigation-controller.d.ts +2 -0
- package/dist/server/app-browser-navigation-controller.js +4 -0
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-elements-wire.d.ts +13 -4
- package/dist/server/app-elements-wire.js +10 -1
- package/dist/server/app-elements-wire.js.map +1 -1
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-fallback-renderer.d.ts +27 -8
- package/dist/server/app-fallback-renderer.js +19 -8
- package/dist/server/app-fallback-renderer.js.map +1 -1
- package/dist/server/app-history-state.js +6 -2
- package/dist/server/app-history-state.js.map +1 -1
- package/dist/server/app-inline-css-client.d.ts +7 -0
- package/dist/server/app-inline-css-client.js +37 -0
- package/dist/server/app-inline-css-client.js.map +1 -0
- package/dist/server/app-interception-context-header.d.ts +33 -0
- package/dist/server/app-interception-context-header.js +44 -0
- package/dist/server/app-interception-context-header.js.map +1 -0
- package/dist/server/app-mounted-slots-header.d.ts +19 -0
- package/dist/server/app-mounted-slots-header.js +40 -1
- package/dist/server/app-mounted-slots-header.js.map +1 -1
- package/dist/server/app-optimistic-routing.js +26 -18
- package/dist/server/app-optimistic-routing.js.map +1 -1
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +2 -0
- package/dist/server/app-page-boundary-render.js.map +1 -1
- package/dist/server/app-page-boundary.d.ts +22 -1
- package/dist/server/app-page-boundary.js +30 -3
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +9 -3
- package/dist/server/app-page-cache.js +14 -8
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +13 -1
- package/dist/server/app-page-dispatch.js +136 -82
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.d.ts +2 -1
- package/dist/server/app-page-element-builder.js +17 -30
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-execution.d.ts +1 -0
- package/dist/server/app-page-execution.js +2 -0
- package/dist/server/app-page-execution.js.map +1 -1
- package/dist/server/app-page-head.d.ts +1 -0
- package/dist/server/app-page-head.js +8 -0
- package/dist/server/app-page-head.js.map +1 -1
- package/dist/server/app-page-render-identity.d.ts +22 -0
- package/dist/server/app-page-render-identity.js +42 -0
- package/dist/server/app-page-render-identity.js.map +1 -0
- package/dist/server/app-page-render-observation.js +1 -1
- package/dist/server/app-page-render.d.ts +9 -1
- package/dist/server/app-page-render.js +8 -2
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +6 -3
- package/dist/server/app-page-request.js +5 -2
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.d.ts +11 -1
- package/dist/server/app-page-response.js +16 -4
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +16 -0
- package/dist/server/app-page-route-wiring.js +25 -10
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +12 -0
- package/dist/server/app-page-stream.js +3 -0
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +3 -0
- package/dist/server/app-route-handler-dispatch.js.map +1 -1
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-execution.js.map +1 -1
- package/dist/server/app-route-handler-response.js +38 -6
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-rsc-handler.d.ts +16 -3
- package/dist/server/app-rsc-handler.js +60 -11
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-rsc-request-normalization.d.ts +2 -1
- package/dist/server/app-rsc-request-normalization.js +6 -4
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-segment-config.d.ts +4 -1
- package/dist/server/app-segment-config.js +6 -1
- package/dist/server/app-segment-config.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +22 -3
- package/dist/server/app-server-action-execution.js +46 -7
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +57 -6
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-error-meta.js +3 -3
- package/dist/server/app-ssr-error-meta.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +25 -1
- package/dist/server/app-ssr-stream.js +237 -19
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/app-static-generation.d.ts +1 -0
- package/dist/server/app-static-generation.js +2 -1
- package/dist/server/app-static-generation.js.map +1 -1
- package/dist/server/client-trace-metadata.d.ts +31 -0
- package/dist/server/client-trace-metadata.js +83 -0
- package/dist/server/client-trace-metadata.js.map +1 -0
- package/dist/server/cookie-utils.d.ts +13 -0
- package/dist/server/cookie-utils.js +20 -0
- package/dist/server/cookie-utils.js.map +1 -0
- package/dist/server/default-not-found-module.d.ts +20 -0
- package/dist/server/default-not-found-module.js +20 -0
- package/dist/server/default-not-found-module.js.map +1 -0
- package/dist/server/dev-server.d.ts +8 -1
- package/dist/server/dev-server.js +56 -11
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/headers.d.ts +5 -1
- package/dist/server/headers.js +5 -1
- package/dist/server/headers.js.map +1 -1
- package/dist/server/html.d.ts +2 -1
- package/dist/server/html.js +6 -1
- package/dist/server/html.js.map +1 -1
- package/dist/server/image-optimization.d.ts +13 -4
- package/dist/server/image-optimization.js +15 -4
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/isr-cache.d.ts +7 -5
- package/dist/server/isr-cache.js +17 -6
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/middleware-runtime.js +1 -2
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/middleware.js +1 -1
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-api-route.d.ts +18 -0
- package/dist/server/pages-api-route.js +3 -1
- package/dist/server/pages-api-route.js.map +1 -1
- package/dist/server/pages-body-parser-config.d.ts +60 -0
- package/dist/server/pages-body-parser-config.js +79 -0
- package/dist/server/pages-body-parser-config.js.map +1 -0
- package/dist/server/pages-data-route.js +1 -0
- package/dist/server/pages-data-route.js.map +1 -1
- package/dist/server/pages-default-404.d.ts +31 -0
- package/dist/server/pages-default-404.js +40 -0
- package/dist/server/pages-default-404.js.map +1 -0
- package/dist/server/pages-document-initial-props.d.ts +7 -0
- package/dist/server/pages-document-initial-props.js +14 -0
- package/dist/server/pages-document-initial-props.js.map +1 -0
- package/dist/server/pages-node-compat.d.ts +10 -0
- package/dist/server/pages-node-compat.js +12 -1
- package/dist/server/pages-node-compat.js.map +1 -1
- package/dist/server/pages-page-data.d.ts +40 -0
- package/dist/server/pages-page-data.js +19 -14
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-method.d.ts +48 -0
- package/dist/server/pages-page-method.js +19 -0
- package/dist/server/pages-page-method.js.map +1 -0
- package/dist/server/pages-page-response.d.ts +8 -0
- package/dist/server/pages-page-response.js +21 -11
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/pages-serializable-props.d.ts +25 -0
- package/dist/server/pages-serializable-props.js +69 -0
- package/dist/server/pages-serializable-props.js.map +1 -0
- package/dist/server/prerender-route-params.d.ts +14 -0
- package/dist/server/prerender-route-params.js +94 -0
- package/dist/server/prerender-route-params.js.map +1 -0
- package/dist/server/prod-server.d.ts +3 -23
- package/dist/server/prod-server.js +43 -57
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/proxy-trust.d.ts +41 -0
- package/dist/server/proxy-trust.js +70 -0
- package/dist/server/proxy-trust.js.map +1 -0
- package/dist/server/request-pipeline.d.ts +3 -3
- package/dist/server/request-pipeline.js +5 -4
- package/dist/server/request-pipeline.js.map +1 -1
- package/dist/server/seed-cache.js +12 -6
- package/dist/server/seed-cache.js.map +1 -1
- package/dist/server/server-action-not-found.js +3 -2
- package/dist/server/server-action-not-found.js.map +1 -1
- package/dist/server/static-file-cache.js +2 -1
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/server/streaming-metadata.d.ts +5 -0
- package/dist/server/streaming-metadata.js +10 -0
- package/dist/server/streaming-metadata.js.map +1 -0
- package/dist/shims/app-router-scroll-state.d.ts +14 -0
- package/dist/shims/app-router-scroll-state.js +51 -0
- package/dist/shims/app-router-scroll-state.js.map +1 -0
- package/dist/shims/app-router-scroll.d.ts +28 -0
- package/dist/shims/app-router-scroll.js +115 -0
- package/dist/shims/app-router-scroll.js.map +1 -0
- package/dist/shims/before-interactive-context.d.ts +30 -0
- package/dist/shims/before-interactive-context.js +10 -0
- package/dist/shims/before-interactive-context.js.map +1 -0
- package/dist/shims/cache-runtime.d.ts +1 -1
- package/dist/shims/cache-runtime.js +14 -1
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +6 -0
- package/dist/shims/cache.js +7 -0
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/default-not-found.d.ts +12 -0
- package/dist/shims/default-not-found.js +61 -0
- package/dist/shims/default-not-found.js.map +1 -0
- package/dist/shims/error.js +3 -0
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/font-local.d.ts +5 -0
- package/dist/shims/font-local.js +6 -2
- package/dist/shims/font-local.js.map +1 -1
- package/dist/shims/head.js +4 -4
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +13 -2
- package/dist/shims/headers.js +73 -22
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/image.d.ts +1 -1
- package/dist/shims/image.js +4 -4
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/app-route-detection.d.ts +37 -0
- package/dist/shims/internal/app-route-detection.js +69 -0
- package/dist/shims/internal/app-route-detection.js.map +1 -0
- package/dist/shims/internal/pages-data-target.d.ts +58 -0
- package/dist/shims/internal/pages-data-target.js +91 -0
- package/dist/shims/internal/pages-data-target.js.map +1 -0
- package/dist/shims/internal/pages-data-url.d.ts +42 -0
- package/dist/shims/internal/pages-data-url.js +73 -0
- package/dist/shims/internal/pages-data-url.js.map +1 -0
- package/dist/shims/link.d.ts +18 -2
- package/dist/shims/link.js +129 -15
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +9 -7
- package/dist/shims/metadata.js +70 -7
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +1 -2
- package/dist/shims/navigation.js +94 -20
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/router.d.ts +5 -0
- package/dist/shims/router.js +389 -80
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.d.ts +11 -1
- package/dist/shims/script.js +158 -15
- package/dist/shims/script.js.map +1 -1
- package/dist/shims/server.js +1 -0
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/url-utils.d.ts +2 -1
- package/dist/shims/url-utils.js +15 -4
- package/dist/shims/url-utils.js.map +1 -1
- package/dist/utils/html-limited-bots.d.ts +5 -0
- package/dist/utils/html-limited-bots.js +15 -0
- package/dist/utils/html-limited-bots.js.map +1 -0
- package/dist/utils/path.d.ts +13 -0
- package/dist/utils/path.js +16 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/query.d.ts +6 -0
- package/dist/utils/query.js +10 -1
- package/dist/utils/query.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import "./headers.js";
|
|
2
2
|
import { processMiddlewareHeaders } from "./request-pipeline.js";
|
|
3
3
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
4
|
-
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
5
4
|
import { NEVER_CACHE_CONTROL, STATIC_CACHE_CONTROL, buildCachedRevalidateCacheControl } from "./cache-control.js";
|
|
5
|
+
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
6
|
+
import { getSetCookieName } from "./cookie-utils.js";
|
|
6
7
|
//#region src/server/app-route-handler-response.ts
|
|
7
8
|
const APP_ROUTE_REWRITE_ERROR = "NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.";
|
|
8
9
|
const APP_ROUTE_NEXT_ERROR = "NextResponse.next() was used in a app route handler, this is not supported. See here for more info: https://nextjs.org/docs/messages/next-response-next-in-app-route-handler";
|
|
@@ -48,10 +49,41 @@ function applyRouteHandlerRevalidateHeader(response, revalidateSeconds, expireSe
|
|
|
48
49
|
function markRouteHandlerCacheMiss(response) {
|
|
49
50
|
setCacheStateHeaders(response.headers, "MISS");
|
|
50
51
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Returns true when the given Set-Cookie string already declares any of the
|
|
54
|
+
* attributes that follow the first `;` (case-insensitively). Used to detect
|
|
55
|
+
* whether a user-emitted Set-Cookie line already carries an explicit `Path=`,
|
|
56
|
+
* matching Next.js's `appendMutableCookies` which re-runs every cookie through
|
|
57
|
+
* `ResponseCookies.set` (and therefore picks up the `Path=/` default for any
|
|
58
|
+
* cookie that didn't supply one).
|
|
59
|
+
*/
|
|
60
|
+
function hasCookieAttribute(cookie, attributeName) {
|
|
61
|
+
const target = attributeName.toLowerCase();
|
|
62
|
+
let i = cookie.indexOf(";");
|
|
63
|
+
while (i !== -1) {
|
|
64
|
+
let start = i + 1;
|
|
65
|
+
while (start < cookie.length && cookie[start] === " ") start++;
|
|
66
|
+
const next = cookie.indexOf(";", start);
|
|
67
|
+
const end = next === -1 ? cookie.length : next;
|
|
68
|
+
const eq = cookie.indexOf("=", start);
|
|
69
|
+
const attrEnd = eq === -1 || eq > end ? end : eq;
|
|
70
|
+
if (cookie.slice(start, attrEnd).trim().toLowerCase() === target) return true;
|
|
71
|
+
i = next;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Ensure each Set-Cookie line carries `Path=/` by default — Next.js's
|
|
77
|
+
* `appendMutableCookies` re-runs every returned cookie through
|
|
78
|
+
* `ResponseCookies.set`, which normalises a missing `path` to `/`. Without
|
|
79
|
+
* this, a raw `new Response(..., { headers: [['Set-Cookie', 'bar=bar2']] })`
|
|
80
|
+
* lands without `Path=/` and tests that assert on the full attribute set
|
|
81
|
+
* (e.g. Next.js's `app-action.test.ts` route-handler-overrides case, see
|
|
82
|
+
* issue #1484) break.
|
|
83
|
+
*/
|
|
84
|
+
function normalizeReturnedCookie(cookie) {
|
|
85
|
+
if (hasCookieAttribute(cookie, "Path")) return cookie;
|
|
86
|
+
return `${cookie}; Path=/`;
|
|
55
87
|
}
|
|
56
88
|
function applyMutableCookieFallbacks(headers, pendingCookies) {
|
|
57
89
|
if (pendingCookies.length === 0) return;
|
|
@@ -74,7 +106,7 @@ function applyMutableCookieFallbacks(headers, pendingCookies) {
|
|
|
74
106
|
headers.delete("Set-Cookie");
|
|
75
107
|
for (const cookie of unkeyedFallbackCookies) headers.append("Set-Cookie", cookie);
|
|
76
108
|
for (const cookie of fallbackCookies.values()) headers.append("Set-Cookie", cookie);
|
|
77
|
-
for (const cookie of returnedCookies) headers.append("Set-Cookie", cookie);
|
|
109
|
+
for (const cookie of returnedCookies) headers.append("Set-Cookie", normalizeReturnedCookie(cookie));
|
|
78
110
|
}
|
|
79
111
|
async function buildAppRouteCacheValue(response) {
|
|
80
112
|
const body = await response.arrayBuffer();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-route-handler-response.js","names":[],"sources":["../../src/server/app-route-handler-response.ts"],"sourcesContent":["import type { CachedRouteValue, CacheControlMetadata } from \"vinext/shims/cache\";\nimport {\n buildCachedRevalidateCacheControl,\n NEVER_CACHE_CONTROL,\n STATIC_CACHE_CONTROL,\n} from \"./cache-control.js\";\nimport {\n MIDDLEWARE_HEADER_PREFIX,\n MIDDLEWARE_NEXT_HEADER,\n MIDDLEWARE_REWRITE_HEADER,\n NEXTJS_CACHE_HEADER,\n VINEXT_CACHE_HEADER,\n} from \"./headers.js\";\nimport { setCacheStateHeaders } from \"./cache-headers.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { processMiddlewareHeaders } from \"./request-pipeline.js\";\n\nexport type RouteHandlerMiddlewareContext = {\n headers: Headers | null;\n status: number | null;\n};\n\ntype BuildRouteHandlerCachedResponseOptions = {\n cacheControl?: CacheControlMetadata;\n cacheState: \"HIT\" | \"STALE\";\n expireSeconds?: number;\n isHead: boolean;\n revalidateSeconds: number;\n};\n\ntype FinalizeRouteHandlerResponseOptions = {\n pendingCookies: string[];\n draftCookie?: string | null;\n isHead: boolean;\n};\n\nconst APP_ROUTE_REWRITE_ERROR =\n \"NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.\";\nconst APP_ROUTE_NEXT_ERROR =\n \"NextResponse.next() was used in a app route handler, this is not supported. See here for more info: https://nextjs.org/docs/messages/next-response-next-in-app-route-handler\";\n\nfunction hasMiddlewareHeader(headers: Headers): boolean {\n for (const key of headers.keys()) {\n if (key.startsWith(MIDDLEWARE_HEADER_PREFIX)) return true;\n }\n return false;\n}\n\nfunction buildRouteHandlerCacheControl(\n cacheState: BuildRouteHandlerCachedResponseOptions[\"cacheState\"],\n revalidateSeconds: number,\n expireSeconds?: number,\n): string {\n if (revalidateSeconds === 0) {\n // A cached response is never produced for revalidate = 0 (the ISR write\n // path skips it), so only the HIT/STALE->fresh rewrite can arrive here\n // with a 0 value, via applyRouteHandlerRevalidateHeader. In all such\n // cases the author opted out of caching entirely.\n return NEVER_CACHE_CONTROL;\n }\n\n if (revalidateSeconds === Infinity) {\n // revalidate = false / Infinity means \"cache indefinitely\" — emit the\n // same static Cache-Control used by pages, not a dynamic SWR value.\n return STATIC_CACHE_CONTROL;\n }\n\n return buildCachedRevalidateCacheControl(cacheState, revalidateSeconds, expireSeconds);\n}\n\nexport function applyRouteHandlerMiddlewareContext(\n response: Response,\n middlewareContext: RouteHandlerMiddlewareContext,\n): Response {\n if (!middlewareContext.headers && middlewareContext.status == null) {\n return response;\n }\n\n const responseHeaders = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(responseHeaders, middlewareContext.headers);\n\n return new Response(response.body, {\n status: middlewareContext.status ?? response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n}\n\nexport function assertSupportedAppRouteHandlerResponse(response: Response): void {\n // NextResponse.next() and rewrite() are middleware control-flow signals.\n // Once an App Route handler has returned, Next.js rejects those responses.\n if (response.headers.has(MIDDLEWARE_REWRITE_HEADER)) {\n throw new Error(APP_ROUTE_REWRITE_ERROR);\n }\n\n if (response.headers.get(MIDDLEWARE_NEXT_HEADER) === \"1\") {\n throw new Error(APP_ROUTE_NEXT_ERROR);\n }\n}\n\nexport function buildRouteHandlerCachedResponse(\n cachedValue: CachedRouteValue,\n options: BuildRouteHandlerCachedResponseOptions,\n): Response {\n const headers = new Headers();\n for (const [key, value] of Object.entries(cachedValue.headers)) {\n if (Array.isArray(value)) {\n for (const entry of value) {\n headers.append(key, entry);\n }\n } else {\n headers.set(key, value);\n }\n }\n setCacheStateHeaders(headers, options.cacheState);\n const revalidateSeconds = options.cacheControl?.revalidate ?? options.revalidateSeconds;\n const expireSeconds =\n options.cacheControl === undefined\n ? undefined\n : (options.cacheControl.expire ?? options.expireSeconds);\n headers.set(\n \"Cache-Control\",\n buildRouteHandlerCacheControl(options.cacheState, revalidateSeconds, expireSeconds),\n );\n\n return new Response(options.isHead ? null : cachedValue.body, {\n status: cachedValue.status,\n headers,\n });\n}\n\nexport function applyRouteHandlerRevalidateHeader(\n response: Response,\n revalidateSeconds: number,\n expireSeconds?: number,\n): void {\n response.headers.set(\n \"cache-control\",\n buildRouteHandlerCacheControl(\"HIT\", revalidateSeconds, expireSeconds),\n );\n}\n\nexport function markRouteHandlerCacheMiss(response: Response): void {\n setCacheStateHeaders(response.headers, \"MISS\");\n}\n\nfunction getSetCookieName(cookie: string): string | null {\n const equalsIndex = cookie.indexOf(\"=\");\n if (equalsIndex <= 0) {\n return null;\n }\n return cookie.slice(0, equalsIndex);\n}\n\nfunction applyMutableCookieFallbacks(headers: Headers, pendingCookies: string[]): void {\n if (pendingCookies.length === 0) {\n return;\n }\n\n const returnedCookies = headers.getSetCookie();\n const returnedCookieNames = new Set<string>();\n for (const cookie of returnedCookies) {\n const name = getSetCookieName(cookie);\n if (name) {\n returnedCookieNames.add(name);\n }\n }\n\n const fallbackCookies = new Map<string, string>();\n const unkeyedFallbackCookies: string[] = [];\n for (const cookie of pendingCookies) {\n const name = getSetCookieName(cookie);\n if (!name) {\n unkeyedFallbackCookies.push(cookie);\n continue;\n }\n\n if (!returnedCookieNames.has(name)) {\n fallbackCookies.set(name, cookie);\n }\n }\n\n headers.delete(\"Set-Cookie\");\n for (const cookie of unkeyedFallbackCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of fallbackCookies.values()) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of returnedCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n}\n\nexport async function buildAppRouteCacheValue(response: Response): Promise<CachedRouteValue> {\n const body = await response.arrayBuffer();\n const headers: CachedRouteValue[\"headers\"] = {};\n\n response.headers.forEach((value, key) => {\n if (\n key === \"set-cookie\" ||\n key === VINEXT_CACHE_HEADER.toLowerCase() ||\n key === NEXTJS_CACHE_HEADER.toLowerCase() ||\n key === \"cache-control\" ||\n key.startsWith(MIDDLEWARE_HEADER_PREFIX)\n ) {\n return;\n }\n headers[key] = value;\n });\n const setCookies = response.headers.getSetCookie?.() ?? [];\n if (setCookies.length > 0) {\n headers[\"set-cookie\"] = setCookies;\n }\n\n return {\n kind: \"APP_ROUTE\",\n body,\n status: response.status,\n headers,\n };\n}\n\nexport function finalizeRouteHandlerResponse(\n response: Response,\n options: FinalizeRouteHandlerResponseOptions,\n): Response {\n const { pendingCookies, draftCookie, isHead } = options;\n if (\n pendingCookies.length === 0 &&\n !draftCookie &&\n !isHead &&\n !hasMiddlewareHeader(response.headers)\n ) {\n return response;\n }\n\n const headers = new Headers(response.headers);\n processMiddlewareHeaders(headers);\n applyMutableCookieFallbacks(headers, pendingCookies);\n if (draftCookie) {\n headers.append(\"Set-Cookie\", draftCookie);\n }\n\n return new Response(isHead ? null : response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-route-handler-response.js","names":[],"sources":["../../src/server/app-route-handler-response.ts"],"sourcesContent":["import type { CachedRouteValue, CacheControlMetadata } from \"vinext/shims/cache\";\nimport {\n buildCachedRevalidateCacheControl,\n NEVER_CACHE_CONTROL,\n STATIC_CACHE_CONTROL,\n} from \"./cache-control.js\";\nimport {\n MIDDLEWARE_HEADER_PREFIX,\n MIDDLEWARE_NEXT_HEADER,\n MIDDLEWARE_REWRITE_HEADER,\n NEXTJS_CACHE_HEADER,\n VINEXT_CACHE_HEADER,\n} from \"./headers.js\";\nimport { setCacheStateHeaders } from \"./cache-headers.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./middleware-response-headers.js\";\nimport { processMiddlewareHeaders } from \"./request-pipeline.js\";\nimport { getSetCookieName } from \"./cookie-utils.js\";\n\nexport type RouteHandlerMiddlewareContext = {\n headers: Headers | null;\n status: number | null;\n};\n\ntype BuildRouteHandlerCachedResponseOptions = {\n cacheControl?: CacheControlMetadata;\n cacheState: \"HIT\" | \"STALE\";\n expireSeconds?: number;\n isHead: boolean;\n revalidateSeconds: number;\n};\n\ntype FinalizeRouteHandlerResponseOptions = {\n pendingCookies: string[];\n draftCookie?: string | null;\n isHead: boolean;\n};\n\nconst APP_ROUTE_REWRITE_ERROR =\n \"NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.\";\nconst APP_ROUTE_NEXT_ERROR =\n \"NextResponse.next() was used in a app route handler, this is not supported. See here for more info: https://nextjs.org/docs/messages/next-response-next-in-app-route-handler\";\n\nfunction hasMiddlewareHeader(headers: Headers): boolean {\n for (const key of headers.keys()) {\n if (key.startsWith(MIDDLEWARE_HEADER_PREFIX)) return true;\n }\n return false;\n}\n\nfunction buildRouteHandlerCacheControl(\n cacheState: BuildRouteHandlerCachedResponseOptions[\"cacheState\"],\n revalidateSeconds: number,\n expireSeconds?: number,\n): string {\n if (revalidateSeconds === 0) {\n // A cached response is never produced for revalidate = 0 (the ISR write\n // path skips it), so only the HIT/STALE->fresh rewrite can arrive here\n // with a 0 value, via applyRouteHandlerRevalidateHeader. In all such\n // cases the author opted out of caching entirely.\n return NEVER_CACHE_CONTROL;\n }\n\n if (revalidateSeconds === Infinity) {\n // revalidate = false / Infinity means \"cache indefinitely\" — emit the\n // same static Cache-Control used by pages, not a dynamic SWR value.\n return STATIC_CACHE_CONTROL;\n }\n\n return buildCachedRevalidateCacheControl(cacheState, revalidateSeconds, expireSeconds);\n}\n\nexport function applyRouteHandlerMiddlewareContext(\n response: Response,\n middlewareContext: RouteHandlerMiddlewareContext,\n): Response {\n if (!middlewareContext.headers && middlewareContext.status == null) {\n return response;\n }\n\n const responseHeaders = new Headers(response.headers);\n mergeMiddlewareResponseHeaders(responseHeaders, middlewareContext.headers);\n\n return new Response(response.body, {\n status: middlewareContext.status ?? response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n}\n\nexport function assertSupportedAppRouteHandlerResponse(response: Response): void {\n // NextResponse.next() and rewrite() are middleware control-flow signals.\n // Once an App Route handler has returned, Next.js rejects those responses.\n if (response.headers.has(MIDDLEWARE_REWRITE_HEADER)) {\n throw new Error(APP_ROUTE_REWRITE_ERROR);\n }\n\n if (response.headers.get(MIDDLEWARE_NEXT_HEADER) === \"1\") {\n throw new Error(APP_ROUTE_NEXT_ERROR);\n }\n}\n\nexport function buildRouteHandlerCachedResponse(\n cachedValue: CachedRouteValue,\n options: BuildRouteHandlerCachedResponseOptions,\n): Response {\n const headers = new Headers();\n for (const [key, value] of Object.entries(cachedValue.headers)) {\n if (Array.isArray(value)) {\n for (const entry of value) {\n headers.append(key, entry);\n }\n } else {\n headers.set(key, value);\n }\n }\n setCacheStateHeaders(headers, options.cacheState);\n const revalidateSeconds = options.cacheControl?.revalidate ?? options.revalidateSeconds;\n const expireSeconds =\n options.cacheControl === undefined\n ? undefined\n : (options.cacheControl.expire ?? options.expireSeconds);\n headers.set(\n \"Cache-Control\",\n buildRouteHandlerCacheControl(options.cacheState, revalidateSeconds, expireSeconds),\n );\n\n return new Response(options.isHead ? null : cachedValue.body, {\n status: cachedValue.status,\n headers,\n });\n}\n\nexport function applyRouteHandlerRevalidateHeader(\n response: Response,\n revalidateSeconds: number,\n expireSeconds?: number,\n): void {\n response.headers.set(\n \"cache-control\",\n buildRouteHandlerCacheControl(\"HIT\", revalidateSeconds, expireSeconds),\n );\n}\n\nexport function markRouteHandlerCacheMiss(response: Response): void {\n setCacheStateHeaders(response.headers, \"MISS\");\n}\n\n/**\n * Returns true when the given Set-Cookie string already declares any of the\n * attributes that follow the first `;` (case-insensitively). Used to detect\n * whether a user-emitted Set-Cookie line already carries an explicit `Path=`,\n * matching Next.js's `appendMutableCookies` which re-runs every cookie through\n * `ResponseCookies.set` (and therefore picks up the `Path=/` default for any\n * cookie that didn't supply one).\n */\nfunction hasCookieAttribute(cookie: string, attributeName: string): boolean {\n const target = attributeName.toLowerCase();\n // Skip past the first '=' (the cookie value separator) so we don't match\n // `attributeName=` inside the cookie value itself.\n let i = cookie.indexOf(\";\");\n while (i !== -1) {\n // Trim leading whitespace after the ';'\n let start = i + 1;\n while (start < cookie.length && cookie[start] === \" \") start++;\n const next = cookie.indexOf(\";\", start);\n const end = next === -1 ? cookie.length : next;\n const eq = cookie.indexOf(\"=\", start);\n const attrEnd = eq === -1 || eq > end ? end : eq;\n const attr = cookie.slice(start, attrEnd).trim().toLowerCase();\n if (attr === target) {\n return true;\n }\n i = next;\n }\n return false;\n}\n\n/**\n * Ensure each Set-Cookie line carries `Path=/` by default — Next.js's\n * `appendMutableCookies` re-runs every returned cookie through\n * `ResponseCookies.set`, which normalises a missing `path` to `/`. Without\n * this, a raw `new Response(..., { headers: [['Set-Cookie', 'bar=bar2']] })`\n * lands without `Path=/` and tests that assert on the full attribute set\n * (e.g. Next.js's `app-action.test.ts` route-handler-overrides case, see\n * issue #1484) break.\n */\nfunction normalizeReturnedCookie(cookie: string): string {\n if (hasCookieAttribute(cookie, \"Path\")) {\n return cookie;\n }\n return `${cookie}; Path=/`;\n}\n\nfunction applyMutableCookieFallbacks(headers: Headers, pendingCookies: string[]): void {\n if (pendingCookies.length === 0) {\n return;\n }\n\n const returnedCookies = headers.getSetCookie();\n const returnedCookieNames = new Set<string>();\n for (const cookie of returnedCookies) {\n const name = getSetCookieName(cookie);\n if (name) {\n returnedCookieNames.add(name);\n }\n }\n\n const fallbackCookies = new Map<string, string>();\n const unkeyedFallbackCookies: string[] = [];\n for (const cookie of pendingCookies) {\n const name = getSetCookieName(cookie);\n if (!name) {\n unkeyedFallbackCookies.push(cookie);\n continue;\n }\n\n if (!returnedCookieNames.has(name)) {\n fallbackCookies.set(name, cookie);\n }\n }\n\n headers.delete(\"Set-Cookie\");\n for (const cookie of unkeyedFallbackCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of fallbackCookies.values()) {\n headers.append(\"Set-Cookie\", cookie);\n }\n for (const cookie of returnedCookies) {\n headers.append(\"Set-Cookie\", normalizeReturnedCookie(cookie));\n }\n}\n\nexport async function buildAppRouteCacheValue(response: Response): Promise<CachedRouteValue> {\n const body = await response.arrayBuffer();\n const headers: CachedRouteValue[\"headers\"] = {};\n\n response.headers.forEach((value, key) => {\n if (\n key === \"set-cookie\" ||\n key === VINEXT_CACHE_HEADER.toLowerCase() ||\n key === NEXTJS_CACHE_HEADER.toLowerCase() ||\n key === \"cache-control\" ||\n key.startsWith(MIDDLEWARE_HEADER_PREFIX)\n ) {\n return;\n }\n headers[key] = value;\n });\n const setCookies = response.headers.getSetCookie?.() ?? [];\n if (setCookies.length > 0) {\n headers[\"set-cookie\"] = setCookies;\n }\n\n return {\n kind: \"APP_ROUTE\",\n body,\n status: response.status,\n headers,\n };\n}\n\nexport function finalizeRouteHandlerResponse(\n response: Response,\n options: FinalizeRouteHandlerResponseOptions,\n): Response {\n const { pendingCookies, draftCookie, isHead } = options;\n if (\n pendingCookies.length === 0 &&\n !draftCookie &&\n !isHead &&\n !hasMiddlewareHeader(response.headers)\n ) {\n return response;\n }\n\n const headers = new Headers(response.headers);\n processMiddlewareHeaders(headers);\n applyMutableCookieFallbacks(headers, pendingCookies);\n if (draftCookie) {\n headers.append(\"Set-Cookie\", draftCookie);\n }\n\n return new Response(isHead ? null : response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n"],"mappings":"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"}
|
|
@@ -38,6 +38,7 @@ type DispatchMatchedPageOptions<TRoute> = {
|
|
|
38
38
|
middlewareContext: AppRscMiddlewareContext;
|
|
39
39
|
mountedSlotsHeader: string | null;
|
|
40
40
|
params: AppPageParams;
|
|
41
|
+
staticParamsValidationParams?: AppPageParams;
|
|
41
42
|
rootParams?: RootParams;
|
|
42
43
|
request: Request;
|
|
43
44
|
route: TRoute;
|
|
@@ -66,15 +67,26 @@ type HandleProgressiveActionRequestOptions = {
|
|
|
66
67
|
middlewareContext: AppRscMiddlewareContext;
|
|
67
68
|
request: Request;
|
|
68
69
|
};
|
|
69
|
-
|
|
70
|
+
/**
|
|
71
|
+
* Side-effect headers captured during a progressive (no-JS) server action's
|
|
72
|
+
* non-redirect execution. Forwarded onto the page render response so that
|
|
73
|
+
* `cookies().set(...)` and revalidation kinds reach the browser. See
|
|
74
|
+
* `app-server-action-execution.ts` and issue #1483 for the full rationale.
|
|
75
|
+
*/
|
|
76
|
+
type ProgressiveActionSideEffects = {
|
|
77
|
+
pendingCookies: string[];
|
|
78
|
+
draftCookie: string | null | undefined; /** Numeric revalidation kind: `0` (none), `1` (static+dynamic), etc. */
|
|
79
|
+
revalidationKind: number;
|
|
80
|
+
};
|
|
81
|
+
type ProgressiveActionFormStateResult = ({
|
|
70
82
|
formState: ReactFormState | null;
|
|
71
83
|
kind: "form-state";
|
|
72
|
-
} | {
|
|
84
|
+
} & ProgressiveActionSideEffects) | ({
|
|
73
85
|
actionError: unknown;
|
|
74
86
|
actionFailed: true;
|
|
75
87
|
formState: null;
|
|
76
88
|
kind: "form-state";
|
|
77
|
-
};
|
|
89
|
+
} & ProgressiveActionSideEffects);
|
|
78
90
|
type HandleServerActionRequestOptions = {
|
|
79
91
|
actionId: string | null;
|
|
80
92
|
cleanPathname: string;
|
|
@@ -115,6 +127,7 @@ type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
|
|
|
115
127
|
beforeFiles: NextRewrite[];
|
|
116
128
|
fallback: NextRewrite[];
|
|
117
129
|
};
|
|
130
|
+
draftModeSecret: string;
|
|
118
131
|
dispatchMatchedPage: (options: DispatchMatchedPageOptions<TRoute>) => Promise<Response>;
|
|
119
132
|
dispatchMatchedRouteHandler: (options: DispatchMatchedRouteHandlerOptions<TRoute>) => Promise<Response>;
|
|
120
133
|
ensureInstrumentation?: () => Promise<void>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
|
|
2
2
|
import { hasBasePath } from "../utils/base-path.js";
|
|
3
3
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
4
|
-
import { VINEXT_MW_CTX_HEADER } from "./headers.js";
|
|
4
|
+
import { ACTION_REVALIDATED_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER } from "./headers.js";
|
|
5
5
|
import { isExternalUrl, matchRedirect, matchRewrite, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
|
|
6
6
|
import { notFoundResponse } from "./http-error-responses.js";
|
|
7
7
|
import { applyConfigHeadersToResponse, cloneRequestWithHeaders, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute, validateImageUrl } from "./request-pipeline.js";
|
|
@@ -10,14 +10,16 @@ import { ensureFetchPatch, setCurrentFetchSoftTags } from "../shims/fetch-cache.
|
|
|
10
10
|
import { createRscRedirectLocation, resolveInvalidRscCacheBustingRequest, stripRscCacheBustingSearchParam, stripRscSuffix } from "./app-rsc-cache-busting.js";
|
|
11
11
|
import { getScriptNonceFromHeaderSources } from "./csp.js";
|
|
12
12
|
import { normalizeDefaultLocalePathname } from "./pages-i18n.js";
|
|
13
|
+
import { isImageOptimizationPath } from "./image-optimization.js";
|
|
14
|
+
import { prerenderRouteParamsPayloadMatchesRoute, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
15
|
+
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
13
16
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
14
|
-
import { applyAppMiddleware } from "./app-middleware.js";
|
|
15
17
|
import "./app-page-response.js";
|
|
18
|
+
import { applyAppMiddleware } from "./app-middleware.js";
|
|
16
19
|
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
17
20
|
import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
|
|
18
21
|
import { pickRootParams, setRootParams } from "../shims/root-params.js";
|
|
19
22
|
import { handleAppPrerenderEndpoint } from "./app-prerender-endpoints.js";
|
|
20
|
-
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
21
23
|
import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
|
|
22
24
|
import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
|
|
23
25
|
import { handleMetadataRouteRequest } from "./metadata-route-response.js";
|
|
@@ -143,7 +145,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
143
145
|
}, matchPathname(cleanPathname));
|
|
144
146
|
if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;
|
|
145
147
|
if (beforeFilesRewrite) cleanPathname = beforeFilesRewrite;
|
|
146
|
-
if (cleanPathname
|
|
148
|
+
if (isImageOptimizationPath(cleanPathname)) {
|
|
147
149
|
const imageUrlResult = validateImageUrl(url.searchParams.get("url"), request.url);
|
|
148
150
|
if (imageUrlResult instanceof Response) return imageUrlResult;
|
|
149
151
|
return Response.redirect(new URL(imageUrlResult, url.origin).href, 302);
|
|
@@ -171,6 +173,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
171
173
|
searchParams: url.searchParams,
|
|
172
174
|
params: {}
|
|
173
175
|
});
|
|
176
|
+
const preActionMatch = options.matchRoute(cleanPathname);
|
|
177
|
+
if (preActionMatch) setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));
|
|
174
178
|
const actionId = request.headers.get("x-rsc-action") ?? request.headers.get("next-action");
|
|
175
179
|
const contentType = request.headers.get("content-type") || "";
|
|
176
180
|
const progressiveActionResult = await options.handleProgressiveActionRequest({
|
|
@@ -198,7 +202,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
198
202
|
searchParams: url.searchParams
|
|
199
203
|
});
|
|
200
204
|
if (serverActionResponse) return serverActionResponse;
|
|
201
|
-
let match =
|
|
205
|
+
let match = preActionMatch;
|
|
202
206
|
if (!match || match.route.isDynamic) {
|
|
203
207
|
const afterFilesRewrite = await applyRewrite({
|
|
204
208
|
basePathState,
|
|
@@ -228,6 +232,10 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
228
232
|
}
|
|
229
233
|
}
|
|
230
234
|
if (!match) {
|
|
235
|
+
if (process.env.NODE_ENV !== "production" && canonicalPathname === "/favicon.ico") {
|
|
236
|
+
options.clearRequestContext();
|
|
237
|
+
return new Response("", { status: 404 });
|
|
238
|
+
}
|
|
231
239
|
const pagesFallbackResponse = await options.renderPagesFallback?.({
|
|
232
240
|
isRscRequest,
|
|
233
241
|
middlewareContext,
|
|
@@ -252,25 +260,28 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
252
260
|
return notFoundResponse({ headers });
|
|
253
261
|
}
|
|
254
262
|
const { route, params } = match;
|
|
263
|
+
const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(request);
|
|
264
|
+
const prerenderRouteParams = prerenderRouteParamsPayloadMatchesRoute(prerenderRouteParamsPayload, route.pattern, params) ? prerenderRouteParamsPayload.params : null;
|
|
265
|
+
const renderParams = prerenderRouteParams ?? params;
|
|
255
266
|
options.setNavigationContext({
|
|
256
267
|
pathname: canonicalPathname,
|
|
257
268
|
searchParams: url.searchParams,
|
|
258
|
-
params
|
|
269
|
+
params: renderParams
|
|
259
270
|
});
|
|
260
|
-
const rootParams = pickRootParams(
|
|
271
|
+
const rootParams = pickRootParams(renderParams, route.rootParamNames);
|
|
261
272
|
setRootParams(rootParams);
|
|
262
273
|
if (route.routeHandler) {
|
|
263
274
|
setCurrentFetchSoftTags(buildPageCacheTags(cleanPathname, [], [...route.routeSegments], "route"));
|
|
264
275
|
return options.dispatchMatchedRouteHandler({
|
|
265
276
|
cleanPathname,
|
|
266
277
|
middlewareContext,
|
|
267
|
-
params: route.isDynamic ?
|
|
278
|
+
params: route.isDynamic ? renderParams : null,
|
|
268
279
|
request,
|
|
269
280
|
route,
|
|
270
281
|
searchParams: url.searchParams
|
|
271
282
|
});
|
|
272
283
|
}
|
|
273
|
-
|
|
284
|
+
const pageResponse = await options.dispatchMatchedPage({
|
|
274
285
|
cleanPathname,
|
|
275
286
|
formState,
|
|
276
287
|
actionError,
|
|
@@ -281,7 +292,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
281
292
|
isRscRequest,
|
|
282
293
|
middlewareContext,
|
|
283
294
|
mountedSlotsHeader,
|
|
284
|
-
params,
|
|
295
|
+
params: renderParams,
|
|
296
|
+
staticParamsValidationParams: prerenderRouteParams === null ? void 0 : params,
|
|
285
297
|
rootParams,
|
|
286
298
|
request,
|
|
287
299
|
route,
|
|
@@ -289,18 +301,55 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
289
301
|
searchParams: url.searchParams,
|
|
290
302
|
renderMode
|
|
291
303
|
});
|
|
304
|
+
if (isProgressiveActionRender) return applyProgressiveActionSideEffects(pageResponse, progressiveActionResult);
|
|
305
|
+
return pageResponse;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Append `Set-Cookie` headers and the `x-action-revalidated` marker captured
|
|
309
|
+
* during progressive (no-JS) server action execution to the page render
|
|
310
|
+
* response. See issue #1483.
|
|
311
|
+
*
|
|
312
|
+
* Falls back to rebuilding the response when the headers object is immutable
|
|
313
|
+
* (e.g. `Response.redirect()`), so cookies set by the action ride out on a
|
|
314
|
+
* redirect issued during the rerender too.
|
|
315
|
+
*/
|
|
316
|
+
function applyProgressiveActionSideEffects(response, sideEffects) {
|
|
317
|
+
const hasPendingCookies = sideEffects.pendingCookies.length > 0;
|
|
318
|
+
const hasDraftCookie = Boolean(sideEffects.draftCookie);
|
|
319
|
+
const hasRevalidationKind = sideEffects.revalidationKind !== 0;
|
|
320
|
+
if (!hasPendingCookies && !hasDraftCookie && !hasRevalidationKind) return response;
|
|
321
|
+
const applyTo = (headers) => {
|
|
322
|
+
for (const cookie of sideEffects.pendingCookies) headers.append("Set-Cookie", cookie);
|
|
323
|
+
if (sideEffects.draftCookie) headers.append("Set-Cookie", sideEffects.draftCookie);
|
|
324
|
+
if (hasRevalidationKind) headers.set(ACTION_REVALIDATED_HEADER, JSON.stringify(sideEffects.revalidationKind));
|
|
325
|
+
};
|
|
326
|
+
try {
|
|
327
|
+
applyTo(response.headers);
|
|
328
|
+
return response;
|
|
329
|
+
} catch {
|
|
330
|
+
const headers = new Headers(response.headers);
|
|
331
|
+
applyTo(headers);
|
|
332
|
+
return new Response(response.body, {
|
|
333
|
+
status: response.status,
|
|
334
|
+
statusText: response.statusText,
|
|
335
|
+
headers
|
|
336
|
+
});
|
|
337
|
+
}
|
|
292
338
|
}
|
|
293
339
|
function createAppRscHandler(options) {
|
|
294
340
|
return async function appRscHandler(rawRequest, ctx) {
|
|
295
341
|
await options.ensureInstrumentation?.();
|
|
296
342
|
const mwCtx = rawRequest.headers.get(VINEXT_MW_CTX_HEADER);
|
|
297
343
|
const isDataRequest = rawRequest.headers.get("x-nextjs-data") === "1";
|
|
344
|
+
const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(rawRequest);
|
|
298
345
|
const filteredHeaders = filterInternalHeaders(rawRequest.headers);
|
|
299
346
|
if (mwCtx !== null) filteredHeaders.set(VINEXT_MW_CTX_HEADER, mwCtx);
|
|
347
|
+
const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParamsPayload);
|
|
348
|
+
if (prerenderRouteParamsHeader !== null) filteredHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
|
|
300
349
|
const request = cloneRequestWithHeaders(rawRequest, filteredHeaders);
|
|
301
350
|
const executionContext = isExecutionContextLike(ctx) ? ctx : getRequestExecutionContext() ?? null;
|
|
302
351
|
return runWithRequestContext(createRequestContext({
|
|
303
|
-
headersContext: headersContextFromRequest(request),
|
|
352
|
+
headersContext: headersContextFromRequest(request, { draftModeSecret: options.draftModeSecret }),
|
|
304
353
|
executionContext,
|
|
305
354
|
unstableCacheRevalidation: "background"
|
|
306
355
|
}), () => runWithPrerenderWorkUnit(async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-rsc-handler.js","names":[],"sources":["../../src/server/app-rsc-handler.ts"],"sourcesContent":["import type {\n NextHeader,\n NextI18nConfig,\n NextRedirect,\n NextRewrite,\n} from \"../config/next-config.js\";\nimport {\n isExternalUrl,\n matchRedirect,\n matchRewrite,\n proxyExternalRequest,\n requestContextFromRequest,\n sanitizeDestination,\n type BasePathMatchState,\n} from \"../config/config-matchers.js\";\nimport { headersContextFromRequest } from \"vinext/shims/headers\";\nimport {\n NEXT_ACTION_HEADER,\n RSC_ACTION_HEADER,\n RSC_HEADER,\n VINEXT_MW_CTX_HEADER,\n} from \"./headers.js\";\nimport { ensureFetchPatch, setCurrentFetchSoftTags } from \"vinext/shims/fetch-cache\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport {\n getRequestExecutionContext,\n type ExecutionContextLike,\n} from \"vinext/shims/request-context\";\nimport { pickRootParams, setRootParams, type RootParams } from \"vinext/shims/root-params\";\nimport { createRequestContext, runWithRequestContext } from \"vinext/shims/unified-request-context\";\nimport { flattenErrorCauses } from \"../utils/error-cause.js\";\nimport { hasBasePath } from \"../utils/base-path.js\";\nimport { applyAppMiddleware, type AppMiddlewareContext } from \"./app-middleware.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./app-page-response.js\";\nimport { handleAppPrerenderEndpoint } from \"./app-prerender-endpoints.js\";\nimport {\n createRscRedirectLocation,\n resolveInvalidRscCacheBustingRequest,\n stripRscCacheBustingSearchParam,\n stripRscSuffix,\n} from \"./app-rsc-cache-busting.js\";\nimport { finalizeAppRscResponse } from \"./app-rsc-response-finalizer.js\";\nimport { normalizeRscRequest } from \"./app-rsc-request-normalization.js\";\nimport { normalizeDefaultLocalePathname } from \"./pages-i18n.js\";\nimport { notFoundResponse } from \"./http-error-responses.js\";\nimport { getScriptNonceFromHeaderSources } from \"./csp.js\";\nimport { buildPageCacheTags } from \"./implicit-tags.js\";\nimport { handleMetadataRouteRequest } from \"./metadata-route-response.js\";\nimport type { MiddlewareModule } from \"./middleware-runtime.js\";\nimport { runWithPrerenderWorkUnit } from \"./prerender-work-unit-setup.js\";\nimport { buildPostMwRequestContext } from \"./app-post-middleware-context.js\";\nimport type { AppRscRenderMode } from \"./app-rsc-render-mode.js\";\nimport {\n cloneRequestWithHeaders,\n filterInternalHeaders,\n applyConfigHeadersToResponse,\n normalizeTrailingSlash,\n resolvePublicFileRoute,\n validateImageUrl,\n} from \"./request-pipeline.js\";\n\ntype AppPageParams = Record<string, string | string[]>;\ntype RequestContext = ReturnType<typeof requestContextFromRequest>;\ntype MetadataRoutes = Parameters<typeof handleMetadataRouteRequest>[0][\"metadataRoutes\"];\ntype MakeThenableParams = Parameters<typeof handleMetadataRouteRequest>[0][\"makeThenableParams\"];\ntype StaticParamsMap = Parameters<typeof handleAppPrerenderEndpoint>[1][\"staticParamsMap\"];\ntype RootParamNamesMap = Parameters<\n typeof handleAppPrerenderEndpoint\n>[1][\"rootParamNamesByPattern\"];\n\ntype AppRscMiddlewareContext = AppMiddlewareContext;\n\ntype AppRscHandlerRoute = {\n isDynamic: boolean;\n page?: unknown;\n pattern: string;\n rootParamNames?: readonly string[];\n routeHandler?: unknown;\n routeSegments: readonly string[];\n};\n\ntype AppRscRouteMatch<TRoute> = {\n params: AppPageParams;\n route: TRoute;\n};\n\ntype DispatchMatchedPageOptions<TRoute> = {\n cleanPathname: string;\n formState: ReactFormState | null;\n actionError?: unknown;\n actionFailed?: boolean;\n handlerStart: number;\n interceptionContext: string | null;\n isProgressiveActionRender: boolean;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n params: AppPageParams;\n rootParams?: RootParams;\n request: Request;\n route: TRoute;\n scriptNonce?: string;\n searchParams: URLSearchParams;\n renderMode: AppRscRenderMode;\n};\n\ntype DispatchMatchedRouteHandlerOptions<TRoute> = {\n cleanPathname: string;\n middlewareContext: AppRscMiddlewareContext;\n /**\n * `null` for non-dynamic routes. Mirrors Next.js' route handler context\n * shape: user code that does `params ? await params : null` resolves to\n * `null` for routes without dynamic segments. Dynamic routes receive the\n * matched params object.\n */\n params: AppPageParams | null;\n request: Request;\n route: TRoute;\n searchParams: URLSearchParams;\n};\n\ntype HandleProgressiveActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n};\n\ntype ProgressiveActionFormStateResult =\n | {\n formState: ReactFormState | null;\n kind: \"form-state\";\n }\n | {\n actionError: unknown;\n actionFailed: true;\n formState: null;\n kind: \"form-state\";\n };\n\ntype HandleServerActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n interceptionContext: string | null;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n request: Request;\n searchParams: URLSearchParams;\n};\n\ntype RenderNotFoundOptions<TRoute> = {\n isRscRequest: boolean;\n matchedParams?: AppPageParams;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n route: TRoute | null;\n scriptNonce?: string;\n};\n\ntype RenderPagesFallbackOptions = {\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n url: URL;\n};\n\ntype NavigationContextValue = {\n params: AppPageParams;\n pathname: string;\n searchParams: URLSearchParams;\n};\n\ntype CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {\n basePath: string;\n clearRequestContext: () => void;\n configHeaders: NextHeader[];\n configRedirects: NextRedirect[];\n configRewrites: {\n afterFiles: NextRewrite[];\n beforeFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n dispatchMatchedPage: (options: DispatchMatchedPageOptions<TRoute>) => Promise<Response>;\n dispatchMatchedRouteHandler: (\n options: DispatchMatchedRouteHandlerOptions<TRoute>,\n ) => Promise<Response>;\n ensureInstrumentation?: () => Promise<void>;\n handleProgressiveActionRequest: (\n options: HandleProgressiveActionRequestOptions,\n ) => Promise<Response | ProgressiveActionFormStateResult | null>;\n handleServerActionRequest: (\n options: HandleServerActionRequestOptions,\n ) => Promise<Response | null>;\n i18nConfig: NextI18nConfig | null;\n isMiddlewareProxy: boolean;\n loadPrerenderPagesRoutes?: () => Promise<unknown>;\n makeThenableParams: MakeThenableParams;\n matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;\n metadataRoutes: MetadataRoutes;\n middlewareModule: MiddlewareModule | null;\n publicFiles: ReadonlySet<string>;\n renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;\n renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;\n rootParamNamesByPattern?: RootParamNamesMap;\n setNavigationContext: (context: NavigationContextValue) => void;\n staticParamsMap: StaticParamsMap;\n trailingSlash: boolean;\n validateDevRequestOrigin?: (request: Request) => Response | null;\n};\n\nfunction hasProperty<TKey extends PropertyKey>(\n value: object,\n key: TKey,\n): value is object & Record<TKey, unknown> {\n return key in value;\n}\n\nfunction isExecutionContextLike(value: unknown): value is ExecutionContextLike {\n if (!value || typeof value !== \"object\") return false;\n return hasProperty(value, \"waitUntil\") && typeof value.waitUntil === \"function\";\n}\n\n// TODO(#1333): once App Router supports `basePath: false` rules (see\n// `normalizeRscRequest` — it 404s out-of-basePath requests before they\n// reach this code), pass `hadBasePath` here and skip the prefix when\n// false, mirroring the same guard in `prod-server.ts` and `deploy.ts`.\nfunction redirectDestinationWithBasePath(destination: string, basePath: string): string {\n if (!basePath || isExternalUrl(destination) || hasBasePath(destination, basePath)) {\n return destination;\n }\n return basePath + destination;\n}\n\nasync function applyRewrite(\n options: {\n basePathState: BasePathMatchState;\n clearRequestContext: () => void;\n request: Request;\n requestContext: RequestContext;\n rewrites: NextRewrite[];\n },\n cleanPathname: string,\n): Promise<Response | string | null> {\n if (!options.rewrites.length) return null;\n\n const rewritten = matchRewrite(\n cleanPathname,\n options.rewrites,\n options.requestContext,\n options.basePathState,\n );\n if (!rewritten) return null;\n\n if (isExternalUrl(rewritten)) {\n options.clearRequestContext();\n return proxyExternalRequest(options.request, rewritten);\n }\n\n return rewritten;\n}\n\nfunction applyConfigHeadersToMiddlewareRedirect(\n response: Response,\n options: {\n basePathState: BasePathMatchState;\n configHeaders: NextHeader[];\n pathname: string;\n requestContext: RequestContext;\n },\n): Response {\n // Non-redirect middleware responses still pass through finalization, where\n // config headers are applied once. Redirects skip finalization to avoid\n // mutating immutable redirect headers, so they need the earlier header layer here.\n if (response.status < 300 || response.status >= 400) return response;\n if (!options.configHeaders.length) return response;\n\n const headers = new Headers();\n applyConfigHeadersToResponse(headers, {\n configHeaders: options.configHeaders,\n pathname: options.pathname,\n requestContext: options.requestContext,\n basePathState: options.basePathState,\n });\n\n if (!headers.entries().next().done) {\n mergeMiddlewareResponseHeaders(headers, response.headers);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n return response;\n}\n\nasync function handleAppRscRequest<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n request: Request,\n preMiddlewareRequestContext: RequestContext,\n isDataRequest: boolean,\n): Promise<Response> {\n const handlerStart = process.env.NODE_ENV !== \"production\" ? performance.now() : 0;\n\n if (process.env.NODE_ENV !== \"production\") {\n const originBlock = options.validateDevRequestOrigin?.(request);\n if (originBlock) return originBlock;\n }\n\n const normalized = normalizeRscRequest(request, options.basePath);\n if (normalized instanceof Response) return normalized;\n\n const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader, renderMode } =\n normalized;\n let { pathname, cleanPathname } = normalized;\n // Canonical (external) pathname the user requested. Middleware rewrites and\n // next.config.js rewrites mutate `cleanPathname` so internal route matching\n // can find the destination page, but hooks like `usePathname()` must reflect\n // the original URL the user sees in the address bar.\n // Matches Next.js: test/e2e/app-dir/hooks/hooks.test.ts —\n // \"should have the canonical url pathname on rewrite\"\n const canonicalPathname = cleanPathname;\n\n // The request reached this point so it was either under basePath (stripped\n // by normalizeRscRequest) or basePath is empty. In both cases the matcher\n // gating below treats default (basePath: true) rules as eligible. The App\n // Router does not yet support `basePath: false` rules — they would need a\n // pre-strip hook in normalizeRscRequest to fire. Tracked as follow-up to\n // issue #1333.\n const basePathState = { basePath: options.basePath, hadBasePath: true };\n\n const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {\n isPrerenderEnabled() {\n return process.env.VINEXT_PRERENDER === \"1\";\n },\n loadPagesRoutes: options.loadPrerenderPagesRoutes,\n pathname,\n rootParamNamesByPattern: options.rootParamNamesByPattern,\n staticParamsMap: options.staticParamsMap,\n });\n if (prerenderEndpointResponse) return prerenderEndpointResponse;\n\n const trailingSlashRedirect = normalizeTrailingSlash(\n pathname,\n options.basePath,\n options.trailingSlash,\n url.search,\n );\n if (trailingSlashRedirect) return trailingSlashRedirect;\n\n // Default-locale path normalisation (issue #1336, item 4). Next.js\n // splices in the (domain-aware) default locale on every request that\n // arrives without a locale prefix before running config redirect / rewrite\n // / header matching. Mirrors resolve-routes.ts lines ~250-263.\n //\n // Defined once here so the same helper is reused for the redirect match\n // below, the middleware-redirect config header match further down, and the\n // post-middleware rewrite matches. `i18nConfig` and `url.hostname` are\n // request-scoped constants from this point on.\n const matchPathname = (p: string): string =>\n normalizeDefaultLocalePathname(p, options.i18nConfig, { hostname: url.hostname });\n\n const redirectPathname = matchPathname(stripRscSuffix(pathname));\n const redirect = matchRedirect(\n redirectPathname,\n options.configRedirects,\n preMiddlewareRequestContext,\n basePathState,\n );\n if (redirect) {\n const destination = sanitizeDestination(\n redirectDestinationWithBasePath(redirect.destination, options.basePath),\n );\n const location =\n isRscRequest && request.headers.get(RSC_HEADER) === \"1\"\n ? await createRscRedirectLocation(destination, request)\n : destination;\n return new Response(null, {\n status: redirect.permanent ? 308 : 307,\n headers: { Location: location },\n });\n }\n\n const rscCacheBustingRedirect = await resolveInvalidRscCacheBustingRequest({\n isRscRequest,\n request,\n });\n if (rscCacheBustingRedirect) return rscCacheBustingRedirect;\n\n const middlewareContext: AppRscMiddlewareContext = {\n headers: null,\n requestHeaders: null,\n status: null,\n };\n\n if (options.middlewareModule) {\n const middlewareResult = await applyAppMiddleware({\n basePath: options.basePath,\n cleanPathname,\n context: middlewareContext,\n i18nConfig: options.i18nConfig,\n isDataRequest,\n isProxy: options.isMiddlewareProxy,\n module: options.middlewareModule,\n request,\n trailingSlash: options.trailingSlash,\n });\n if (middlewareResult.kind === \"response\") {\n return applyConfigHeadersToMiddlewareRedirect(middlewareResult.response, {\n basePathState,\n configHeaders: options.configHeaders,\n pathname: matchPathname(cleanPathname),\n requestContext: preMiddlewareRequestContext,\n });\n }\n\n cleanPathname = middlewareResult.cleanPathname;\n if (middlewareResult.search !== null) {\n url.search = middlewareResult.search;\n }\n }\n\n const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareContext.headers);\n const postMiddlewareRequestContext = buildPostMwRequestContext(request);\n\n // Rewrites (beforeFiles, afterFiles, fallback) use `matchPathname` from\n // above to splice in the default locale before matching. Route matching\n // itself continues to use the un-prefixed `cleanPathname` because App\n // Router files live under `app/...` with no locale segment. See issue\n // #1336 item 4 / pages-i18n.normalizeDefaultLocalePathname.\n const beforeFilesRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.beforeFiles,\n },\n matchPathname(cleanPathname),\n );\n if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;\n if (beforeFilesRewrite) cleanPathname = beforeFilesRewrite;\n\n if (cleanPathname === \"/_vinext/image\") {\n const imageUrlResult = validateImageUrl(url.searchParams.get(\"url\"), request.url);\n if (imageUrlResult instanceof Response) return imageUrlResult;\n return Response.redirect(new URL(imageUrlResult, url.origin).href, 302);\n }\n\n const metadataRouteResponse = await handleMetadataRouteRequest({\n metadataRoutes: options.metadataRoutes,\n cleanPathname,\n makeThenableParams: options.makeThenableParams,\n });\n if (metadataRouteResponse) return metadataRouteResponse;\n\n const publicFileResponse = resolvePublicFileRoute({\n cleanPathname,\n middlewareContext,\n pathname,\n publicFiles: options.publicFiles,\n request,\n });\n if (publicFileResponse) {\n options.clearRequestContext();\n return publicFileResponse;\n }\n\n if (isRscRequest) {\n stripRscCacheBustingSearchParam(url);\n }\n\n options.setNavigationContext({\n pathname: canonicalPathname,\n searchParams: url.searchParams,\n params: {},\n });\n\n const actionId =\n request.headers.get(RSC_ACTION_HEADER) ?? request.headers.get(NEXT_ACTION_HEADER);\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n const progressiveActionResult = await options.handleProgressiveActionRequest({\n actionId,\n cleanPathname,\n contentType,\n middlewareContext,\n request,\n });\n if (progressiveActionResult instanceof Response) return progressiveActionResult;\n const isProgressiveActionRender = progressiveActionResult?.kind === \"form-state\";\n const formState = isProgressiveActionRender ? progressiveActionResult.formState : null;\n const failedProgressiveActionResult =\n isProgressiveActionRender && \"actionFailed\" in progressiveActionResult\n ? progressiveActionResult\n : null;\n const actionFailed = failedProgressiveActionResult !== null;\n const actionError = failedProgressiveActionResult?.actionError;\n\n const serverActionResponse = await options.handleServerActionRequest({\n actionId,\n cleanPathname,\n contentType,\n interceptionContext: interceptionContextHeader,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n request,\n searchParams: url.searchParams,\n });\n if (serverActionResponse) return serverActionResponse;\n\n let match = options.matchRoute(cleanPathname);\n if (!match || match.route.isDynamic) {\n const afterFilesRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.afterFiles,\n },\n matchPathname(cleanPathname),\n );\n if (afterFilesRewrite instanceof Response) return afterFilesRewrite;\n if (afterFilesRewrite) {\n cleanPathname = afterFilesRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n const fallbackRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.fallback,\n },\n matchPathname(cleanPathname),\n );\n if (fallbackRewrite instanceof Response) return fallbackRewrite;\n if (fallbackRewrite) {\n cleanPathname = fallbackRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n const pagesFallbackResponse = await options.renderPagesFallback?.({\n isRscRequest,\n middlewareContext,\n request,\n url,\n });\n if (pagesFallbackResponse) {\n options.clearRequestContext();\n return pagesFallbackResponse;\n }\n\n const renderedNotFoundResponse = await options.renderNotFound({\n isRscRequest,\n middlewareContext,\n request,\n route: null,\n scriptNonce,\n });\n if (renderedNotFoundResponse) return renderedNotFoundResponse;\n\n options.clearRequestContext();\n const headers = new Headers();\n mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);\n return notFoundResponse({ headers });\n }\n\n const { route, params } = match;\n options.setNavigationContext({\n pathname: canonicalPathname,\n searchParams: url.searchParams,\n params,\n });\n const rootParams = pickRootParams(params, route.rootParamNames);\n setRootParams(rootParams);\n\n if (route.routeHandler) {\n setCurrentFetchSoftTags(\n buildPageCacheTags(cleanPathname, [], [...route.routeSegments], \"route\"),\n );\n return options.dispatchMatchedRouteHandler({\n cleanPathname,\n middlewareContext,\n // Non-dynamic routes report params as `null` to match Next.js. Internal\n // bookkeeping above (navigation context, root params) keeps the matched\n // object (always `{}` for non-dynamic) so `useParams()` etc. still see\n // an object shape; only the user-facing handler context surfaces null.\n params: route.isDynamic ? params : null,\n request,\n route,\n searchParams: url.searchParams,\n });\n }\n\n return options.dispatchMatchedPage({\n cleanPathname,\n formState,\n actionError,\n actionFailed,\n handlerStart,\n interceptionContext: interceptionContextHeader,\n isProgressiveActionRender,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n params,\n rootParams,\n request,\n route,\n scriptNonce,\n searchParams: url.searchParams,\n renderMode,\n });\n}\n\nexport function createAppRscHandler<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n): (request: Request, ctx: unknown) => Promise<Response> {\n return async function appRscHandler(rawRequest, ctx) {\n await options.ensureInstrumentation?.();\n\n // Strip forged internal headers at the App Router request boundary.\n // Must happen BEFORE headersContextFromRequest() and\n // requestContextFromRequest() so the captured context never contains\n // attacker-controlled internal headers. This is the correct boundary\n // for pure App Router requests; in hybrid app+pages mode the connect\n // handler already filtered headers upstream and x-vinext-mw-ctx\n // (not in INTERNAL_HEADERS) carries the forwarded middleware context.\n // srvx's NodeRequestHeaders reads from rawHeaders for iteration but falls\n // back to req.headers for .get() / .has(). In the dev server we add\n // x-vinext-mw-ctx to req.headers after the Request is built, so it is\n // visible to .get() but lost when filterInternalHeaders iterates. Read it\n // BEFORE iterating so applyForwardedMiddlewareContext can skip middleware.\n const mwCtx = rawRequest.headers.get(VINEXT_MW_CTX_HEADER);\n // Capture `x-nextjs-data` before filtering — the middleware redirect\n // protocol needs to know whether the inbound request was a `_next/data`\n // fetch to emit `x-nextjs-redirect` instead of an HTTP redirect.\n const isDataRequest = rawRequest.headers.get(\"x-nextjs-data\") === \"1\";\n const filteredHeaders = filterInternalHeaders(rawRequest.headers);\n if (mwCtx !== null) {\n filteredHeaders.set(VINEXT_MW_CTX_HEADER, mwCtx);\n }\n const request = cloneRequestWithHeaders(rawRequest, filteredHeaders);\n\n const executionContext = isExecutionContextLike(ctx)\n ? ctx\n : (getRequestExecutionContext() ?? null);\n const headersContext = headersContextFromRequest(request);\n const requestContext = createRequestContext({\n headersContext,\n executionContext,\n unstableCacheRevalidation: \"background\",\n });\n\n return runWithRequestContext(requestContext, () =>\n runWithPrerenderWorkUnit(\n async () => {\n ensureFetchPatch();\n const preMiddlewareRequestContext = requestContextFromRequest(request);\n let response: Response;\n\n try {\n response = await handleAppRscRequest(\n options,\n request,\n preMiddlewareRequestContext,\n isDataRequest,\n );\n } catch (error) {\n if (process.env.NODE_ENV !== \"production\") {\n flattenErrorCauses(error);\n }\n throw error;\n }\n\n return finalizeAppRscResponse(response, request, {\n basePath: options.basePath,\n configHeaders: options.configHeaders,\n i18nConfig: options.i18nConfig,\n requestContext: preMiddlewareRequestContext,\n });\n },\n { route: () => new URL(request.url).pathname },\n ),\n );\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAqNA,SAAS,YACP,OACA,KACyC;CACzC,OAAO,OAAO;;AAGhB,SAAS,uBAAuB,OAA+C;CAC7E,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO;CAChD,OAAO,YAAY,OAAO,YAAY,IAAI,OAAO,MAAM,cAAc;;AAOvE,SAAS,gCAAgC,aAAqB,UAA0B;CACtF,IAAI,CAAC,YAAY,cAAc,YAAY,IAAI,YAAY,aAAa,SAAS,EAC/E,OAAO;CAET,OAAO,WAAW;;AAGpB,eAAe,aACb,SAOA,eACmC;CACnC,IAAI,CAAC,QAAQ,SAAS,QAAQ,OAAO;CAErC,MAAM,YAAY,aAChB,eACA,QAAQ,UACR,QAAQ,gBACR,QAAQ,cACT;CACD,IAAI,CAAC,WAAW,OAAO;CAEvB,IAAI,cAAc,UAAU,EAAE;EAC5B,QAAQ,qBAAqB;EAC7B,OAAO,qBAAqB,QAAQ,SAAS,UAAU;;CAGzD,OAAO;;AAGT,SAAS,uCACP,UACA,SAMU;CAIV,IAAI,SAAS,SAAS,OAAO,SAAS,UAAU,KAAK,OAAO;CAC5D,IAAI,CAAC,QAAQ,cAAc,QAAQ,OAAO;CAE1C,MAAM,UAAU,IAAI,SAAS;CAC7B,6BAA6B,SAAS;EACpC,eAAe,QAAQ;EACvB,UAAU,QAAQ;EAClB,gBAAgB,QAAQ;EACxB,eAAe,QAAQ;EACxB,CAAC;CAEF,IAAI,CAAC,QAAQ,SAAS,CAAC,MAAM,CAAC,MAAM;EAClC,+BAA+B,SAAS,SAAS,QAAQ;EACzD,OAAO,IAAI,SAAS,SAAS,MAAM;GACjC,QAAQ,SAAS;GACjB,YAAY,SAAS;GACrB;GACD,CAAC;;CAGJ,OAAO;;AAGT,eAAe,oBACb,SACA,SACA,6BACA,eACmB;CACnB,MAAM,eAAe,QAAQ,IAAI,aAAa,eAAe,YAAY,KAAK,GAAG;CAEjF,IAAI,QAAQ,IAAI,aAAa,cAAc;EACzC,MAAM,cAAc,QAAQ,2BAA2B,QAAQ;EAC/D,IAAI,aAAa,OAAO;;CAG1B,MAAM,aAAa,oBAAoB,SAAS,QAAQ,SAAS;CACjE,IAAI,sBAAsB,UAAU,OAAO;CAE3C,MAAM,EAAE,KAAK,cAAc,2BAA2B,oBAAoB,eACxE;CACF,IAAI,EAAE,UAAU,kBAAkB;CAOlC,MAAM,oBAAoB;CAQ1B,MAAM,gBAAgB;EAAE,UAAU,QAAQ;EAAU,aAAa;EAAM;CAEvE,MAAM,4BAA4B,MAAM,2BAA2B,SAAS;EAC1E,qBAAqB;GACnB,OAAO,QAAQ,IAAI,qBAAqB;;EAE1C,iBAAiB,QAAQ;EACzB;EACA,yBAAyB,QAAQ;EACjC,iBAAiB,QAAQ;EAC1B,CAAC;CACF,IAAI,2BAA2B,OAAO;CAEtC,MAAM,wBAAwB,uBAC5B,UACA,QAAQ,UACR,QAAQ,eACR,IAAI,OACL;CACD,IAAI,uBAAuB,OAAO;CAWlC,MAAM,iBAAiB,MACrB,+BAA+B,GAAG,QAAQ,YAAY,EAAE,UAAU,IAAI,UAAU,CAAC;CAGnF,MAAM,WAAW,cADQ,cAAc,eAAe,SAAS,CAE7C,EAChB,QAAQ,iBACR,6BACA,cACD;CACD,IAAI,UAAU;EACZ,MAAM,cAAc,oBAClB,gCAAgC,SAAS,aAAa,QAAQ,SAAS,CACxE;EACD,MAAM,WACJ,gBAAgB,QAAQ,QAAQ,IAAA,MAAe,KAAK,MAChD,MAAM,0BAA0B,aAAa,QAAQ,GACrD;EACN,OAAO,IAAI,SAAS,MAAM;GACxB,QAAQ,SAAS,YAAY,MAAM;GACnC,SAAS,EAAE,UAAU,UAAU;GAChC,CAAC;;CAGJ,MAAM,0BAA0B,MAAM,qCAAqC;EACzE;EACA;EACD,CAAC;CACF,IAAI,yBAAyB,OAAO;CAEpC,MAAM,oBAA6C;EACjD,SAAS;EACT,gBAAgB;EAChB,QAAQ;EACT;CAED,IAAI,QAAQ,kBAAkB;EAC5B,MAAM,mBAAmB,MAAM,mBAAmB;GAChD,UAAU,QAAQ;GAClB;GACA,SAAS;GACT,YAAY,QAAQ;GACpB;GACA,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB;GACA,eAAe,QAAQ;GACxB,CAAC;EACF,IAAI,iBAAiB,SAAS,YAC5B,OAAO,uCAAuC,iBAAiB,UAAU;GACvE;GACA,eAAe,QAAQ;GACvB,UAAU,cAAc,cAAc;GACtC,gBAAgB;GACjB,CAAC;EAGJ,gBAAgB,iBAAiB;EACjC,IAAI,iBAAiB,WAAW,MAC9B,IAAI,SAAS,iBAAiB;;CAIlC,MAAM,cAAc,gCAAgC,QAAQ,SAAS,kBAAkB,QAAQ;CAC/F,MAAM,+BAA+B,0BAA0B,QAAQ;CAOvE,MAAM,qBAAqB,MAAM,aAC/B;EACE;EACA,qBAAqB,QAAQ;EAC7B;EACA,gBAAgB;EAChB,UAAU,QAAQ,eAAe;EAClC,EACD,cAAc,cAAc,CAC7B;CACD,IAAI,8BAA8B,UAAU,OAAO;CACnD,IAAI,oBAAoB,gBAAgB;CAExC,IAAI,kBAAkB,kBAAkB;EACtC,MAAM,iBAAiB,iBAAiB,IAAI,aAAa,IAAI,MAAM,EAAE,QAAQ,IAAI;EACjF,IAAI,0BAA0B,UAAU,OAAO;EAC/C,OAAO,SAAS,SAAS,IAAI,IAAI,gBAAgB,IAAI,OAAO,CAAC,MAAM,IAAI;;CAGzE,MAAM,wBAAwB,MAAM,2BAA2B;EAC7D,gBAAgB,QAAQ;EACxB;EACA,oBAAoB,QAAQ;EAC7B,CAAC;CACF,IAAI,uBAAuB,OAAO;CAElC,MAAM,qBAAqB,uBAAuB;EAChD;EACA;EACA;EACA,aAAa,QAAQ;EACrB;EACD,CAAC;CACF,IAAI,oBAAoB;EACtB,QAAQ,qBAAqB;EAC7B,OAAO;;CAGT,IAAI,cACF,gCAAgC,IAAI;CAGtC,QAAQ,qBAAqB;EAC3B,UAAU;EACV,cAAc,IAAI;EAClB,QAAQ,EAAE;EACX,CAAC;CAEF,MAAM,WACJ,QAAQ,QAAQ,IAAA,eAAsB,IAAI,QAAQ,QAAQ,IAAA,cAAuB;CACnF,MAAM,cAAc,QAAQ,QAAQ,IAAI,eAAe,IAAI;CAE3D,MAAM,0BAA0B,MAAM,QAAQ,+BAA+B;EAC3E;EACA;EACA;EACA;EACA;EACD,CAAC;CACF,IAAI,mCAAmC,UAAU,OAAO;CACxD,MAAM,4BAA4B,yBAAyB,SAAS;CACpE,MAAM,YAAY,4BAA4B,wBAAwB,YAAY;CAClF,MAAM,gCACJ,6BAA6B,kBAAkB,0BAC3C,0BACA;CACN,MAAM,eAAe,kCAAkC;CACvD,MAAM,cAAc,+BAA+B;CAEnD,MAAM,uBAAuB,MAAM,QAAQ,0BAA0B;EACnE;EACA;EACA;EACA,qBAAqB;EACrB;EACA;EACA;EACA;EACA,cAAc,IAAI;EACnB,CAAC;CACF,IAAI,sBAAsB,OAAO;CAEjC,IAAI,QAAQ,QAAQ,WAAW,cAAc;CAC7C,IAAI,CAAC,SAAS,MAAM,MAAM,WAAW;EACnC,MAAM,oBAAoB,MAAM,aAC9B;GACE;GACA,qBAAqB,QAAQ;GAC7B;GACA,gBAAgB;GAChB,UAAU,QAAQ,eAAe;GAClC,EACD,cAAc,cAAc,CAC7B;EACD,IAAI,6BAA6B,UAAU,OAAO;EAClD,IAAI,mBAAmB;GACrB,gBAAgB;GAChB,QAAQ,QAAQ,WAAW,cAAc;;;CAI7C,IAAI,CAAC,OAAO;EACV,MAAM,kBAAkB,MAAM,aAC5B;GACE;GACA,qBAAqB,QAAQ;GAC7B;GACA,gBAAgB;GAChB,UAAU,QAAQ,eAAe;GAClC,EACD,cAAc,cAAc,CAC7B;EACD,IAAI,2BAA2B,UAAU,OAAO;EAChD,IAAI,iBAAiB;GACnB,gBAAgB;GAChB,QAAQ,QAAQ,WAAW,cAAc;;;CAI7C,IAAI,CAAC,OAAO;EACV,MAAM,wBAAwB,MAAM,QAAQ,sBAAsB;GAChE;GACA;GACA;GACA;GACD,CAAC;EACF,IAAI,uBAAuB;GACzB,QAAQ,qBAAqB;GAC7B,OAAO;;EAGT,MAAM,2BAA2B,MAAM,QAAQ,eAAe;GAC5D;GACA;GACA;GACA,OAAO;GACP;GACD,CAAC;EACF,IAAI,0BAA0B,OAAO;EAErC,QAAQ,qBAAqB;EAC7B,MAAM,UAAU,IAAI,SAAS;EAC7B,+BAA+B,SAAS,kBAAkB,QAAQ;EAClE,OAAO,iBAAiB,EAAE,SAAS,CAAC;;CAGtC,MAAM,EAAE,OAAO,WAAW;CAC1B,QAAQ,qBAAqB;EAC3B,UAAU;EACV,cAAc,IAAI;EAClB;EACD,CAAC;CACF,MAAM,aAAa,eAAe,QAAQ,MAAM,eAAe;CAC/D,cAAc,WAAW;CAEzB,IAAI,MAAM,cAAc;EACtB,wBACE,mBAAmB,eAAe,EAAE,EAAE,CAAC,GAAG,MAAM,cAAc,EAAE,QAAQ,CACzE;EACD,OAAO,QAAQ,4BAA4B;GACzC;GACA;GAKA,QAAQ,MAAM,YAAY,SAAS;GACnC;GACA;GACA,cAAc,IAAI;GACnB,CAAC;;CAGJ,OAAO,QAAQ,oBAAoB;EACjC;EACA;EACA;EACA;EACA;EACA,qBAAqB;EACrB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cAAc,IAAI;EAClB;EACD,CAAC;;AAGJ,SAAgB,oBACd,SACuD;CACvD,OAAO,eAAe,cAAc,YAAY,KAAK;EACnD,MAAM,QAAQ,yBAAyB;EAcvC,MAAM,QAAQ,WAAW,QAAQ,IAAI,qBAAqB;EAI1D,MAAM,gBAAgB,WAAW,QAAQ,IAAI,gBAAgB,KAAK;EAClE,MAAM,kBAAkB,sBAAsB,WAAW,QAAQ;EACjE,IAAI,UAAU,MACZ,gBAAgB,IAAI,sBAAsB,MAAM;EAElD,MAAM,UAAU,wBAAwB,YAAY,gBAAgB;EAEpE,MAAM,mBAAmB,uBAAuB,IAAI,GAChD,MACC,4BAA4B,IAAI;EAQrC,OAAO,sBANgB,qBAAqB;GAC1C,gBAFqB,0BAA0B,QAEjC;GACd;GACA,2BAA2B;GAC5B,CAE0C,QACzC,yBACE,YAAY;GACV,kBAAkB;GAClB,MAAM,8BAA8B,0BAA0B,QAAQ;GACtE,IAAI;GAEJ,IAAI;IACF,WAAW,MAAM,oBACf,SACA,SACA,6BACA,cACD;YACM,OAAO;IACd,IAAI,QAAQ,IAAI,aAAa,cAC3B,mBAAmB,MAAM;IAE3B,MAAM;;GAGR,OAAO,uBAAuB,UAAU,SAAS;IAC/C,UAAU,QAAQ;IAClB,eAAe,QAAQ;IACvB,YAAY,QAAQ;IACpB,gBAAgB;IACjB,CAAC;KAEJ,EAAE,aAAa,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,CAC/C,CACF"}
|
|
1
|
+
{"version":3,"file":"app-rsc-handler.js","names":[],"sources":["../../src/server/app-rsc-handler.ts"],"sourcesContent":["import type {\n NextHeader,\n NextI18nConfig,\n NextRedirect,\n NextRewrite,\n} from \"../config/next-config.js\";\nimport {\n isExternalUrl,\n matchRedirect,\n matchRewrite,\n proxyExternalRequest,\n requestContextFromRequest,\n sanitizeDestination,\n type BasePathMatchState,\n} from \"../config/config-matchers.js\";\nimport { headersContextFromRequest } from \"vinext/shims/headers\";\nimport {\n ACTION_REVALIDATED_HEADER,\n NEXT_ACTION_HEADER,\n RSC_ACTION_HEADER,\n RSC_HEADER,\n VINEXT_MW_CTX_HEADER,\n VINEXT_PRERENDER_ROUTE_PARAMS_HEADER,\n} from \"./headers.js\";\nimport { ensureFetchPatch, setCurrentFetchSoftTags } from \"vinext/shims/fetch-cache\";\nimport type { ReactFormState } from \"react-dom/client\";\nimport {\n getRequestExecutionContext,\n type ExecutionContextLike,\n} from \"vinext/shims/request-context\";\nimport { pickRootParams, setRootParams, type RootParams } from \"vinext/shims/root-params\";\nimport { createRequestContext, runWithRequestContext } from \"vinext/shims/unified-request-context\";\nimport { flattenErrorCauses } from \"../utils/error-cause.js\";\nimport { hasBasePath } from \"../utils/base-path.js\";\nimport { applyAppMiddleware, type AppMiddlewareContext } from \"./app-middleware.js\";\nimport { mergeMiddlewareResponseHeaders } from \"./app-page-response.js\";\nimport { handleAppPrerenderEndpoint } from \"./app-prerender-endpoints.js\";\nimport {\n createRscRedirectLocation,\n resolveInvalidRscCacheBustingRequest,\n stripRscCacheBustingSearchParam,\n stripRscSuffix,\n} from \"./app-rsc-cache-busting.js\";\nimport { finalizeAppRscResponse } from \"./app-rsc-response-finalizer.js\";\nimport { normalizeRscRequest } from \"./app-rsc-request-normalization.js\";\nimport { normalizeDefaultLocalePathname } from \"./pages-i18n.js\";\nimport { notFoundResponse } from \"./http-error-responses.js\";\nimport { getScriptNonceFromHeaderSources } from \"./csp.js\";\nimport { buildPageCacheTags } from \"./implicit-tags.js\";\nimport { isImageOptimizationPath } from \"./image-optimization.js\";\nimport { handleMetadataRouteRequest } from \"./metadata-route-response.js\";\nimport type { MiddlewareModule } from \"./middleware-runtime.js\";\nimport { runWithPrerenderWorkUnit } from \"./prerender-work-unit-setup.js\";\nimport { buildPostMwRequestContext } from \"./app-post-middleware-context.js\";\nimport type { AppRscRenderMode } from \"./app-rsc-render-mode.js\";\nimport {\n cloneRequestWithHeaders,\n filterInternalHeaders,\n applyConfigHeadersToResponse,\n normalizeTrailingSlash,\n resolvePublicFileRoute,\n validateImageUrl,\n} from \"./request-pipeline.js\";\nimport {\n prerenderRouteParamsPayloadMatchesRoute,\n readTrustedPrerenderRouteParams,\n serializePrerenderRouteParamsHeader,\n} from \"./prerender-route-params.js\";\n\ntype AppPageParams = Record<string, string | string[]>;\ntype RequestContext = ReturnType<typeof requestContextFromRequest>;\ntype MetadataRoutes = Parameters<typeof handleMetadataRouteRequest>[0][\"metadataRoutes\"];\ntype MakeThenableParams = Parameters<typeof handleMetadataRouteRequest>[0][\"makeThenableParams\"];\ntype StaticParamsMap = Parameters<typeof handleAppPrerenderEndpoint>[1][\"staticParamsMap\"];\ntype RootParamNamesMap = Parameters<\n typeof handleAppPrerenderEndpoint\n>[1][\"rootParamNamesByPattern\"];\n\ntype AppRscMiddlewareContext = AppMiddlewareContext;\n\ntype AppRscHandlerRoute = {\n isDynamic: boolean;\n page?: unknown;\n pattern: string;\n rootParamNames?: readonly string[];\n routeHandler?: unknown;\n routeSegments: readonly string[];\n};\n\ntype AppRscRouteMatch<TRoute> = {\n params: AppPageParams;\n route: TRoute;\n};\n\ntype DispatchMatchedPageOptions<TRoute> = {\n cleanPathname: string;\n formState: ReactFormState | null;\n actionError?: unknown;\n actionFailed?: boolean;\n handlerStart: number;\n interceptionContext: string | null;\n isProgressiveActionRender: boolean;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n params: AppPageParams;\n staticParamsValidationParams?: AppPageParams;\n rootParams?: RootParams;\n request: Request;\n route: TRoute;\n scriptNonce?: string;\n searchParams: URLSearchParams;\n renderMode: AppRscRenderMode;\n};\n\ntype DispatchMatchedRouteHandlerOptions<TRoute> = {\n cleanPathname: string;\n middlewareContext: AppRscMiddlewareContext;\n /**\n * `null` for non-dynamic routes. Mirrors Next.js' route handler context\n * shape: user code that does `params ? await params : null` resolves to\n * `null` for routes without dynamic segments. Dynamic routes receive the\n * matched params object.\n */\n params: AppPageParams | null;\n request: Request;\n route: TRoute;\n searchParams: URLSearchParams;\n};\n\ntype HandleProgressiveActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n};\n\n/**\n * Side-effect headers captured during a progressive (no-JS) server action's\n * non-redirect execution. Forwarded onto the page render response so that\n * `cookies().set(...)` and revalidation kinds reach the browser. See\n * `app-server-action-execution.ts` and issue #1483 for the full rationale.\n */\ntype ProgressiveActionSideEffects = {\n pendingCookies: string[];\n draftCookie: string | null | undefined;\n /** Numeric revalidation kind: `0` (none), `1` (static+dynamic), etc. */\n revalidationKind: number;\n};\n\ntype ProgressiveActionFormStateResult =\n | ({\n formState: ReactFormState | null;\n kind: \"form-state\";\n } & ProgressiveActionSideEffects)\n | ({\n actionError: unknown;\n actionFailed: true;\n formState: null;\n kind: \"form-state\";\n } & ProgressiveActionSideEffects);\n\ntype HandleServerActionRequestOptions = {\n actionId: string | null;\n cleanPathname: string;\n contentType: string;\n interceptionContext: string | null;\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n mountedSlotsHeader: string | null;\n request: Request;\n searchParams: URLSearchParams;\n};\n\ntype RenderNotFoundOptions<TRoute> = {\n isRscRequest: boolean;\n matchedParams?: AppPageParams;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n route: TRoute | null;\n scriptNonce?: string;\n};\n\ntype RenderPagesFallbackOptions = {\n isRscRequest: boolean;\n middlewareContext: AppRscMiddlewareContext;\n request: Request;\n url: URL;\n};\n\ntype NavigationContextValue = {\n params: AppPageParams;\n pathname: string;\n searchParams: URLSearchParams;\n};\n\ntype CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {\n basePath: string;\n clearRequestContext: () => void;\n configHeaders: NextHeader[];\n configRedirects: NextRedirect[];\n configRewrites: {\n afterFiles: NextRewrite[];\n beforeFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n draftModeSecret: string;\n dispatchMatchedPage: (options: DispatchMatchedPageOptions<TRoute>) => Promise<Response>;\n dispatchMatchedRouteHandler: (\n options: DispatchMatchedRouteHandlerOptions<TRoute>,\n ) => Promise<Response>;\n ensureInstrumentation?: () => Promise<void>;\n handleProgressiveActionRequest: (\n options: HandleProgressiveActionRequestOptions,\n ) => Promise<Response | ProgressiveActionFormStateResult | null>;\n handleServerActionRequest: (\n options: HandleServerActionRequestOptions,\n ) => Promise<Response | null>;\n i18nConfig: NextI18nConfig | null;\n isMiddlewareProxy: boolean;\n loadPrerenderPagesRoutes?: () => Promise<unknown>;\n makeThenableParams: MakeThenableParams;\n matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;\n metadataRoutes: MetadataRoutes;\n middlewareModule: MiddlewareModule | null;\n publicFiles: ReadonlySet<string>;\n renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;\n renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;\n rootParamNamesByPattern?: RootParamNamesMap;\n setNavigationContext: (context: NavigationContextValue) => void;\n staticParamsMap: StaticParamsMap;\n trailingSlash: boolean;\n validateDevRequestOrigin?: (request: Request) => Response | null;\n};\n\nfunction hasProperty<TKey extends PropertyKey>(\n value: object,\n key: TKey,\n): value is object & Record<TKey, unknown> {\n return key in value;\n}\n\nfunction isExecutionContextLike(value: unknown): value is ExecutionContextLike {\n if (!value || typeof value !== \"object\") return false;\n return hasProperty(value, \"waitUntil\") && typeof value.waitUntil === \"function\";\n}\n\n// TODO(#1333): once App Router supports `basePath: false` rules (see\n// `normalizeRscRequest` — it 404s out-of-basePath requests before they\n// reach this code), pass `hadBasePath` here and skip the prefix when\n// false, mirroring the same guard in `prod-server.ts` and `deploy.ts`.\nfunction redirectDestinationWithBasePath(destination: string, basePath: string): string {\n if (!basePath || isExternalUrl(destination) || hasBasePath(destination, basePath)) {\n return destination;\n }\n return basePath + destination;\n}\n\nasync function applyRewrite(\n options: {\n basePathState: BasePathMatchState;\n clearRequestContext: () => void;\n request: Request;\n requestContext: RequestContext;\n rewrites: NextRewrite[];\n },\n cleanPathname: string,\n): Promise<Response | string | null> {\n if (!options.rewrites.length) return null;\n\n const rewritten = matchRewrite(\n cleanPathname,\n options.rewrites,\n options.requestContext,\n options.basePathState,\n );\n if (!rewritten) return null;\n\n if (isExternalUrl(rewritten)) {\n options.clearRequestContext();\n return proxyExternalRequest(options.request, rewritten);\n }\n\n return rewritten;\n}\n\nfunction applyConfigHeadersToMiddlewareRedirect(\n response: Response,\n options: {\n basePathState: BasePathMatchState;\n configHeaders: NextHeader[];\n pathname: string;\n requestContext: RequestContext;\n },\n): Response {\n // Non-redirect middleware responses still pass through finalization, where\n // config headers are applied once. Redirects skip finalization to avoid\n // mutating immutable redirect headers, so they need the earlier header layer here.\n if (response.status < 300 || response.status >= 400) return response;\n if (!options.configHeaders.length) return response;\n\n const headers = new Headers();\n applyConfigHeadersToResponse(headers, {\n configHeaders: options.configHeaders,\n pathname: options.pathname,\n requestContext: options.requestContext,\n basePathState: options.basePathState,\n });\n\n if (!headers.entries().next().done) {\n mergeMiddlewareResponseHeaders(headers, response.headers);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n return response;\n}\n\nasync function handleAppRscRequest<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n request: Request,\n preMiddlewareRequestContext: RequestContext,\n isDataRequest: boolean,\n): Promise<Response> {\n const handlerStart = process.env.NODE_ENV !== \"production\" ? performance.now() : 0;\n\n if (process.env.NODE_ENV !== \"production\") {\n const originBlock = options.validateDevRequestOrigin?.(request);\n if (originBlock) return originBlock;\n }\n\n const normalized = normalizeRscRequest(request, options.basePath);\n if (normalized instanceof Response) return normalized;\n\n const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader, renderMode } =\n normalized;\n let { pathname, cleanPathname } = normalized;\n // Canonical (external) pathname the user requested. Middleware rewrites and\n // next.config.js rewrites mutate `cleanPathname` so internal route matching\n // can find the destination page, but hooks like `usePathname()` must reflect\n // the original URL the user sees in the address bar.\n // Matches Next.js: test/e2e/app-dir/hooks/hooks.test.ts —\n // \"should have the canonical url pathname on rewrite\"\n const canonicalPathname = cleanPathname;\n\n // The request reached this point so it was either under basePath (stripped\n // by normalizeRscRequest) or basePath is empty. In both cases the matcher\n // gating below treats default (basePath: true) rules as eligible. The App\n // Router does not yet support `basePath: false` rules — they would need a\n // pre-strip hook in normalizeRscRequest to fire. Tracked as follow-up to\n // issue #1333.\n const basePathState = { basePath: options.basePath, hadBasePath: true };\n\n const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {\n isPrerenderEnabled() {\n return process.env.VINEXT_PRERENDER === \"1\";\n },\n loadPagesRoutes: options.loadPrerenderPagesRoutes,\n pathname,\n rootParamNamesByPattern: options.rootParamNamesByPattern,\n staticParamsMap: options.staticParamsMap,\n });\n if (prerenderEndpointResponse) return prerenderEndpointResponse;\n\n const trailingSlashRedirect = normalizeTrailingSlash(\n pathname,\n options.basePath,\n options.trailingSlash,\n url.search,\n );\n if (trailingSlashRedirect) return trailingSlashRedirect;\n\n // Default-locale path normalisation (issue #1336, item 4). Next.js\n // splices in the (domain-aware) default locale on every request that\n // arrives without a locale prefix before running config redirect / rewrite\n // / header matching. Mirrors resolve-routes.ts lines ~250-263.\n //\n // Defined once here so the same helper is reused for the redirect match\n // below, the middleware-redirect config header match further down, and the\n // post-middleware rewrite matches. `i18nConfig` and `url.hostname` are\n // request-scoped constants from this point on.\n const matchPathname = (p: string): string =>\n normalizeDefaultLocalePathname(p, options.i18nConfig, { hostname: url.hostname });\n\n const redirectPathname = matchPathname(stripRscSuffix(pathname));\n const redirect = matchRedirect(\n redirectPathname,\n options.configRedirects,\n preMiddlewareRequestContext,\n basePathState,\n );\n if (redirect) {\n const destination = sanitizeDestination(\n redirectDestinationWithBasePath(redirect.destination, options.basePath),\n );\n const location =\n isRscRequest && request.headers.get(RSC_HEADER) === \"1\"\n ? await createRscRedirectLocation(destination, request)\n : destination;\n return new Response(null, {\n status: redirect.permanent ? 308 : 307,\n headers: { Location: location },\n });\n }\n\n const rscCacheBustingRedirect = await resolveInvalidRscCacheBustingRequest({\n isRscRequest,\n request,\n });\n if (rscCacheBustingRedirect) return rscCacheBustingRedirect;\n\n const middlewareContext: AppRscMiddlewareContext = {\n headers: null,\n requestHeaders: null,\n status: null,\n };\n\n if (options.middlewareModule) {\n const middlewareResult = await applyAppMiddleware({\n basePath: options.basePath,\n cleanPathname,\n context: middlewareContext,\n i18nConfig: options.i18nConfig,\n isDataRequest,\n isProxy: options.isMiddlewareProxy,\n module: options.middlewareModule,\n request,\n trailingSlash: options.trailingSlash,\n });\n if (middlewareResult.kind === \"response\") {\n return applyConfigHeadersToMiddlewareRedirect(middlewareResult.response, {\n basePathState,\n configHeaders: options.configHeaders,\n pathname: matchPathname(cleanPathname),\n requestContext: preMiddlewareRequestContext,\n });\n }\n\n cleanPathname = middlewareResult.cleanPathname;\n if (middlewareResult.search !== null) {\n url.search = middlewareResult.search;\n }\n }\n\n const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareContext.headers);\n const postMiddlewareRequestContext = buildPostMwRequestContext(request);\n\n // Rewrites (beforeFiles, afterFiles, fallback) use `matchPathname` from\n // above to splice in the default locale before matching. Route matching\n // itself continues to use the un-prefixed `cleanPathname` because App\n // Router files live under `app/...` with no locale segment. See issue\n // #1336 item 4 / pages-i18n.normalizeDefaultLocalePathname.\n const beforeFilesRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.beforeFiles,\n },\n matchPathname(cleanPathname),\n );\n if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;\n if (beforeFilesRewrite) cleanPathname = beforeFilesRewrite;\n\n if (isImageOptimizationPath(cleanPathname)) {\n const imageUrlResult = validateImageUrl(url.searchParams.get(\"url\"), request.url);\n if (imageUrlResult instanceof Response) return imageUrlResult;\n return Response.redirect(new URL(imageUrlResult, url.origin).href, 302);\n }\n\n const metadataRouteResponse = await handleMetadataRouteRequest({\n metadataRoutes: options.metadataRoutes,\n cleanPathname,\n makeThenableParams: options.makeThenableParams,\n });\n if (metadataRouteResponse) return metadataRouteResponse;\n\n const publicFileResponse = resolvePublicFileRoute({\n cleanPathname,\n middlewareContext,\n pathname,\n publicFiles: options.publicFiles,\n request,\n });\n if (publicFileResponse) {\n options.clearRequestContext();\n return publicFileResponse;\n }\n\n if (isRscRequest) {\n stripRscCacheBustingSearchParam(url);\n }\n\n options.setNavigationContext({\n pathname: canonicalPathname,\n searchParams: url.searchParams,\n params: {},\n });\n\n // Eagerly seed `setRootParams` from the current cleanPathname before any\n // action dispatch so that user code which reads `unstable_rootParams()`\n // inside route handlers, `\"use cache\"` functions, and the page rerender\n // that follows a successful server action observes the matched layout's\n // root params. Without this seeding the rootParams remain null until the\n // post-action match block below runs, which is too late for action\n // execution and route-handler dispatch (both happen earlier).\n //\n // The route is matched against the pre-rewrite cleanPathname here. If the\n // afterFiles / fallback rewrites further down land on a different route,\n // the second `setRootParams` call below replaces this value before the\n // page renders, so there is no stale-value risk for ordinary page renders.\n // For action requests we intentionally do not re-run rewrites — actions\n // are always processed against the cleanPathname they were posted to.\n const preActionMatch = options.matchRoute(cleanPathname);\n if (preActionMatch) {\n setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));\n }\n\n const actionId =\n request.headers.get(RSC_ACTION_HEADER) ?? request.headers.get(NEXT_ACTION_HEADER);\n const contentType = request.headers.get(\"content-type\") || \"\";\n\n const progressiveActionResult = await options.handleProgressiveActionRequest({\n actionId,\n cleanPathname,\n contentType,\n middlewareContext,\n request,\n });\n if (progressiveActionResult instanceof Response) return progressiveActionResult;\n const isProgressiveActionRender = progressiveActionResult?.kind === \"form-state\";\n const formState = isProgressiveActionRender ? progressiveActionResult.formState : null;\n const failedProgressiveActionResult =\n isProgressiveActionRender && \"actionFailed\" in progressiveActionResult\n ? progressiveActionResult\n : null;\n const actionFailed = failedProgressiveActionResult !== null;\n const actionError = failedProgressiveActionResult?.actionError;\n\n const serverActionResponse = await options.handleServerActionRequest({\n actionId,\n cleanPathname,\n contentType,\n interceptionContext: interceptionContextHeader,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n request,\n searchParams: url.searchParams,\n });\n if (serverActionResponse) return serverActionResponse;\n\n let match = preActionMatch;\n if (!match || match.route.isDynamic) {\n const afterFilesRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.afterFiles,\n },\n matchPathname(cleanPathname),\n );\n if (afterFilesRewrite instanceof Response) return afterFilesRewrite;\n if (afterFilesRewrite) {\n cleanPathname = afterFilesRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n const fallbackRewrite = await applyRewrite(\n {\n basePathState,\n clearRequestContext: options.clearRequestContext,\n request,\n requestContext: postMiddlewareRequestContext,\n rewrites: options.configRewrites.fallback,\n },\n matchPathname(cleanPathname),\n );\n if (fallbackRewrite instanceof Response) return fallbackRewrite;\n if (fallbackRewrite) {\n cleanPathname = fallbackRewrite;\n match = options.matchRoute(cleanPathname);\n }\n }\n\n if (!match) {\n // Dev-only favicon short-circuit: browsers auto-request /favicon.ico on\n // every page load. Don't compile/render the not-found page for it.\n // Check `canonicalPathname` (the original browser-requested URL) so a\n // middleware rewrite that lands on `/favicon.ico` still falls through to\n // the normal not-found render.\n // Matches Next.js: packages/next/src/server/lib/router-server.ts —\n // condition `parsedUrl.pathname === '/favicon.ico'`.\n if (process.env.NODE_ENV !== \"production\" && canonicalPathname === \"/favicon.ico\") {\n options.clearRequestContext();\n return new Response(\"\", { status: 404 });\n }\n\n const pagesFallbackResponse = await options.renderPagesFallback?.({\n isRscRequest,\n middlewareContext,\n request,\n url,\n });\n if (pagesFallbackResponse) {\n options.clearRequestContext();\n return pagesFallbackResponse;\n }\n\n const renderedNotFoundResponse = await options.renderNotFound({\n isRscRequest,\n middlewareContext,\n request,\n route: null,\n scriptNonce,\n });\n if (renderedNotFoundResponse) return renderedNotFoundResponse;\n\n options.clearRequestContext();\n const headers = new Headers();\n mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);\n return notFoundResponse({ headers });\n }\n\n const { route, params } = match;\n const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(request);\n const prerenderRouteParams = prerenderRouteParamsPayloadMatchesRoute(\n prerenderRouteParamsPayload,\n route.pattern,\n params,\n )\n ? prerenderRouteParamsPayload.params\n : null;\n const renderParams = prerenderRouteParams ?? params;\n options.setNavigationContext({\n pathname: canonicalPathname,\n searchParams: url.searchParams,\n params: renderParams,\n });\n const rootParams = pickRootParams(renderParams, route.rootParamNames);\n setRootParams(rootParams);\n\n if (route.routeHandler) {\n setCurrentFetchSoftTags(\n buildPageCacheTags(cleanPathname, [], [...route.routeSegments], \"route\"),\n );\n return options.dispatchMatchedRouteHandler({\n cleanPathname,\n middlewareContext,\n // Non-dynamic routes report params as `null` to match Next.js. Internal\n // bookkeeping above (navigation context, root params) keeps the matched\n // object (always `{}` for non-dynamic) so `useParams()` etc. still see\n // an object shape; only the user-facing handler context surfaces null.\n params: route.isDynamic ? renderParams : null,\n request,\n route,\n searchParams: url.searchParams,\n });\n }\n\n const pageResponse = await options.dispatchMatchedPage({\n cleanPathname,\n formState,\n actionError,\n actionFailed,\n handlerStart,\n interceptionContext: interceptionContextHeader,\n isProgressiveActionRender,\n isRscRequest,\n middlewareContext,\n mountedSlotsHeader,\n params: renderParams,\n staticParamsValidationParams: prerenderRouteParams === null ? undefined : params,\n rootParams,\n request,\n route,\n scriptNonce,\n searchParams: url.searchParams,\n renderMode,\n });\n\n // No-JS progressive form actions write cookies via cookies().set() / draftMode()\n // *during action execution*, before the page rerender begins. Those writes only\n // exist on the request-scoped headers state; the page-render path never flushes\n // them. We attach them here so the rendered Response carries the action's\n // Set-Cookie headers and revalidation marker, mirroring Next.js'\n // res.setHeader('set-cookie', ...) flush in action-handler.ts / app-render.tsx.\n // Issue: https://github.com/cloudflare/vinext/issues/1483\n if (isProgressiveActionRender) {\n return applyProgressiveActionSideEffects(pageResponse, progressiveActionResult);\n }\n return pageResponse;\n}\n\n/**\n * Append `Set-Cookie` headers and the `x-action-revalidated` marker captured\n * during progressive (no-JS) server action execution to the page render\n * response. See issue #1483.\n *\n * Falls back to rebuilding the response when the headers object is immutable\n * (e.g. `Response.redirect()`), so cookies set by the action ride out on a\n * redirect issued during the rerender too.\n */\nfunction applyProgressiveActionSideEffects(\n response: Response,\n sideEffects: ProgressiveActionFormStateResult,\n): Response {\n const hasPendingCookies = sideEffects.pendingCookies.length > 0;\n const hasDraftCookie = Boolean(sideEffects.draftCookie);\n const hasRevalidationKind = sideEffects.revalidationKind !== 0;\n if (!hasPendingCookies && !hasDraftCookie && !hasRevalidationKind) {\n return response;\n }\n\n const applyTo = (headers: Headers): void => {\n for (const cookie of sideEffects.pendingCookies) {\n headers.append(\"Set-Cookie\", cookie);\n }\n if (sideEffects.draftCookie) {\n headers.append(\"Set-Cookie\", sideEffects.draftCookie);\n }\n if (hasRevalidationKind) {\n headers.set(ACTION_REVALIDATED_HEADER, JSON.stringify(sideEffects.revalidationKind));\n }\n };\n\n try {\n applyTo(response.headers);\n return response;\n } catch {\n // Headers were immutable (Response.redirect()/Response.error()) — rebuild\n // with a fresh mutable Headers seeded from the original response.\n const headers = new Headers(response.headers);\n applyTo(headers);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n}\n\nexport function createAppRscHandler<TRoute extends AppRscHandlerRoute>(\n options: CreateAppRscHandlerOptions<TRoute>,\n): (request: Request, ctx: unknown) => Promise<Response> {\n return async function appRscHandler(rawRequest, ctx) {\n await options.ensureInstrumentation?.();\n\n // Strip forged internal headers at the App Router request boundary.\n // Must happen BEFORE headersContextFromRequest() and\n // requestContextFromRequest() so the captured context never contains\n // attacker-controlled internal headers. This is the correct boundary\n // for pure App Router requests; in hybrid app+pages mode the connect\n // handler already filtered headers upstream and x-vinext-mw-ctx\n // (not in INTERNAL_HEADERS) carries the forwarded middleware context.\n // srvx's NodeRequestHeaders reads from rawHeaders for iteration but falls\n // back to req.headers for .get() / .has(). In the dev server we add\n // x-vinext-mw-ctx to req.headers after the Request is built, so it is\n // visible to .get() but lost when filterInternalHeaders iterates. Read it\n // BEFORE iterating so applyForwardedMiddlewareContext can skip middleware.\n const mwCtx = rawRequest.headers.get(VINEXT_MW_CTX_HEADER);\n // Capture `x-nextjs-data` before filtering — the middleware redirect\n // protocol needs to know whether the inbound request was a `_next/data`\n // fetch to emit `x-nextjs-redirect` instead of an HTTP redirect.\n const isDataRequest = rawRequest.headers.get(\"x-nextjs-data\") === \"1\";\n // Read the trusted prerender route params before filtering strips the\n // route-params header (it IS in VINEXT_INTERNAL_HEADERS), then re-attach the\n // validated value below so the second read in handleAppRscRequest still sees\n // it. The secret was already verified upstream at prod-server's\n // nodeToWebRequest boundary; the surviving secret header (NOT in either\n // internal-header list) lets readTrustedPrerenderRouteParams's\n // VINEXT_PRERENDER gate pass on the reconstructed request. If the secret\n // header is ever added to VINEXT_INTERNAL_HEADERS, that second read breaks.\n const prerenderRouteParamsPayload = readTrustedPrerenderRouteParams(rawRequest);\n const filteredHeaders = filterInternalHeaders(rawRequest.headers);\n if (mwCtx !== null) {\n filteredHeaders.set(VINEXT_MW_CTX_HEADER, mwCtx);\n }\n const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(\n prerenderRouteParamsPayload,\n );\n if (prerenderRouteParamsHeader !== null) {\n filteredHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);\n }\n const request = cloneRequestWithHeaders(rawRequest, filteredHeaders);\n\n const executionContext = isExecutionContextLike(ctx)\n ? ctx\n : (getRequestExecutionContext() ?? null);\n const headersContext = headersContextFromRequest(request, {\n draftModeSecret: options.draftModeSecret,\n });\n const requestContext = createRequestContext({\n headersContext,\n executionContext,\n unstableCacheRevalidation: \"background\",\n });\n\n return runWithRequestContext(requestContext, () =>\n runWithPrerenderWorkUnit(\n async () => {\n ensureFetchPatch();\n const preMiddlewareRequestContext = requestContextFromRequest(request);\n let response: Response;\n\n try {\n response = await handleAppRscRequest(\n options,\n request,\n preMiddlewareRequestContext,\n isDataRequest,\n );\n } catch (error) {\n if (process.env.NODE_ENV !== \"production\") {\n flattenErrorCauses(error);\n }\n throw error;\n }\n\n return finalizeAppRscResponse(response, request, {\n basePath: options.basePath,\n configHeaders: options.configHeaders,\n i18nConfig: options.i18nConfig,\n requestContext: preMiddlewareRequestContext,\n });\n },\n { route: () => new URL(request.url).pathname },\n ),\n );\n };\n}\n"],"mappings":"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"}
|
|
@@ -30,7 +30,8 @@ type NormalizedRscRequest = {
|
|
|
30
30
|
* 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)
|
|
31
31
|
* 5. basePath check + strip — 404 when pathname lacks the basePath prefix.
|
|
32
32
|
* `/__vinext/` bypasses this for internal prerender endpoints.
|
|
33
|
-
* 6. RSC detection: `.rsc` suffix
|
|
33
|
+
* 6. RSC detection: `.rsc` suffix, or Next-style `RSC: 1` plus the internal
|
|
34
|
+
* `_rsc` cache-busting query. The header alone does not select payload
|
|
34
35
|
* rendering at the canonical HTML URL, so caches that ignore Vary cannot
|
|
35
36
|
* store Flight responses under HTML URLs.
|
|
36
37
|
* 7. cleanPathname — pathname with `.rsc` suffix stripped
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
2
2
|
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
3
|
-
import { VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
|
|
3
|
+
import { VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
|
|
4
4
|
import { normalizePath } from "./normalize-path.js";
|
|
5
5
|
import { badRequestResponse, notFoundResponse } from "./http-error-responses.js";
|
|
6
6
|
import { guardProtocolRelativeUrl } from "./request-pipeline.js";
|
|
7
7
|
import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
|
|
8
8
|
import { APP_RSC_RENDER_MODE_NAVIGATION, parseAppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
9
9
|
import { stripRscSuffix } from "./app-rsc-cache-busting.js";
|
|
10
|
+
import { normalizeInterceptionContextHeader } from "./app-interception-context-header.js";
|
|
10
11
|
import { parseClientReuseManifestHeader } from "./client-reuse-manifest.js";
|
|
11
12
|
//#region src/server/app-rsc-request-normalization.ts
|
|
12
13
|
/**
|
|
@@ -26,7 +27,8 @@ import { parseClientReuseManifestHeader } from "./client-reuse-manifest.js";
|
|
|
26
27
|
* 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)
|
|
27
28
|
* 5. basePath check + strip — 404 when pathname lacks the basePath prefix.
|
|
28
29
|
* `/__vinext/` bypasses this for internal prerender endpoints.
|
|
29
|
-
* 6. RSC detection: `.rsc` suffix
|
|
30
|
+
* 6. RSC detection: `.rsc` suffix, or Next-style `RSC: 1` plus the internal
|
|
31
|
+
* `_rsc` cache-busting query. The header alone does not select payload
|
|
30
32
|
* rendering at the canonical HTML URL, so caches that ignore Vary cannot
|
|
31
33
|
* store Flight responses under HTML URLs.
|
|
32
34
|
* 7. cleanPathname — pathname with `.rsc` suffix stripped
|
|
@@ -53,9 +55,9 @@ function normalizeRscRequest(request, basePath) {
|
|
|
53
55
|
if (!hasBasePath(pathname, basePath) && !pathname.startsWith("/__vinext/")) return notFoundResponse();
|
|
54
56
|
pathname = stripBasePath(pathname, basePath);
|
|
55
57
|
}
|
|
56
|
-
const isRscRequest = pathname.endsWith(".rsc");
|
|
58
|
+
const isRscRequest = pathname.endsWith(".rsc") || request.headers.get("RSC") === "1" && url.searchParams.has("_rsc");
|
|
57
59
|
const cleanPathname = stripRscSuffix(pathname);
|
|
58
|
-
const interceptionContextHeader = request.headers.get(
|
|
60
|
+
const interceptionContextHeader = normalizeInterceptionContextHeader(request.headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER));
|
|
59
61
|
const mountedSlotsHeader = normalizeMountedSlotsHeader(request.headers.get(VINEXT_MOUNTED_SLOTS_HEADER));
|
|
60
62
|
const renderMode = isRscRequest ? parseAppRscRenderMode(request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER)) : APP_RSC_RENDER_MODE_NAVIGATION;
|
|
61
63
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-rsc-request-normalization.js","names":[],"sources":["../../src/server/app-rsc-request-normalization.ts"],"sourcesContent":["import { normalizePath } from \"./normalize-path.js\";\nimport { normalizePathnameForRouteMatchStrict } from \"../routing/utils.js\";\nimport { guardProtocolRelativeUrl } from \"./request-pipeline.js\";\nimport { hasBasePath, stripBasePath } from \"../utils/base-path.js\";\nimport {\n VINEXT_CLIENT_REUSE_MANIFEST_HEADER,\n VINEXT_INTERCEPTION_CONTEXT_HEADER,\n VINEXT_MOUNTED_SLOTS_HEADER,\n VINEXT_RSC_RENDER_MODE_HEADER,\n} from \"./headers.js\";\nimport {\n parseClientReuseManifestHeader,\n type ClientReuseManifestParseResult,\n} from \"./client-reuse-manifest.js\";\nimport { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\nimport { stripRscSuffix } from \"./app-rsc-cache-busting.js\";\nimport {\n APP_RSC_RENDER_MODE_NAVIGATION,\n parseAppRscRenderMode,\n type AppRscRenderMode,\n} from \"./app-rsc-render-mode.js\";\nimport { badRequestResponse, notFoundResponse } from \"./http-error-responses.js\";\n\nexport { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\n\nexport type NormalizedRscRequest = {\n /** Parsed URL. Callers may mutate `url.search` after middleware runs. */\n url: URL;\n /** Normalized pathname with basePath stripped. Used for all internal routing. */\n pathname: string;\n /** Pathname with `.rsc` suffix removed. Used for route matching and navigation context. */\n cleanPathname: string;\n /** True when the request targets a canonical `.rsc` payload URL. */\n isRscRequest: boolean;\n /** Sanitized X-Vinext-Interception-Context header (null bytes stripped). null when absent. */\n interceptionContextHeader: string | null;\n /** Normalized x-vinext-mounted-slots header (deduplicated, sorted). null when absent or blank. */\n mountedSlotsHeader: string | null;\n /** Semantic RSC payload mode. HTML requests always normalize to \"navigation\". */\n renderMode: AppRscRenderMode;\n /** Disabled ClientReuseManifest hint. Never authorizes skip transport in this stage. */\n clientReuseManifest: ClientReuseManifestParseResult;\n};\n\n/**\n * Normalize an App Router RSC request.\n *\n * Performs all security-sensitive and compatibility-sensitive preprocessing before\n * route matching. The ordering of steps is security-critical — changing it introduces\n * vulnerabilities:\n *\n * 1. Parse URL\n * 2. Protocol-relative URL guard — on the raw pathname, BEFORE normalizePath collapses\n * `//` to `/`. If the guard ran after normalization, `//evil.com` → `/evil.com`\n * would bypass the check and reach the trailing-slash redirector, which echoes the\n * path into a `Location` header that browsers interpret as protocol-relative.\n * 3. Strict percent-decode each segment — throws on malformed sequences (→ 400). Must\n * run before basePath check so %2F-encoded slashes cannot create fake basePath prefixes.\n * 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)\n * 5. basePath check + strip — 404 when pathname lacks the basePath prefix.\n * `/__vinext/` bypasses this for internal prerender endpoints.\n * 6. RSC detection: `.rsc` suffix
|
|
1
|
+
{"version":3,"file":"app-rsc-request-normalization.js","names":[],"sources":["../../src/server/app-rsc-request-normalization.ts"],"sourcesContent":["import { normalizePath } from \"./normalize-path.js\";\nimport { normalizePathnameForRouteMatchStrict } from \"../routing/utils.js\";\nimport { guardProtocolRelativeUrl } from \"./request-pipeline.js\";\nimport { hasBasePath, stripBasePath } from \"../utils/base-path.js\";\nimport {\n RSC_HEADER,\n VINEXT_CLIENT_REUSE_MANIFEST_HEADER,\n VINEXT_INTERCEPTION_CONTEXT_HEADER,\n VINEXT_MOUNTED_SLOTS_HEADER,\n VINEXT_RSC_RENDER_MODE_HEADER,\n} from \"./headers.js\";\nimport {\n parseClientReuseManifestHeader,\n type ClientReuseManifestParseResult,\n} from \"./client-reuse-manifest.js\";\nimport { normalizeInterceptionContextHeader } from \"./app-interception-context-header.js\";\nimport { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\nimport { stripRscSuffix, VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM } from \"./app-rsc-cache-busting.js\";\nimport {\n APP_RSC_RENDER_MODE_NAVIGATION,\n parseAppRscRenderMode,\n type AppRscRenderMode,\n} from \"./app-rsc-render-mode.js\";\nimport { badRequestResponse, notFoundResponse } from \"./http-error-responses.js\";\n\nexport { normalizeMountedSlotsHeader } from \"./app-mounted-slots-header.js\";\n\nexport type NormalizedRscRequest = {\n /** Parsed URL. Callers may mutate `url.search` after middleware runs. */\n url: URL;\n /** Normalized pathname with basePath stripped. Used for all internal routing. */\n pathname: string;\n /** Pathname with `.rsc` suffix removed. Used for route matching and navigation context. */\n cleanPathname: string;\n /** True when the request targets a canonical `.rsc` payload URL. */\n isRscRequest: boolean;\n /** Sanitized X-Vinext-Interception-Context header (null bytes stripped). null when absent. */\n interceptionContextHeader: string | null;\n /** Normalized x-vinext-mounted-slots header (deduplicated, sorted). null when absent or blank. */\n mountedSlotsHeader: string | null;\n /** Semantic RSC payload mode. HTML requests always normalize to \"navigation\". */\n renderMode: AppRscRenderMode;\n /** Disabled ClientReuseManifest hint. Never authorizes skip transport in this stage. */\n clientReuseManifest: ClientReuseManifestParseResult;\n};\n\n/**\n * Normalize an App Router RSC request.\n *\n * Performs all security-sensitive and compatibility-sensitive preprocessing before\n * route matching. The ordering of steps is security-critical — changing it introduces\n * vulnerabilities:\n *\n * 1. Parse URL\n * 2. Protocol-relative URL guard — on the raw pathname, BEFORE normalizePath collapses\n * `//` to `/`. If the guard ran after normalization, `//evil.com` → `/evil.com`\n * would bypass the check and reach the trailing-slash redirector, which echoes the\n * path into a `Location` header that browsers interpret as protocol-relative.\n * 3. Strict percent-decode each segment — throws on malformed sequences (→ 400). Must\n * run before basePath check so %2F-encoded slashes cannot create fake basePath prefixes.\n * 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)\n * 5. basePath check + strip — 404 when pathname lacks the basePath prefix.\n * `/__vinext/` bypasses this for internal prerender endpoints.\n * 6. RSC detection: `.rsc` suffix, or Next-style `RSC: 1` plus the internal\n * `_rsc` cache-busting query. The header alone does not select payload\n * rendering at the canonical HTML URL, so caches that ignore Vary cannot\n * store Flight responses under HTML URLs.\n * 7. cleanPathname — pathname with `.rsc` suffix stripped\n * 8. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)\n * 9. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys\n * 10. Read semantic render mode for refresh/action payload rendering\n * 11. Parse disabled ClientReuseManifest hints on canonical RSC payload requests\n *\n * @returns A 400 or 404 Response for invalid or out-of-scope inputs,\n * or a NormalizedRscRequest for valid requests.\n */\nexport function normalizeRscRequest(\n request: Request,\n basePath: string,\n): Response | NormalizedRscRequest {\n const url = new URL(request.url);\n\n // Step 2: Guard against protocol-relative open redirects on the raw pathname.\n // normalizePath (step 4) would collapse //evil.com to /evil.com, causing the\n // guard to miss it. Raw pathname must be checked first.\n const protoGuard = guardProtocolRelativeUrl(url.pathname);\n if (protoGuard) return protoGuard;\n\n // Step 3: Strict segment-wise percent-decode. Preserves encoded path delimiters\n // (%2F stays %2F) to prevent encoded slashes from acting as path separators.\n // Throws on malformed sequences like %GG — caller must return 400.\n let decoded: string;\n try {\n decoded = normalizePathnameForRouteMatchStrict(url.pathname);\n } catch {\n return badRequestResponse();\n }\n\n // Step 4: Collapse double-slashes and resolve . / .. segments.\n let pathname = normalizePath(decoded);\n\n // Step 5: basePath check and strip.\n // Skipped when basePath is empty (no basePath configured).\n // /__vinext/ prefix bypasses the check for internal prerender endpoints\n // that must be reachable regardless of basePath configuration.\n if (basePath) {\n if (!hasBasePath(pathname, basePath) && !pathname.startsWith(\"/__vinext/\")) {\n return notFoundResponse();\n }\n pathname = stripBasePath(pathname, basePath);\n }\n\n // Steps 6-7: RSC detection and cleanPathname.\n const isRscRequest =\n pathname.endsWith(\".rsc\") ||\n (request.headers.get(RSC_HEADER) === \"1\" &&\n url.searchParams.has(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM));\n const cleanPathname = stripRscSuffix(pathname);\n\n // Step 8: Validate and sanitize X-Vinext-Interception-Context.\n //\n // The legitimate value is always a same-origin URL pathname (`/feed`,\n // `/photos/42`, …) emitted by the vinext browser entry. We strip null bytes\n // (header-injection defense), bound length, and require a pathname-shaped\n // value so an attacker cannot fan out unbounded distinct values into the\n // RSC / optimistic-route cache keys. See SECURITY-AUDIT-2026-05.md F-PROD-1.\n const interceptionContextHeader = normalizeInterceptionContextHeader(\n request.headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER),\n );\n\n // Step 9: Normalize mounted-slots header for canonical cache keying.\n const mountedSlotsHeader = normalizeMountedSlotsHeader(\n request.headers.get(VINEXT_MOUNTED_SLOTS_HEADER),\n );\n const renderMode = isRscRequest\n ? parseAppRscRenderMode(request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER))\n : APP_RSC_RENDER_MODE_NAVIGATION;\n const clientReuseManifest = isRscRequest\n ? parseClientReuseManifestHeader(request.headers.get(VINEXT_CLIENT_REUSE_MANIFEST_HEADER))\n : ({ kind: \"absent\" } satisfies ClientReuseManifestParseResult);\n\n return {\n clientReuseManifest,\n url,\n pathname,\n cleanPathname,\n isRscRequest,\n interceptionContextHeader,\n mountedSlotsHeader,\n renderMode,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4EA,SAAgB,oBACd,SACA,UACiC;CACjC,MAAM,MAAM,IAAI,IAAI,QAAQ,IAAI;CAKhC,MAAM,aAAa,yBAAyB,IAAI,SAAS;CACzD,IAAI,YAAY,OAAO;CAKvB,IAAI;CACJ,IAAI;EACF,UAAU,qCAAqC,IAAI,SAAS;SACtD;EACN,OAAO,oBAAoB;;CAI7B,IAAI,WAAW,cAAc,QAAQ;CAMrC,IAAI,UAAU;EACZ,IAAI,CAAC,YAAY,UAAU,SAAS,IAAI,CAAC,SAAS,WAAW,aAAa,EACxE,OAAO,kBAAkB;EAE3B,WAAW,cAAc,UAAU,SAAS;;CAI9C,MAAM,eACJ,SAAS,SAAS,OAAO,IACxB,QAAQ,QAAQ,IAAA,MAAe,KAAK,OACnC,IAAI,aAAa,IAAA,OAA0C;CAC/D,MAAM,gBAAgB,eAAe,SAAS;CAS9C,MAAM,4BAA4B,mCAChC,QAAQ,QAAQ,IAAI,mCAAmC,CACxD;CAGD,MAAM,qBAAqB,4BACzB,QAAQ,QAAQ,IAAI,4BAA4B,CACjD;CACD,MAAM,aAAa,eACf,sBAAsB,QAAQ,QAAQ,IAAI,8BAA8B,CAAC,GACzE;CAKJ,OAAO;EACL,qBAL0B,eACxB,+BAA+B,QAAQ,QAAQ,IAAI,oCAAoC,CAAC,GACvF,EAAE,MAAM,UAAU;EAIrB;EACA;EACA;EACA;EACA;EACA;EACA;EACD"}
|
|
@@ -7,12 +7,14 @@ type AppRouteSegmentConfigModule = {
|
|
|
7
7
|
dynamicParams?: unknown;
|
|
8
8
|
fetchCache?: unknown;
|
|
9
9
|
revalidate?: unknown;
|
|
10
|
+
runtime?: unknown;
|
|
10
11
|
};
|
|
11
12
|
type EffectiveAppPageSegmentConfig = {
|
|
12
13
|
dynamicConfig?: AppRouteSegmentDynamic;
|
|
13
14
|
dynamicParamsConfig?: boolean;
|
|
14
15
|
fetchCache?: FetchCacheMode;
|
|
15
16
|
revalidateSeconds: number | null;
|
|
17
|
+
runtime?: string;
|
|
16
18
|
};
|
|
17
19
|
type ResolveAppPageSegmentConfigOptions = {
|
|
18
20
|
layouts?: readonly (AppRouteSegmentConfigModule | null | undefined)[];
|
|
@@ -28,6 +30,7 @@ type ResolveAppPageSegmentConfigOptions = {
|
|
|
28
30
|
*/
|
|
29
31
|
declare function resolveAppPageSegmentConfig(options: ResolveAppPageSegmentConfigOptions): EffectiveAppPageSegmentConfig;
|
|
30
32
|
declare function resolveAppPageFetchCacheMode(options: ResolveAppPageSegmentConfigOptions): FetchCacheMode | null;
|
|
33
|
+
declare function isEdgeRuntime(runtime: string | undefined): boolean;
|
|
31
34
|
//#endregion
|
|
32
|
-
export { resolveAppPageFetchCacheMode, resolveAppPageSegmentConfig };
|
|
35
|
+
export { isEdgeRuntime, resolveAppPageFetchCacheMode, resolveAppPageSegmentConfig };
|
|
33
36
|
//# sourceMappingURL=app-segment-config.d.ts.map
|