vinext 1.4.0 → 1.4.1

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.
Files changed (104) hide show
  1. package/README.md +20 -20
  2. package/dist/build/prerender.js +3 -2
  3. package/dist/check.js +3 -6
  4. package/dist/client/dev-error-overlay-store.d.ts +1 -0
  5. package/dist/client/dev-error-overlay.d.ts +2 -0
  6. package/dist/client/dev-error-overlay.js +19 -3
  7. package/dist/config/config-matchers.js +2 -0
  8. package/dist/config/destination-params.d.ts +2 -1
  9. package/dist/config/destination-params.js +52 -2
  10. package/dist/config/next-config.d.ts +6 -0
  11. package/dist/config/next-config.js +18 -3
  12. package/dist/entries/app-rsc-entry.js +0 -1
  13. package/dist/entries/pages-server-entry.js +3 -1
  14. package/dist/index.js +29 -20
  15. package/dist/plugins/strip-server-exports.js +2 -1
  16. package/dist/server/api-handler.js +2 -1
  17. package/dist/server/app-browser-entry.js +7 -3
  18. package/dist/server/app-browser-rsc-redirect.js +3 -3
  19. package/dist/server/app-browser-server-action-client.js +2 -2
  20. package/dist/server/app-browser-visible-commit.js +2 -2
  21. package/dist/server/app-optimistic-routing.js +2 -3
  22. package/dist/server/app-page-boundary-render.js +5 -10
  23. package/dist/server/app-page-dispatch.d.ts +0 -1
  24. package/dist/server/app-page-dispatch.js +0 -1
  25. package/dist/server/app-page-element-builder.js +3 -3
  26. package/dist/server/app-page-execution.js +9 -6
  27. package/dist/server/app-page-render.d.ts +0 -1
  28. package/dist/server/app-page-render.js +14 -14
  29. package/dist/server/app-page-response.js +1 -1
  30. package/dist/server/app-page-route-wiring.js +22 -5
  31. package/dist/server/app-page-stream.d.ts +10 -8
  32. package/dist/server/app-page-stream.js +2 -1
  33. package/dist/server/app-request-stage-independent-entry.js +1 -1
  34. package/dist/server/app-route-handler-execution.js +3 -2
  35. package/dist/server/app-route-handler-runtime.d.ts +1 -1
  36. package/dist/server/app-route-handler-runtime.js +11 -7
  37. package/dist/server/app-router-entry.js +1 -1
  38. package/dist/server/app-rsc-cache-busting.d.ts +10 -10
  39. package/dist/server/app-rsc-cache-busting.js +27 -68
  40. package/dist/server/app-rsc-error-handler.js +1 -1
  41. package/dist/server/app-rsc-errors.js +4 -1
  42. package/dist/server/app-rsc-handler.js +53 -62
  43. package/dist/server/app-rsc-request-normalization.d.ts +10 -12
  44. package/dist/server/app-rsc-request-normalization.js +11 -14
  45. package/dist/server/app-rsc-response-stage.js +4 -12
  46. package/dist/server/app-server-action-execution.js +8 -4
  47. package/dist/server/app-ssr-entry.d.ts +6 -0
  48. package/dist/server/app-ssr-entry.js +13 -8
  49. package/dist/server/app-worker-stages.d.ts +12 -3
  50. package/dist/server/app-worker-stages.js +37 -4
  51. package/dist/server/bfcache-identity.d.ts +7 -0
  52. package/dist/server/bfcache-identity.js +10 -1
  53. package/dist/server/cacheability-manifest.js +1 -2
  54. package/dist/server/dev-origin-check.d.ts +2 -1
  55. package/dist/server/dev-origin-check.js +2 -1
  56. package/dist/server/dev-server.js +2 -1
  57. package/dist/server/image-optimization.d.ts +5 -0
  58. package/dist/server/image-optimization.js +6 -1
  59. package/dist/server/isr-cache.js +4 -1
  60. package/dist/server/metadata-route-response.js +1 -1
  61. package/dist/server/middleware-matcher.js +19 -6
  62. package/dist/server/middleware-runtime.js +6 -2
  63. package/dist/server/multi-stage.d.ts +7 -3
  64. package/dist/server/pages-node-compat.d.ts +1 -1
  65. package/dist/server/pages-node-compat.js +2 -0
  66. package/dist/server/pages-page-data.js +2 -1
  67. package/dist/server/pages-page-handler.js +17 -6
  68. package/dist/server/pages-page-response.d.ts +9 -0
  69. package/dist/server/pages-page-response.js +18 -4
  70. package/dist/server/pages-request-stage-entry.js +24 -4
  71. package/dist/server/pages-router-entry.js +3 -2
  72. package/dist/server/prod-server.d.ts +2 -2
  73. package/dist/server/prod-server.js +42 -8
  74. package/dist/server/request-error-log.d.ts +9 -0
  75. package/dist/server/request-error-log.js +13 -0
  76. package/dist/server/request-pipeline.d.ts +9 -4
  77. package/dist/server/request-pipeline.js +23 -15
  78. package/dist/server/rsc-completion-metadata.js +3 -0
  79. package/dist/server/static-file-cache.d.ts +9 -0
  80. package/dist/server/static-file-cache.js +13 -2
  81. package/dist/shims/cache-request-state.d.ts +6 -6
  82. package/dist/shims/cache-request-state.js +6 -36
  83. package/dist/shims/cache-runtime.d.ts +3 -1
  84. package/dist/shims/cache-runtime.js +77 -47
  85. package/dist/shims/cache.d.ts +10 -5
  86. package/dist/shims/cache.js +35 -22
  87. package/dist/shims/client-hook-error.d.ts +2 -0
  88. package/dist/shims/client-hook-error.js +16 -1
  89. package/dist/shims/fetch-cache.js +6 -2
  90. package/dist/shims/headers.d.ts +2 -1
  91. package/dist/shims/headers.js +5 -3
  92. package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
  93. package/dist/shims/link.js +5 -10
  94. package/dist/shims/navigation.js +2 -3
  95. package/dist/shims/request-state-types.d.ts +2 -1
  96. package/dist/shims/slot.d.ts +6 -2
  97. package/dist/shims/slot.js +10 -3
  98. package/dist/shims/unified-request-context.d.ts +6 -0
  99. package/dist/shims/unified-request-context.js +1 -0
  100. package/dist/utils/cache-life-profiles.d.ts +33 -0
  101. package/dist/utils/cache-life-profiles.js +111 -0
  102. package/dist/utils/middleware-request-headers.d.ts +14 -3
  103. package/dist/utils/middleware-request-headers.js +54 -7
  104. package/package.json +1 -1
@@ -22,8 +22,10 @@ function encodeBase64Url(bytes) {
22
22
  for (const byte of bytes) binary += String.fromCharCode(byte);
23
23
  return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
24
24
  }
25
- function normalizeHeaderValue(value) {
26
- return value ?? "0";
25
+ function serializeHeaderValue(value) {
26
+ if (value === null) return "0";
27
+ if (value === "0") return "\\0";
28
+ return value.replaceAll("\\", "\\\\").replaceAll(",", "\\,");
27
29
  }
28
30
  function normalizeCompatibilityId(value) {
29
31
  return value && value.length > 0 ? value : null;
@@ -57,9 +59,9 @@ function resolveHardNavigationTargetFromRscResponse(responseUrl, currentHref, or
57
59
  const parsed = new URL(responseUrl, origin);
58
60
  stripRscCacheBustingSearchParam(parsed);
59
61
  const origUrl = new URL(currentHref, origin);
60
- let pathname = stripRscSuffix(parsed.pathname);
62
+ let pathname = parsed.pathname;
61
63
  if (origUrl.pathname.length > 1 && origUrl.pathname.endsWith("/") && !pathname.endsWith("/")) pathname += "/";
62
- let hardNavigationTarget = pathname + parsed.search;
64
+ let hardNavigationTarget = toPathAbsolutePathname(pathname) + parsed.search;
63
65
  if (origUrl.hash) hardNavigationTarget += origUrl.hash;
64
66
  return hardNavigationTarget;
65
67
  }
@@ -74,21 +76,21 @@ function normalizeRenderModeHeaderValue(value) {
74
76
  const renderMode = parseAppRscRenderMode(value);
75
77
  return renderMode === "navigation" ? null : renderMode;
76
78
  }
77
- function createCacheBustingInput(headers, options = {}) {
79
+ function createCacheBustingInput(headers) {
78
80
  const values = [
79
81
  headers.get(NEXT_ROUTER_PREFETCH_HEADER),
80
82
  headers.get(NEXT_ROUTER_SEGMENT_PREFETCH_HEADER),
81
83
  headers.get(NEXT_ROUTER_STATE_TREE_HEADER),
82
84
  headers.get(NEXT_URL_HEADER),
83
85
  headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER),
84
- ...options.includeInterceptionIdHeader === false ? [] : [headers.get(VINEXT_INTERCEPTION_ID_HEADER)],
86
+ headers.get(VINEXT_INTERCEPTION_ID_HEADER),
85
87
  headers.get(VINEXT_MOUNTED_SLOTS_HEADER),
86
- ...options.includeRenderModeHeader === false ? [] : [normalizeRenderModeHeaderValue(headers.get(VINEXT_RSC_RENDER_MODE_HEADER))]
88
+ normalizeRenderModeHeaderValue(headers.get(VINEXT_RSC_RENDER_MODE_HEADER))
87
89
  ];
88
90
  const stateFingerprint = headers.get(VINEXT_RSC_STATE_FINGERPRINT_HEADER);
89
- if (options.includeStateFingerprintHeader !== false && stateFingerprint !== null) values.push(stateFingerprint);
91
+ if (stateFingerprint !== null) values.push(stateFingerprint);
90
92
  if (values.every((value) => value === null)) return null;
91
- return values.map(normalizeHeaderValue).join(",");
93
+ return values.map(serializeHeaderValue).join(",");
92
94
  }
93
95
  async function sha256CacheBustingHash(input) {
94
96
  const subtle = globalThis.crypto?.subtle;
@@ -147,13 +149,6 @@ function keepOnlyValidatedRscCacheBustingSearchParam(url, isRscRequest) {
147
149
  url.search = "";
148
150
  if (hash !== null) setRscCacheBustingSearchParam(url, hash);
149
151
  }
150
- /**
151
- * Remove a trailing `.rsc` suffix from a pathname. Returns the pathname
152
- * unchanged when the suffix is absent.
153
- */
154
- function stripRscSuffix(pathname) {
155
- return pathname.endsWith(".rsc") ? pathname.slice(0, -4) : pathname;
156
- }
157
152
  function createCanonicalRscRequestHeaders(deploymentId = getDeploymentId()) {
158
153
  const headers = new Headers({
159
154
  Accept: VINEXT_RSC_CONTENT_TYPE,
@@ -232,15 +227,22 @@ function parseRscRequestPath(href) {
232
227
  return new URL(beforeHash, RSC_REQUEST_URL_BASE);
233
228
  }
234
229
  /**
230
+ * A pathname as the start of a path-absolute reference. One that begins with
231
+ * "//" would serialize as a protocol-relative URL naming another host, so it
232
+ * keeps a "/." prefix, as the WHATWG URL serializer does. URL resolution drops
233
+ * the dot segment, so the reference still targets the same pathname on the
234
+ * origin it is resolved against.
235
+ */
236
+ function toPathAbsolutePathname(pathname) {
237
+ return pathname.startsWith("//") ? `/.${pathname}` : pathname;
238
+ }
239
+ /**
235
240
  * Serialize the path-absolute reference callers fetch against the app origin.
236
- * A pathname that begins with "//" would serialize as a protocol-relative URL
237
- * and send the request to another host, so it keeps a "/." prefix, as the
238
- * WHATWG URL serializer does. URL resolution drops the dot segment, so the
239
- * request still targets the same pathname on the app origin, as Next.js's
240
- * full-URL fetch does.
241
+ * A "//" pathname keeps its "/." prefix so the request still targets the same
242
+ * pathname on the app origin, as Next.js's full-URL fetch does.
241
243
  */
242
244
  function formatRscRequestPath(url) {
243
- return `${url.pathname.startsWith("//") ? `/.${url.pathname}` : url.pathname}${url.search}`;
245
+ return `${toPathAbsolutePathname(url.pathname)}${url.search}`;
244
246
  }
245
247
  async function createRscRequestUrl(href, headers) {
246
248
  const url = parseRscRequestPath(href);
@@ -275,55 +277,12 @@ async function resolveInvalidRscCacheBustingRequest(options) {
275
277
  const url = new URL(options.request.url);
276
278
  const actualHash = url.searchParams.get(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);
277
279
  const expectedHash = await computeRscCacheBustingSearchParam(options.request.headers);
278
- if (actualHash === null && expectedHash === "" && url.pathname.endsWith(".rsc")) return null;
279
- const acceptedHashes = /* @__PURE__ */ new Set([expectedHash]);
280
- if (actualHash !== null && actualHash !== expectedHash) {
281
- acceptedHashes.add(computeLegacyRscCacheBustingSearchParam(options.request.headers));
282
- const compatibilityInputs = [];
283
- const hasInterceptionId = options.request.headers.has(VINEXT_INTERCEPTION_ID_HEADER);
284
- const hasStateFingerprint = options.request.headers.has(VINEXT_RSC_STATE_FINGERPRINT_HEADER);
285
- const hasNormalRenderMode = normalizeRenderModeHeaderValue(options.request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER)) === null;
286
- if (!hasInterceptionId) compatibilityInputs.push({ includeInterceptionIdHeader: false });
287
- if (hasStateFingerprint) {
288
- compatibilityInputs.push({ includeStateFingerprintHeader: false });
289
- if (!hasInterceptionId) compatibilityInputs.push({
290
- includeInterceptionIdHeader: false,
291
- includeStateFingerprintHeader: false
292
- });
293
- }
294
- if (hasNormalRenderMode) {
295
- compatibilityInputs.push({ includeRenderModeHeader: false });
296
- if (!hasInterceptionId) compatibilityInputs.push({
297
- includeInterceptionIdHeader: false,
298
- includeRenderModeHeader: false
299
- });
300
- }
301
- if (hasStateFingerprint && hasNormalRenderMode) {
302
- compatibilityInputs.push({
303
- includeRenderModeHeader: false,
304
- includeStateFingerprintHeader: false
305
- });
306
- if (!hasInterceptionId) compatibilityInputs.push({
307
- includeInterceptionIdHeader: false,
308
- includeRenderModeHeader: false,
309
- includeStateFingerprintHeader: false
310
- });
311
- }
312
- for (const compatibilityOptions of compatibilityInputs) {
313
- const input = createCacheBustingInput(options.request.headers, compatibilityOptions);
314
- if (input === null) acceptedHashes.add("");
315
- else {
316
- acceptedHashes.add(await sha256CacheBustingHash(input));
317
- acceptedHashes.add(fnv1a64(input));
318
- }
319
- }
320
- }
321
- if (actualHash !== null && acceptedHashes.has(actualHash)) return null;
280
+ if (actualHash !== null && (actualHash === expectedHash || actualHash === computeLegacyRscCacheBustingSearchParam(options.request.headers))) return null;
322
281
  setRscCacheBustingSearchParam(url, expectedHash);
323
282
  return new Response(null, {
324
283
  status: 307,
325
- headers: { Location: `${url.pathname}${url.search}` }
284
+ headers: { Location: formatRscRequestPath(url) }
326
285
  });
327
286
  }
328
287
  //#endregion
329
- export { VINEXT_RSC_BUILD_ID_HEADER, VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, computeRscCacheBustingSearchParam, createCanonicalLoadingShellRscRequestHeaders, createCanonicalRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, formatRscRequestPath, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, keepOnlyValidatedRscCacheBustingSearchParam, parseRscRequestPath, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, stripRscSuffix };
288
+ export { VINEXT_RSC_BUILD_ID_HEADER, VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, computeRscCacheBustingSearchParam, createCanonicalLoadingShellRscRequestHeaders, createCanonicalRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, formatRscRequestPath, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, keepOnlyValidatedRscCacheBustingSearchParam, parseRscRequestPath, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, toPathAbsolutePathname };
@@ -23,7 +23,7 @@ function createAppRscOnErrorHandler(reportRequestError, request, pathname, route
23
23
  routerKind: "App Router",
24
24
  routePath: routePath || pathname,
25
25
  routeType: overrides?.routeType ?? "render",
26
- renderSource: overrides?.renderSource ?? (request.headers.get("RSC") === "1" || new URL(request.url).pathname.endsWith(".rsc") ? "react-server-components-payload" : "react-server-components"),
26
+ renderSource: overrides?.renderSource ?? (request.headers.get("RSC") === "1" ? "react-server-components-payload" : "react-server-components"),
27
27
  revalidateReason: isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate")) ? "on-demand" : overrides?.revalidateReason
28
28
  };
29
29
  let loggedErrors = loggedErrorsByRequest.get(request);
@@ -1,4 +1,6 @@
1
1
  import { isNavigationSignalError } from "../utils/navigation-signal.js";
2
+ import { logRequestError } from "./request-error-log.js";
3
+ import { rewriteClientHookError } from "../shims/client-hook-error.js";
2
4
  import { resolveAppPageSpecialError } from "./app-page-execution.js";
3
5
  import { isAppRenderAbortError } from "./app-render-abort-error.js";
4
6
  import { getProperError } from "./proper-error.js";
@@ -87,6 +89,7 @@ function createRscOnErrorHandler(options) {
87
89
  if (!hasDigest(properError) && (properError !== reportableError || options.attachDigest !== false)) try {
88
90
  Object.assign(properError, { digest });
89
91
  } catch {}
92
+ if (nodeEnv !== "production") rewriteClientHookError(properError);
90
93
  if (options.requestInfo && options.errorContext) options.reportRequestError(properError, options.requestInfo, options.errorContext);
91
94
  if (process.env.VINEXT_PRERENDER === "1" && error) {
92
95
  if (!loggedPrerenderErrors?.has(reportableError)) {
@@ -94,7 +97,7 @@ function createRscOnErrorHandler(options) {
94
97
  const route = options.requestInfo?.path ?? options.errorContext?.routePath ?? "<unknown>";
95
98
  console.error(`[vinext] Error prerendering route ${JSON.stringify(route)}:`, reportableError);
96
99
  }
97
- } else if (!(reportableError !== error && thrownHasDigest) && !wasLogged(reportableError)) console.error("[vinext] Server render error:", properError);
100
+ } else if (!(reportableError !== error && thrownHasDigest) && !wasLogged(reportableError)) logRequestError("[vinext] Server render error:", properError);
98
101
  return digest;
99
102
  };
100
103
  }
@@ -8,7 +8,7 @@ import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base
8
8
  import "./app-rsc-vary.js";
9
9
  import { ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_REWRITTEN_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_SPECIAL_ERROR_STATUS_HEADER } from "./headers.js";
10
10
  import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } from "./http-error-responses.js";
11
- import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, normalizeTrailingSlashPathname, resolvePublicFileRoute } from "./request-pipeline.js";
11
+ import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, normalizeTrailingSlashPathname, resolvePublicFileRoute, stripRequestUrlFragment } from "./request-pipeline.js";
12
12
  import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
13
13
  import { normalizePathnameForRouteMatch, normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
14
14
  import { patternToNextFormat } from "../routing/route-validation.js";
@@ -31,7 +31,7 @@ import { openForwardedMiddlewareContext } from "./forwarded-middleware-context.j
31
31
  import { consumeResponseStageLinkProvenance, copyLinkHeaderProvenance } from "./app-response-header-provenance.js";
32
32
  import { setFrameworkRequestRoute, traceFrameworkRequest } from "./request-tracing.js";
33
33
  import { mergeMiddlewareResponseHeaders, mergeMiddlewareResponseHeadersOntoResponse, withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
34
- import { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestUrl, hasRscCacheBustingSearchParam, resolveInvalidRscCacheBustingRequest, stripRscCacheBustingSearchParam, stripRscSuffix } from "./app-rsc-cache-busting.js";
34
+ import { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestUrl, hasRscCacheBustingSearchParam, resolveInvalidRscCacheBustingRequest, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
35
35
  import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
36
36
  import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
37
37
  import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
@@ -44,7 +44,7 @@ import { buildPageCacheTags } from "./implicit-tags.js";
44
44
  import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
45
45
  import { pickRootParams, setRootParams } from "../shims/root-params.js";
46
46
  import { createRouteTreePrefetchResponse, isRouteTreePrefetchRequest } from "./app-route-tree-prefetch.js";
47
- import { createSharedAppCacheIdentity, createSharedAppPageCacheIdentity, createSharedHybridPagesCacheIdentity, isStaticCandidateAppPageDispatch, prepareSharedAppPageDispatch, withoutAppPageDispatchQuery } from "./app-worker-stages.js";
47
+ import { createSharedAppCacheIdentity, createSharedAppPageCacheIdentity, createSharedAppRouteCacheIdentity, createSharedHybridPagesCacheIdentity, isStaticCandidateAppPageDispatch, prepareSharedAppPageDispatch, withoutAppPageDispatchQuery } from "./app-worker-stages.js";
48
48
  import { flattenErrorCauses } from "../utils/error-cause.js";
49
49
  import { applyAppRscConfigHeaders, finalizeAppRscResponse, markAppRscResponseConfigHeadersApplied } from "./app-rsc-response-finalizer.js";
50
50
  import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
@@ -257,13 +257,6 @@ function requestWithoutRscCacheBustingSearchParam(request) {
257
257
  stripRscCacheBustingSearchParam(url);
258
258
  return cloneRequestWithUrl(request, url.toString());
259
259
  }
260
- function requestWithoutRscSuffix(request) {
261
- const url = new URL(request.url);
262
- const pathname = stripRscSuffix(url.pathname);
263
- if (pathname === url.pathname) return request;
264
- url.pathname = pathname;
265
- return cloneRequestWithUrl(request, url.toString());
266
- }
267
260
  /** Send a response with the never-cache policy, rebuilding immutable headers. */
268
261
  function withNeverCacheControl(response) {
269
262
  const applyNoStore = (headers) => {
@@ -320,8 +313,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
320
313
  setInterceptionResponseUncacheable(true);
321
314
  return badRequestResponse();
322
315
  }
323
- const { requestCleanPathname } = normalized;
324
- let { pathname, cleanPathname } = normalized;
316
+ const { pathname, requestPathname } = normalized;
317
+ let cleanPathname = pathname;
325
318
  let resolvedUrl = cleanPathname + url.search;
326
319
  const originalResolvedUrl = serializeResolvedUrl(resolvedUrl, url);
327
320
  const getResolvedSearchParams = () => new URL(resolvedUrl, url).searchParams;
@@ -331,7 +324,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
331
324
  hadBasePath
332
325
  };
333
326
  let cleanPathnameIsRequestPathname = true;
334
- const matchCleanPathname = () => cleanPathnameIsRequestPathname && options.matchRequestRoute ? options.matchRequestRoute(requestCleanPathname) : options.matchRoute(cleanPathname);
327
+ const matchCleanPathname = () => cleanPathnameIsRequestPathname && options.matchRequestRoute ? options.matchRequestRoute(requestPathname) : options.matchRoute(cleanPathname);
335
328
  if (interceptionIdHeader !== null && (!isRscRequest || interceptionContextHeader === null || request.method !== "GET" && request.method !== "HEAD" || !options.hasInterceptionId(interceptionIdHeader))) {
336
329
  setInterceptionResponseUncacheable(true);
337
330
  return badRequestResponse();
@@ -348,7 +341,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
348
341
  if (sourceMatch.interceptionSourceIsConcrete !== void 0) return sourceMatch.interceptionSourceIsConcrete;
349
342
  return sourceContext !== null && (options.matchRequestRoute ?? options.matchRoute)(sourceContext)?.route === sourceMatch.route;
350
343
  };
351
- if (provesConcreteInterceptionSource(hadBasePath && hasRawInterceptionContext && interceptionContextHeader !== null ? options.matchInterceptRoute?.(requestCleanPathname, interceptionContextHeader, interceptionIdHeader) ?? null : null)) setInterceptionResponseUncacheable(false);
344
+ if (provesConcreteInterceptionSource(hadBasePath && hasRawInterceptionContext && interceptionContextHeader !== null ? options.matchInterceptRoute?.(requestPathname, interceptionContextHeader, interceptionIdHeader) ?? null : null)) setInterceptionResponseUncacheable(false);
352
345
  if (pathname === "/__vinext/prerender/static-params" || pathname === "/__vinext/prerender/pages-static-paths" || pathname === "/__vinext/prerender/metadata-routes") {
353
346
  const { handleAppPrerenderEndpoint } = await import("./app-prerender-endpoints.js");
354
347
  const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {
@@ -364,16 +357,16 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
364
357
  if (prerenderEndpointResponse) return prerenderEndpointResponse;
365
358
  }
366
359
  if (!isDataRequest && !options.skipTrailingSlashRedirect) {
367
- const trailingSlashRedirect = options.trailingSlash && options.isMetadataRoutePath && await options.isMetadataRoutePath(cleanPathname) ? null : normalizeTrailingSlash(requestCleanPathname, hadBasePath ? options.basePath : "", options.trailingSlash, url.search);
360
+ const trailingSlashRedirect = options.trailingSlash && options.isMetadataRoutePath && await options.isMetadataRoutePath(cleanPathname) ? null : normalizeTrailingSlash(requestPathname, hadBasePath ? options.basePath : "", options.trailingSlash, url.search);
368
361
  if (trailingSlashRedirect) return trailingSlashRedirect;
369
362
  }
370
363
  const matchPathname = (p) => normalizeDefaultLocalePathname(p, options.i18nConfig, { hostname: url.hostname });
371
- const restoreLocaleRootTrailingSlash = !pagesDataRequest && shouldRestoreLocaleRootTrailingSlash(stripRscSuffix(url.pathname), options);
372
- const headerMatchPathname = normalizeDefaultLocalePathname(requestCleanPathname, options.i18nConfig, {
364
+ const restoreLocaleRootTrailingSlash = !pagesDataRequest && shouldRestoreLocaleRootTrailingSlash(url.pathname, options);
365
+ const headerMatchPathname = normalizeDefaultLocalePathname(requestPathname, options.i18nConfig, {
373
366
  hostname: url.hostname,
374
367
  restoreRootTrailingSlash: restoreLocaleRootTrailingSlash
375
368
  });
376
- const redirectPathname = matchPathname(requestCleanPathname);
369
+ const redirectPathname = matchPathname(requestPathname);
377
370
  const configMatchers = HAS_CONFIG_REDIRECTS && options.configRedirects.length ? await import("../config/config-matchers.js") : null;
378
371
  const redirect = configMatchers ? configMatchers.matchRedirect(redirectPathname, options.configRedirects, preMiddlewareRequestContext, basePathState, dispatchResponseStage ? void 0 : markConditionalRedirectCacheability) : null;
379
372
  if (configMatchers && redirect) {
@@ -399,9 +392,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
399
392
  };
400
393
  const runMiddleware = isOnDemandRevalidateRequest(request.headers.get("x-prerender-revalidate")) ? void 0 : options.runMiddleware;
401
394
  const isolatedMiddlewareSource = runMiddleware && request.body && !request.bodyUsed ? request.clone() : null;
402
- const normalizedUserlandRequest = requestWithoutRscSuffix(request);
403
- const userlandRequest = requestWithoutRscCacheBustingSearchParam(normalizedUserlandRequest);
404
- const isolatedMiddlewareRequest = isolatedMiddlewareSource ? requestWithoutRscCacheBustingSearchParam(requestWithoutRscSuffix(isolatedMiddlewareSource)) : void 0;
395
+ const userlandRequest = requestWithoutRscCacheBustingSearchParam(request);
396
+ const isolatedMiddlewareRequest = isolatedMiddlewareSource ? requestWithoutRscCacheBustingSearchParam(isolatedMiddlewareSource) : void 0;
405
397
  let didMiddlewareRewrite = false;
406
398
  let didMiddlewareRewritePathname = false;
407
399
  let resolvedPathnameHasBasePath = hadBasePath;
@@ -413,7 +405,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
413
405
  const middlewareResult = await runMiddleware({
414
406
  cleanPathname,
415
407
  context: middlewareContext,
416
- externalRewriteRequest: normalizedUserlandRequest,
408
+ externalRewriteRequest: request,
417
409
  hadBasePath,
418
410
  isDataRequest: isMiddlewareDataRequest,
419
411
  middlewareRequest: isolatedMiddlewareRequest,
@@ -448,8 +440,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
448
440
  cleanPathname = middlewareResult.cleanPathname;
449
441
  didMiddlewareRewrite = middlewareResult.rewritten;
450
442
  if (didMiddlewareRewrite) resolvedPathnameHasBasePath = middlewareResult.rewriteHadBasePath ?? true;
451
- if (didMiddlewareRewrite || cleanPathname !== normalized.cleanPathname) cleanPathnameIsRequestPathname = false;
452
- didMiddlewareRewritePathname = cleanPathname !== normalized.cleanPathname;
443
+ if (didMiddlewareRewrite || cleanPathname !== pathname) cleanPathnameIsRequestPathname = false;
444
+ didMiddlewareRewritePathname = cleanPathname !== pathname;
453
445
  if (middlewareResult.search !== null) url.search = middlewareResult.search;
454
446
  resolvedUrl = cleanPathname + url.search;
455
447
  }
@@ -505,7 +497,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
505
497
  const rscPath = canonicalRsc.navigation ? createCanonicalRscRequestUrl(dispatchRequest.url) : await createRscRequestUrl(dispatchRequest.url, canonicalRsc.headers);
506
498
  dispatchRequest = cloneRequestWithUrl(dispatchRequest, new URL(rscPath, dispatchRequest.url).toString());
507
499
  }
508
- const cacheIdentity = cache !== "shared" || stageProps.kind === "app-full-request" || stageProps.kind === "hybrid-pages" || !adapterUsesSharedCacheIdentity() ? void 0 : stageProps.kind === "app-page" && adapterSharedCacheIdentity() === "query-free" && responseStagePolicy === null && stageProps.matchKind !== "interception" && stageProps.interceptionContext === null && stageProps.interceptionId === null && stageProps.mountedSlotsHeader === null ? createSharedAppPageCacheIdentity(dispatchRequest, stageProps) : createSharedAppCacheIdentity(dispatchRequest, stageProps);
500
+ const cacheIdentity = cache !== "shared" || stageProps.kind === "app-full-request" || stageProps.kind === "hybrid-pages" || !adapterUsesSharedCacheIdentity() ? void 0 : adapterSharedCacheIdentity() !== "query-free" || responseStagePolicy !== null ? createSharedAppCacheIdentity(dispatchRequest, stageProps) : stageProps.kind === "app-page" && stageProps.matchKind !== "interception" && stageProps.interceptionContext === null && stageProps.interceptionId === null && stageProps.mountedSlotsHeader === null ? createSharedAppPageCacheIdentity(dispatchRequest, stageProps) : stageProps.kind === "app-metadata" || stageProps.kind === "app-route-handler" && stageProps.matchKind !== "interception" ? createSharedAppRouteCacheIdentity(dispatchRequest, stageProps) : createSharedAppCacheIdentity(dispatchRequest, stageProps);
509
501
  let response = await dispatchResponseStage(dispatchRequest, stageProps, cacheIdentity ? {
510
502
  cache,
511
503
  cacheIdentity
@@ -536,7 +528,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
536
528
  };
537
529
  const renderMetadataRouteIfMatched = async () => {
538
530
  if (!filesystemRouteEligible || (options.isMetadataRoute ? !options.isMetadataRoute(cleanPathname) : !options.handleMetadataRouteRequest)) return null;
539
- const metadataRoutePathname = cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname;
531
+ const metadataRoutePathname = cleanPathnameIsRequestPathname ? requestPathname : cleanPathname;
540
532
  const metadataResponseStage = transportedResponseStage ?? options.renderResponseStageLocally;
541
533
  if (metadataResponseStage) {
542
534
  const response = await metadataResponseStage(responseStageRequest(), {
@@ -616,9 +608,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
616
608
  basePathState: currentBasePathState(),
617
609
  clearRequestContext: options.clearRequestContext,
618
610
  middlewareContext,
619
- request: normalizedUserlandRequest,
611
+ request,
620
612
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
621
- paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
613
+ paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestPathname : cleanPathname),
622
614
  rewrites: [rewrite],
623
615
  validateExternalRewriteRequest: () => validateClaimedOutsideBasePathRsc(true)
624
616
  }, matchPathname(cleanPathname), dispatchResponseStage === void 0);
@@ -663,7 +655,6 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
663
655
  const publicFileResponse = resolvePublicFileRoute({
664
656
  cleanPathname: cleanPathnameIsRequestPathname ? cleanPathname : normalizePathnameForRouteMatch(cleanPathname),
665
657
  middlewareContext,
666
- pathname,
667
658
  publicFiles: options.publicFiles,
668
659
  request
669
660
  });
@@ -680,7 +671,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
680
671
  params: {}
681
672
  });
682
673
  const directPreActionMatch = filesystemRouteEligible ? matchCleanPathname() : null;
683
- const preActionRoutePathname = cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname;
674
+ const preActionRoutePathname = cleanPathnameIsRequestPathname ? requestPathname : cleanPathname;
684
675
  let interceptionSourceContext = interceptionSourcePathname !== null ? interceptionContextHeader : null;
685
676
  let interceptionSourceMatch = filesystemRouteEligible && interceptionSourcePathname !== null && interceptionContextHeader !== null ? options.matchInterceptRoute?.(preActionRoutePathname, interceptionContextHeader, interceptionIdHeader) ?? null : null;
686
677
  let hasVerifiedInterceptionSource = provesConcreteInterceptionSource(interceptionSourceMatch);
@@ -749,7 +740,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
749
740
  sourceMiddlewareResult = await runWithHeadersContext(sourceHeadersContext, () => runMiddleware({
750
741
  cleanPathname: decodedSourceRequestPathname,
751
742
  context: sourceMiddlewareContext,
752
- externalRewriteRequest: normalizedUserlandRequest,
743
+ externalRewriteRequest: request,
753
744
  hadBasePath: resolvedPathnameHasBasePath,
754
745
  isDataRequest: isMiddlewareDataRequest,
755
746
  request: sourceMiddlewareRequest,
@@ -792,21 +783,22 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
792
783
  sourceRulesPathname = sourceMiddlewareResult.cleanPathname;
793
784
  }
794
785
  }
795
- if (HAS_CONFIG_REWRITES && options.configRewrites.beforeFiles.length) {
786
+ if (HAS_CONFIG_REWRITES && (options.configRewrites.beforeFiles.length || options.configRewrites.afterFiles.length)) {
796
787
  const { matchRewrite } = await import("../config/config-matchers.js");
797
788
  const sourceRewriteContext = requestContextForResolvedUrl(buildPostMwRequestContext(userlandRequest), resolvedUrl, url);
798
- let didRewriteSource = false;
799
- for (const rewrite of options.configRewrites.beforeFiles) {
800
- const destination = matchRewrite(matchPathname(sourceRulesPathname), [rewrite], sourceRewriteContext, currentBasePathState(), matchPathname(sourceRulesPathname), dispatchResponseStage === void 0 ? markConditionalRewriteCacheability : void 0);
801
- if (!destination) continue;
802
- if (isExternalUrl(destination) || destination.includes("?")) {
803
- options.clearRequestContext();
804
- return notFoundResponse();
789
+ const rewriteSource = (rewrites, stopAtRoute) => {
790
+ let didRewriteSource = false;
791
+ for (const rewrite of rewrites) {
792
+ const destination = matchRewrite(matchPathname(sourceRulesPathname), [rewrite], sourceRewriteContext, currentBasePathState(), matchPathname(sourceRulesPathname), dispatchResponseStage === void 0 ? markConditionalRewriteCacheability : void 0);
793
+ if (!destination) continue;
794
+ if (isExternalUrl(destination) || destination.includes("?")) return false;
795
+ sourceRulesPathname = pathnameForResolvedUrl(destination);
796
+ didRewriteSource = true;
797
+ if (stopAtRoute && options.matchRoute(sourceRulesPathname)) break;
805
798
  }
806
- sourceRulesPathname = pathnameForResolvedUrl(destination);
807
- didRewriteSource = true;
808
- }
809
- if (didRewriteSource && !adoptRewrittenInterceptionSource(sourceRulesPathname)) {
799
+ return !didRewriteSource || adoptRewrittenInterceptionSource(sourceRulesPathname);
800
+ };
801
+ if (!rewriteSource(options.configRewrites.beforeFiles, false) || interceptionSourceMatch.route.isDynamic && !rewriteSource(options.configRewrites.afterFiles, true)) {
810
802
  options.clearRequestContext();
811
803
  return notFoundResponse();
812
804
  }
@@ -831,7 +823,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
831
823
  const isInterceptionMatch = interceptionPreActionMatch !== null;
832
824
  const rendersRawRequestMatch = options.matchRawRequestRoute !== void 0 && (isPossibleAppRouteActionRequest(request) || isDraftModeRequest(request, options.draftModeSecret) || isDraftModeEnabled());
833
825
  const usesRawRequestMatch = () => rendersRawRequestMatch && cleanPathnameIsRequestPathname && !isInterceptionMatch;
834
- const renderedRouteMatch = (routeMatch) => routeMatch !== null && usesRawRequestMatch() ? options.matchRawRequestRoute(requestCleanPathname) ?? routeMatch : routeMatch;
826
+ const renderedRouteMatch = (routeMatch) => routeMatch !== null && usesRawRequestMatch() ? options.matchRawRequestRoute(requestPathname) ?? routeMatch : routeMatch;
835
827
  const renderedPreActionMatch = renderedRouteMatch(preActionMatch);
836
828
  if (renderedPreActionMatch) setRootParams(pickRootParams(renderedPreActionMatch.params, renderedPreActionMatch.route.rootParamNames));
837
829
  if (pagesDataRequest && didMiddlewareRewritePathname && preActionMatch && !preActionMatch.route.isDynamic) {
@@ -854,9 +846,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
854
846
  if (routeMatch && isAppRouteHandlerRoute(routeMatch.route)) return null;
855
847
  if (!options.handleServerActionRequest) return createMissingServerActionResponse(options, actionId);
856
848
  const sourceConfigHeaders = new Headers();
857
- const sourceConfigUrl = new URL(request.url);
858
- sourceConfigUrl.pathname = hadBasePath ? addBasePathToPathname(requestCleanPathname, options.basePath) : requestCleanPathname;
859
- await applyAppRscConfigHeaders(sourceConfigHeaders, cloneRequestWithUrl(request, sourceConfigUrl.toString()), {
849
+ await applyAppRscConfigHeaders(sourceConfigHeaders, request, {
860
850
  basePath: options.basePath,
861
851
  configHeaders: options.configHeaders,
862
852
  i18nConfig: options.i18nConfig,
@@ -915,7 +905,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
915
905
  let match = preActionMatch;
916
906
  const renderPagesForMatchKind = async (matchKind) => {
917
907
  if (!filesystemRouteEligible) return null;
918
- const pagesRouteUrl = cleanPathnameIsRequestPathname ? requestCleanPathname + resolvedUrl.slice(pathnameForResolvedUrl(resolvedUrl).length) : resolvedUrl;
908
+ const pagesRouteUrl = cleanPathnameIsRequestPathname ? requestPathname + resolvedUrl.slice(pathnameForResolvedUrl(resolvedUrl).length) : resolvedUrl;
919
909
  let sharedOuterPolicyNeedsReconciliation = false;
920
910
  const dispatchPagesResponseStage = dispatchResponseStage ? async (stageRequest, resourceKind, dataKind, hasRequestAwareDocument, runsInitialProps) => {
921
911
  const pagesOnDemandRevalidate = resourceKind === "page" && isOnDemandRevalidateRequest(stageRequest.headers.get("x-prerender-revalidate"));
@@ -1009,9 +999,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1009
999
  basePathState: currentBasePathState(),
1010
1000
  clearRequestContext: options.clearRequestContext,
1011
1001
  middlewareContext,
1012
- request: normalizedUserlandRequest,
1002
+ request,
1013
1003
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
1014
- paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
1004
+ paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestPathname : cleanPathname),
1015
1005
  rewrites: [rewrite],
1016
1006
  validateExternalRewriteRequest: () => validateClaimedOutsideBasePathRsc(true)
1017
1007
  }, matchPathname(cleanPathname), dispatchResponseStage === void 0);
@@ -1057,9 +1047,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1057
1047
  basePathState: currentBasePathState(),
1058
1048
  clearRequestContext: options.clearRequestContext,
1059
1049
  middlewareContext,
1060
- request: normalizedUserlandRequest,
1050
+ request,
1061
1051
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
1062
- paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
1052
+ paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestPathname : cleanPathname),
1063
1053
  rewrites: [rewrite],
1064
1054
  validateExternalRewriteRequest: () => validateClaimedOutsideBasePathRsc(true)
1065
1055
  }, matchPathname(cleanPathname), dispatchResponseStage === void 0);
@@ -1096,7 +1086,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1096
1086
  if (match) break;
1097
1087
  }
1098
1088
  if (interceptionCacheProofInvalidated && interceptionSourceContext !== null) {
1099
- const finalInterceptionTargetPathname = cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname;
1089
+ const finalInterceptionTargetPathname = cleanPathnameIsRequestPathname ? requestPathname : cleanPathname;
1100
1090
  const finalInterceptionSourceMatch = filesystemRouteEligible && match !== null ? options.matchInterceptRoute?.(finalInterceptionTargetPathname, interceptionSourceContext, interceptionIdHeader) ?? null : null;
1101
1091
  const hasVerifiedFinalInterceptionSource = hasVerifiedInterceptionSource && interceptionSourceMatch !== null && provesConcreteInterceptionSource(finalInterceptionSourceMatch) && finalInterceptionSourceMatch?.route === interceptionSourceMatch.route && haveSamePageParams(finalInterceptionSourceMatch.params, interceptionSourceMatch.params);
1102
1092
  if (interceptionIdHeader !== null && !hasVerifiedFinalInterceptionSource) {
@@ -1140,7 +1130,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1140
1130
  const finalRouteMatch = renderedRouteMatch(match);
1141
1131
  setRootParams(finalRouteMatch ? pickRootParams(finalRouteMatch.params, finalRouteMatch.route.rootParamNames) : null);
1142
1132
  if (isServerActionRequest) {
1143
- const serverActionResponse = await handleServerAction(finalRouteMatch, cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname);
1133
+ const serverActionResponse = await handleServerAction(finalRouteMatch, cleanPathnameIsRequestPathname ? requestPathname : cleanPathname);
1144
1134
  if (serverActionResponse) return serverActionResponse;
1145
1135
  } else {
1146
1136
  const progressiveActionResult = await handleProgressiveAction(finalRouteMatch, match);
@@ -1186,7 +1176,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1186
1176
  }
1187
1177
  match = renderedRouteMatch(match);
1188
1178
  const { route, params } = match;
1189
- const requestPathnameDiffersFromCachePath = requestCleanPathname !== cleanPathname;
1179
+ const requestPathnameDiffersFromCachePath = requestPathname !== cleanPathname;
1190
1180
  const rawRequestPathnameIsObservable = isInterceptionMatch || route.routeHandler != null || typeof route.__loadRouteHandler === "function";
1191
1181
  if ((!isInterceptionMatch || requestPathnameDiffersFromCachePath) && options.matchRequestRoute) {
1192
1182
  const cachePathMatch = options.matchRoute(cleanPathname);
@@ -1213,7 +1203,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1213
1203
  const isPrerenderFallbackShell = prerenderRouteParamsMatch?.kind === "fallback-shell";
1214
1204
  const renderParams = prerenderRouteParams ?? params;
1215
1205
  const responseStageMatchKind = isInterceptionMatch ? "interception" : cleanPathnameIsRequestPathname && options.matchRequestRoute ? usesRawRequestMatch() ? "raw-request" : "request" : "resolved";
1216
- const responseStageRoutePathname = isInterceptionMatch ? preActionRoutePathname : cleanPathnameIsRequestPathname ? requestCleanPathname || "/" : cleanPathname || "/";
1206
+ const responseStageRoutePathname = isInterceptionMatch ? preActionRoutePathname : cleanPathnameIsRequestPathname ? requestPathname || "/" : cleanPathname || "/";
1217
1207
  const matchedResponseStage = transportedResponseStage ?? options.renderResponseStageLocally;
1218
1208
  let runtimeFallbackShells = [];
1219
1209
  if (options.createPprFallbackShells && request.method === "GET" && !isRscRequest && !isPrerenderFallbackShell && route.params) runtimeFallbackShells = options.createPprFallbackShells({
@@ -1229,7 +1219,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1229
1219
  const rootParams = pickRootParams(renderParams, route.rootParamNames);
1230
1220
  setRootParams(rootParams);
1231
1221
  if (route.routeHandler) {
1232
- const routeHandlerRequest = isEdgeRouteHandler(route.routeHandler) ? userlandRequest : normalizedUserlandRequest;
1222
+ const routeHandlerRequest = isEdgeRouteHandler(route.routeHandler) ? userlandRequest : request;
1233
1223
  const routeHandlerUrl = new URL(routeHandlerRequest.url);
1234
1224
  const internalRscValues = isEdgeRouteHandler(route.routeHandler) ? [] : routeHandlerUrl.searchParams.getAll(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);
1235
1225
  routeHandlerUrl.search = resolvedSearchParams.toString();
@@ -1312,7 +1302,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1312
1302
  handlerStart,
1313
1303
  interceptionContext: interceptionSourceContext,
1314
1304
  interceptionId: interceptionIdHeader,
1315
- interceptionPathname: cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname,
1305
+ interceptionPathname: cleanPathnameIsRequestPathname ? requestPathname : cleanPathname,
1316
1306
  isProgressiveActionRender: progressiveActionFormState !== null,
1317
1307
  isRscRequest,
1318
1308
  middlewareContext,
@@ -1375,8 +1365,9 @@ function applyProgressiveActionSideEffects(response, sideEffects) {
1375
1365
  }
1376
1366
  /** Build the request-only handler without retaining the response renderer graph. */
1377
1367
  function createAppRscRequestHandler(options) {
1378
- const handleAppRscRequestLifecycle = async (rawRequest, ctx, allowInternalRscDocumentFallback = false, dispatchResponseStage, responseStageProbeMode = null, transportedPrerenderState) => {
1379
- const rawRequestSignal = rawRequest.signal;
1368
+ const handleAppRscRequestLifecycle = async (hostRequest, ctx, allowInternalRscDocumentFallback = false, dispatchResponseStage, responseStageProbeMode = null, transportedPrerenderState) => {
1369
+ const rawRequestSignal = hostRequest.signal;
1370
+ const rawRequest = stripRequestUrlFragment(hostRequest);
1380
1371
  const mwCtx = openForwardedMiddlewareContext(rawRequest.headers.get(VINEXT_MW_CTX_HEADER), options.devForwardedMiddlewareContextKey);
1381
1372
  const pagesDataUrl = new URL(rawRequest.url);
1382
1373
  const pagesDataInScope = !options.basePath || hasBasePath(pagesDataUrl.pathname, options.basePath);
@@ -1440,7 +1431,7 @@ function createAppRscRequestHandler(options) {
1440
1431
  basePath: options.basePath,
1441
1432
  configHeaders: options.configHeaders,
1442
1433
  i18nConfig: options.i18nConfig,
1443
- restoreLocaleRootTrailingSlash: shouldRestoreLocaleRootTrailingSlash(stripRscSuffix(new URL(rawRequest.url).pathname), options),
1434
+ restoreLocaleRootTrailingSlash: shouldRestoreLocaleRootTrailingSlash(new URL(rawRequest.url).pathname, options),
1444
1435
  middlewareHeaders: middlewareContext.headers,
1445
1436
  recordCacheability: dispatchResponseStage === void 0,
1446
1437
  requestContext: preMiddlewareRequestContext
@@ -1468,7 +1459,7 @@ function createAppRscRequestHandler(options) {
1468
1459
  detached: detachedTrace,
1469
1460
  getStatus: (response) => response?.status,
1470
1461
  headers: rawRequest.headers,
1471
- isRsc: traceUrl.pathname.endsWith(".rsc") || rawRequest.headers.get("RSC") === "1",
1462
+ isRsc: rawRequest.headers.get("RSC") === "1",
1472
1463
  method: rawRequest.method,
1473
1464
  target: traceUrl.pathname + traceUrl.search
1474
1465
  });
@@ -6,11 +6,9 @@ export type NormalizedRscRequest = {
6
6
  url: URL;
7
7
  /** Normalized pathname with basePath stripped. Used for all internal routing. */
8
8
  pathname: string;
9
- /** Pathname with `.rsc` suffix removed. Used for route matching and navigation context. */
10
- cleanPathname: string;
11
- /** Original encoded request pathname with basePath and `.rsc` removed. */
12
- requestCleanPathname: string;
13
- /** True when the request targets a canonical `.rsc` payload URL. */
9
+ /** Original encoded request pathname with basePath stripped. */
10
+ requestPathname: string;
11
+ /** True when the request selects the RSC payload with `RSC: 1`. */
14
12
  isRscRequest: boolean;
15
13
  /** Sanitized X-Vinext-Interception-Context header (null bytes stripped). null when absent. */
16
14
  interceptionContextHeader: string | null;
@@ -42,13 +40,13 @@ export type NormalizedRscRequest = {
42
40
  * 4. Collapse double-slashes, resolve `.` and `..` segments (normalizePath)
43
41
  * 5. basePath check + strip — 404 when pathname lacks the basePath prefix.
44
42
  * `/__vinext/` bypasses this for internal prerender endpoints.
45
- * 6. RSC detection: `.rsc` suffix or Next-style `RSC: 1`. The internal
46
- * `_rsc` cache-busting query is validated separately so full-route Flight
47
- * responses do not share the canonical HTML URL in caches that ignore Vary.
48
- * 7. cleanPathname — pathname with `.rsc` suffix stripped
49
- * 8. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)
50
- * 9. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys
51
- * 10. Read semantic render mode for refresh/action payload rendering
43
+ * 6. RSC detection: `RSC: 1`, as in Next.js. A `.rsc` suffix is an ordinary
44
+ * part of the pathname. The internal `_rsc` cache-busting query is
45
+ * validated separately so full-route Flight responses do not share the
46
+ * canonical HTML URL in caches that ignore Vary.
47
+ * 7. Sanitize X-Vinext-Interception-Context — strip null bytes (header injection)
48
+ * 8. Normalize x-vinext-mounted-slots — dedup and sort for canonical cache keys
49
+ * 9. Read semantic render mode for refresh/action payload rendering
52
50
  *
53
51
  * @returns A 400 or 404 Response for invalid or out-of-scope inputs,
54
52
  * or a NormalizedRscRequest for valid requests.