vinext 1.0.0-beta.1 → 1.0.0-beta.2

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 (175) hide show
  1. package/README.md +4 -1
  2. package/dist/build/client-build-config.js +1 -0
  3. package/dist/build/report.d.ts +8 -1
  4. package/dist/build/report.js +12 -2
  5. package/dist/check.js +15 -2
  6. package/dist/cli.js +3 -2
  7. package/dist/config/config-matchers.d.ts +13 -37
  8. package/dist/config/config-matchers.js +31 -121
  9. package/dist/config/next-config.d.ts +3 -2
  10. package/dist/config/next-config.js +3 -1
  11. package/dist/config/request-context.d.ts +14 -0
  12. package/dist/config/request-context.js +26 -0
  13. package/dist/entries/app-rsc-entry.js +27 -9
  14. package/dist/entries/app-rsc-manifest.js +17 -0
  15. package/dist/entries/pages-server-entry.js +3 -2
  16. package/dist/index.js +82 -58
  17. package/dist/init.d.ts +6 -4
  18. package/dist/init.js +20 -22
  19. package/dist/plugins/og-assets.js +1 -1
  20. package/dist/routing/app-route-graph.d.ts +13 -5
  21. package/dist/routing/app-route-graph.js +59 -13
  22. package/dist/routing/app-router.js +12 -6
  23. package/dist/routing/file-matcher.d.ts +11 -22
  24. package/dist/routing/file-matcher.js +21 -33
  25. package/dist/routing/pages-router.js +23 -29
  26. package/dist/routing/route-matching.d.ts +14 -1
  27. package/dist/routing/route-matching.js +13 -1
  28. package/dist/routing/route-pattern.d.ts +2 -1
  29. package/dist/routing/route-pattern.js +7 -4
  30. package/dist/routing/route-trie.d.ts +5 -1
  31. package/dist/routing/route-trie.js +5 -2
  32. package/dist/server/app-browser-entry.js +7 -6
  33. package/dist/server/app-browser-history-controller.d.ts +1 -1
  34. package/dist/server/app-browser-history-controller.js +3 -3
  35. package/dist/server/app-browser-navigation-controller.js +1 -1
  36. package/dist/server/app-browser-state.js +1 -1
  37. package/dist/server/app-browser-visible-commit.js +1 -1
  38. package/dist/server/app-fallback-renderer.d.ts +3 -0
  39. package/dist/server/app-fallback-renderer.js +4 -2
  40. package/dist/server/app-middleware.js +2 -1
  41. package/dist/server/app-page-boundary-render.d.ts +12 -1
  42. package/dist/server/app-page-boundary-render.js +84 -2
  43. package/dist/server/app-page-cache-finalizer.d.ts +1 -1
  44. package/dist/server/app-page-cache.d.ts +1 -1
  45. package/dist/server/app-page-dispatch.d.ts +11 -2
  46. package/dist/server/app-page-dispatch.js +14 -17
  47. package/dist/server/app-page-element-builder.d.ts +7 -2
  48. package/dist/server/app-page-element-builder.js +112 -27
  49. package/dist/server/app-page-head.d.ts +54 -2
  50. package/dist/server/app-page-head.js +164 -78
  51. package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
  52. package/dist/server/app-page-http-access-fallback-metadata.js +106 -0
  53. package/dist/server/app-page-render.d.ts +2 -2
  54. package/dist/server/app-page-render.js +1 -1
  55. package/dist/server/app-page-request.d.ts +12 -0
  56. package/dist/server/app-page-request.js +133 -13
  57. package/dist/server/app-page-route-wiring.d.ts +9 -0
  58. package/dist/server/app-page-route-wiring.js +43 -3
  59. package/dist/server/app-post-middleware-context.d.ts +1 -1
  60. package/dist/server/app-post-middleware-context.js +1 -1
  61. package/dist/server/app-route-handler-dispatch.js +31 -17
  62. package/dist/server/app-route-handler-execution.d.ts +6 -1
  63. package/dist/server/app-route-handler-execution.js +42 -16
  64. package/dist/server/app-route-handler-policy.d.ts +2 -0
  65. package/dist/server/app-route-handler-policy.js +3 -3
  66. package/dist/server/app-route-module-loader.d.ts +3 -1
  67. package/dist/server/app-route-module-loader.js +1 -0
  68. package/dist/server/app-rsc-cache-busting.d.ts +1 -1
  69. package/dist/server/app-rsc-errors.d.ts +1 -1
  70. package/dist/server/app-rsc-errors.js +12 -2
  71. package/dist/server/app-rsc-handler.d.ts +10 -5
  72. package/dist/server/app-rsc-handler.js +52 -24
  73. package/dist/server/app-rsc-request-normalization.d.ts +3 -2
  74. package/dist/server/app-rsc-request-normalization.js +8 -2
  75. package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
  76. package/dist/server/app-rsc-response-finalizer.js +5 -11
  77. package/dist/server/app-rsc-route-matching.d.ts +20 -0
  78. package/dist/server/app-rsc-route-matching.js +87 -11
  79. package/dist/server/app-segment-config.js +13 -3
  80. package/dist/server/app-server-action-execution.d.ts +3 -1
  81. package/dist/server/app-server-action-execution.js +9 -7
  82. package/dist/server/app-ssr-entry.js +2 -2
  83. package/dist/server/app-ssr-stream.d.ts +1 -7
  84. package/dist/server/app-ssr-stream.js +2 -10
  85. package/dist/server/config-headers.d.ts +24 -0
  86. package/dist/server/config-headers.js +52 -0
  87. package/dist/server/dev-initial-server-error.d.ts +1 -1
  88. package/dist/server/dev-server.js +29 -13
  89. package/dist/server/isr-cache.d.ts +1 -1
  90. package/dist/server/middleware-matcher-pattern.d.ts +22 -0
  91. package/dist/server/middleware-matcher-pattern.js +219 -0
  92. package/dist/server/middleware-matcher.d.ts +2 -7
  93. package/dist/server/middleware-matcher.js +13 -60
  94. package/dist/server/middleware-path-to-regexp.d.ts +14 -0
  95. package/dist/server/middleware-path-to-regexp.js +228 -0
  96. package/dist/server/middleware-runtime.js +4 -3
  97. package/dist/server/middleware.d.ts +1 -1
  98. package/dist/server/middleware.js +2 -1
  99. package/dist/server/pages-data-route.d.ts +11 -1
  100. package/dist/server/pages-data-route.js +16 -1
  101. package/dist/server/pages-get-initial-props.d.ts +15 -2
  102. package/dist/server/pages-get-initial-props.js +16 -6
  103. package/dist/server/pages-page-data.d.ts +3 -1
  104. package/dist/server/pages-page-data.js +16 -7
  105. package/dist/server/pages-page-handler.d.ts +4 -2
  106. package/dist/server/pages-page-handler.js +16 -17
  107. package/dist/server/pages-page-response.js +1 -1
  108. package/dist/server/pages-readiness.d.ts +3 -3
  109. package/dist/server/pages-request-pipeline.d.ts +1 -0
  110. package/dist/server/pages-request-pipeline.js +25 -11
  111. package/dist/server/pages-router-entry.js +6 -0
  112. package/dist/server/prerender-route-params.js +2 -2
  113. package/dist/server/prod-server.d.ts +1 -4
  114. package/dist/server/prod-server.js +36 -23
  115. package/dist/server/request-pipeline.d.ts +15 -29
  116. package/dist/server/request-pipeline.js +24 -59
  117. package/dist/server/rsc-stream-hints.js +122 -18
  118. package/dist/shims/app.d.ts +1 -1
  119. package/dist/shims/cache-request-state.d.ts +27 -1
  120. package/dist/shims/cache-request-state.js +60 -1
  121. package/dist/shims/cache-runtime.d.ts +12 -1
  122. package/dist/shims/cache-runtime.js +22 -7
  123. package/dist/shims/cache.d.ts +5 -5
  124. package/dist/shims/cache.js +26 -10
  125. package/dist/shims/document.d.ts +42 -83
  126. package/dist/shims/document.js +62 -53
  127. package/dist/shims/dynamic.d.ts +5 -25
  128. package/dist/shims/dynamic.js +29 -8
  129. package/dist/shims/error.d.ts +1 -1
  130. package/dist/shims/error.js +1 -1
  131. package/dist/shims/fetch-cache.js +12 -3
  132. package/dist/shims/font-google-base.d.ts +11 -4
  133. package/dist/shims/font-local.d.ts +10 -3
  134. package/dist/shims/head.d.ts +13 -2
  135. package/dist/shims/head.js +3 -3
  136. package/dist/shims/headers.d.ts +28 -31
  137. package/dist/shims/headers.js +109 -49
  138. package/dist/shims/image.d.ts +27 -37
  139. package/dist/shims/image.js +21 -14
  140. package/dist/shims/internal/cookie-serialize.d.ts +3 -1
  141. package/dist/shims/internal/cookie-serialize.js +3 -1
  142. package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
  143. package/dist/shims/internal/utils.d.ts +3 -3
  144. package/dist/shims/legacy-image.d.ts +3 -37
  145. package/dist/shims/legacy-image.js +6 -16
  146. package/dist/shims/link.d.ts +15 -22
  147. package/dist/shims/link.js +20 -11
  148. package/dist/shims/navigation-context-state.d.ts +1 -1
  149. package/dist/shims/navigation.d.ts +7 -3
  150. package/dist/shims/navigation.js +24 -13
  151. package/dist/shims/navigation.react-server.js +1 -1
  152. package/dist/shims/next-shims-augmentations.d.ts +1 -0
  153. package/dist/shims/next-shims-public.d.ts +1 -0
  154. package/dist/shims/public-shim-map.json.js +103 -0
  155. package/dist/shims/readonly-url-search-params.d.ts +3 -3
  156. package/dist/shims/readonly-url-search-params.js +3 -3
  157. package/dist/shims/request-state-types.d.ts +1 -1
  158. package/dist/shims/router.d.ts +55 -21
  159. package/dist/shims/router.js +162 -37
  160. package/dist/shims/script.d.ts +6 -10
  161. package/dist/shims/script.js +6 -3
  162. package/dist/shims/server.d.ts +45 -22
  163. package/dist/shims/server.js +44 -5
  164. package/dist/shims/unified-request-context.d.ts +1 -1
  165. package/dist/shims/unified-request-context.js +2 -0
  166. package/dist/shims/url-safety.d.ts +1 -1
  167. package/dist/shims/url-safety.js +2 -2
  168. package/dist/typegen.d.ts +8 -2
  169. package/dist/typegen.js +76 -15
  170. package/dist/utils/domain-locale.d.ts +2 -2
  171. package/dist/utils/external-url.d.ts +5 -0
  172. package/dist/utils/external-url.js +7 -0
  173. package/dist/utils/regex-safety.d.ts +8 -0
  174. package/dist/utils/regex-safety.js +737 -0
  175. package/package.json +13 -2
@@ -1,15 +1,27 @@
1
+ import { NEVER_CACHE_CONTROL, applyCdnResponseHeaders } from "./cache-control.js";
1
2
  import { isDraftModeRequest, setHeadersContext } from "../shims/headers.js";
2
- import { runWithRootParamsUsage } from "../shims/root-params.js";
3
+ import { _drainPendingRevalidations } from "../shims/cache-request-state.js";
3
4
  import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
5
+ import { runWithRootParamsUsage } from "../shims/root-params.js";
4
6
  import { applyRouteHandlerMiddlewareContext, applyRouteHandlerRevalidateHeader, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, finalizeRouteHandlerResponse, markRouteHandlerCacheMiss } from "./app-route-handler-response.js";
5
7
  import { createTrackedAppRouteRequest, markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
6
8
  import { createStaticGenerationHeadersContext, getAppRouteStaticGenerationErrorMessage } from "./app-static-generation.js";
7
9
  import { resolveAppRouteHandlerSpecialError, shouldApplyAppRouteHandlerRevalidateHeader, shouldWriteAppRouteHandlerCache } from "./app-route-handler-policy.js";
8
10
  //#region src/server/app-route-handler-execution.ts
11
+ function applyDraftModeCachePolicy(response, isDraftMode) {
12
+ if (!isDraftMode) return response;
13
+ const headers = new Headers(response.headers);
14
+ applyCdnResponseHeaders(headers, { cacheControl: NEVER_CACHE_CONTROL });
15
+ return new Response(response.body, {
16
+ status: response.status,
17
+ statusText: response.statusText,
18
+ headers
19
+ });
20
+ }
9
21
  function configureAppRouteStaticGenerationContext(options) {
10
22
  if (options.dynamicConfig === "force-static" || options.dynamicConfig === "error") {
11
23
  setHeadersContext(createStaticGenerationHeadersContext({
12
- draftModeEnabled: options.draftModeSecret !== void 0 && isDraftModeRequest(options.request, options.draftModeSecret),
24
+ draftModeEnabled: options.isDraftMode ?? (options.draftModeSecret !== void 0 && isDraftModeRequest(options.request, options.draftModeSecret)),
13
25
  draftModeSecret: options.draftModeSecret,
14
26
  dynamicConfig: options.dynamicConfig,
15
27
  routeKind: "route",
@@ -46,18 +58,30 @@ async function runAppRouteHandler(options) {
46
58
  async function executeAppRouteHandler(options) {
47
59
  const previousHeadersPhase = options.setHeadersAccessPhase("route-handler");
48
60
  try {
49
- const { dynamicUsedInHandler, response } = await runAppRouteHandler({
50
- ...options,
51
- dynamicConfig: options.handler.dynamic
52
- });
61
+ let handlerResult;
62
+ try {
63
+ handlerResult = await runAppRouteHandler({
64
+ ...options,
65
+ dynamicConfig: options.handler.dynamic
66
+ });
67
+ } finally {
68
+ await _drainPendingRevalidations();
69
+ }
70
+ const { dynamicUsedInHandler, response } = handlerResult;
53
71
  assertSupportedAppRouteHandlerResponse(response);
54
72
  const handlerSetCacheControl = response.headers.has("cache-control");
55
73
  if (dynamicUsedInHandler) markKnownDynamicAppRoute(options.routePattern);
74
+ const pendingCookies = options.getAndClearPendingCookies();
75
+ const handlerDraftCookie = options.getDraftModeCookieHeader();
76
+ const draftCookie = handlerDraftCookie ?? options.initialDraftModeCookie;
77
+ const shouldApplyDraftPolicy = (options.getActiveDraftModeState?.() ?? options.isDraftMode === true) || draftCookie != null;
78
+ if (handlerDraftCookie != null) markKnownDynamicAppRoute(options.routePattern);
56
79
  const routeTags = options.buildPageCacheTags(options.cleanPathname, options.getCollectedFetchTags());
57
80
  if (shouldApplyAppRouteHandlerRevalidateHeader({
58
81
  dynamicUsedInHandler,
59
82
  handlerSetCacheControl,
60
83
  isAutoHead: options.isAutoHead,
84
+ isDraftMode: shouldApplyDraftPolicy,
61
85
  method: options.method,
62
86
  revalidateSeconds: options.revalidateSeconds
63
87
  })) {
@@ -70,6 +94,7 @@ async function executeAppRouteHandler(options) {
70
94
  dynamicUsedInHandler,
71
95
  handlerSetCacheControl,
72
96
  isAutoHead: options.isAutoHead,
97
+ isDraftMode: shouldApplyDraftPolicy,
73
98
  isProduction: options.isProduction,
74
99
  method: options.method,
75
100
  revalidateSeconds: options.revalidateSeconds
@@ -90,29 +115,30 @@ async function executeAppRouteHandler(options) {
90
115
  })();
91
116
  options.executionContext?.waitUntil(routeWritePromise);
92
117
  }
93
- const pendingCookies = options.getAndClearPendingCookies();
94
- const draftCookie = options.getDraftModeCookieHeader();
95
118
  options.clearRequestContext();
96
- return applyRouteHandlerMiddlewareContext(finalizeRouteHandlerResponse(response, {
119
+ return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(finalizeRouteHandlerResponse(response, {
97
120
  pendingCookies,
98
121
  draftCookie,
99
122
  isHead: options.isAutoHead
100
- }), options.middlewareContext);
123
+ }), options.middlewareContext), shouldApplyDraftPolicy);
101
124
  } catch (error) {
102
125
  const pendingCookies = options.getAndClearPendingCookies();
103
- const draftCookie = options.getDraftModeCookieHeader();
126
+ const handlerDraftCookie = options.getDraftModeCookieHeader();
127
+ const draftCookie = handlerDraftCookie ?? options.initialDraftModeCookie;
128
+ const shouldApplyDraftPolicy = (options.getActiveDraftModeState?.() ?? options.isDraftMode === true) || draftCookie != null;
129
+ if (handlerDraftCookie != null) markKnownDynamicAppRoute(options.routePattern);
104
130
  const specialError = resolveAppRouteHandlerSpecialError(error, options.request.url, { isAction: isPossibleAppRouteActionRequest(options.request) });
105
131
  options.clearRequestContext();
106
132
  if (specialError) {
107
- if (specialError.kind === "redirect") return applyRouteHandlerMiddlewareContext(finalizeRouteHandlerResponse(new Response(null, {
133
+ if (specialError.kind === "redirect") return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(finalizeRouteHandlerResponse(new Response(null, {
108
134
  status: specialError.statusCode,
109
135
  headers: { Location: specialError.location }
110
136
  }), {
111
137
  pendingCookies,
112
138
  draftCookie,
113
139
  isHead: options.isAutoHead
114
- }), options.middlewareContext);
115
- return applyRouteHandlerMiddlewareContext(new Response(null, { status: specialError.statusCode }), options.middlewareContext);
140
+ }), options.middlewareContext), shouldApplyDraftPolicy);
141
+ return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(new Response(null, { status: specialError.statusCode }), options.middlewareContext), shouldApplyDraftPolicy);
116
142
  }
117
143
  console.error("[vinext] Route handler error:", error);
118
144
  options.reportRequestError(error instanceof Error ? error : new Error(String(error)), {
@@ -124,10 +150,10 @@ async function executeAppRouteHandler(options) {
124
150
  routePath: options.routePattern,
125
151
  routeType: "route"
126
152
  });
127
- return applyRouteHandlerMiddlewareContext(new Response(null, { status: 500 }), options.middlewareContext);
153
+ return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(new Response(null, { status: 500 }), options.middlewareContext), shouldApplyDraftPolicy);
128
154
  } finally {
129
155
  options.setHeadersAccessPhase(previousHeadersPhase);
130
156
  }
131
157
  }
132
158
  //#endregion
133
- export { executeAppRouteHandler, runAppRouteHandler };
159
+ export { applyDraftModeCachePolicy, executeAppRouteHandler, runAppRouteHandler };
@@ -20,6 +20,7 @@ type AppRouteHandlerCacheReadOptions = {
20
20
  handlerFn: unknown;
21
21
  isAutoHead: boolean;
22
22
  isKnownDynamic: boolean;
23
+ isDraftMode?: boolean;
23
24
  isProduction: boolean;
24
25
  method: string;
25
26
  revalidateSeconds: number | null;
@@ -29,6 +30,7 @@ type AppRouteHandlerResponseCacheOptions = {
29
30
  dynamicUsedInHandler: boolean;
30
31
  handlerSetCacheControl: boolean;
31
32
  isAutoHead: boolean;
33
+ isDraftMode?: boolean;
32
34
  isProduction: boolean;
33
35
  method: string;
34
36
  revalidateSeconds: number | null;
@@ -30,13 +30,13 @@ function resolveAppRouteHandlerMethod(handler, method) {
30
30
  };
31
31
  }
32
32
  function shouldReadAppRouteHandlerCache(options) {
33
- return options.isProduction && options.revalidateSeconds !== null && options.revalidateSeconds > 0 && options.revalidateSeconds !== Infinity && options.dynamicConfig !== "force-dynamic" && !options.isKnownDynamic && (options.method === "GET" || options.isAutoHead) && typeof options.handlerFn === "function";
33
+ return options.isProduction && options.revalidateSeconds !== null && options.revalidateSeconds > 0 && options.revalidateSeconds !== Infinity && options.dynamicConfig !== "force-dynamic" && !options.isDraftMode && !options.isKnownDynamic && (options.method === "GET" || options.isAutoHead) && typeof options.handlerFn === "function";
34
34
  }
35
35
  function shouldApplyAppRouteHandlerRevalidateHeader(options) {
36
- return options.revalidateSeconds !== null && !options.dynamicUsedInHandler && (options.method === "GET" || options.isAutoHead) && !options.handlerSetCacheControl;
36
+ return options.revalidateSeconds !== null && !options.isDraftMode && !options.dynamicUsedInHandler && (options.method === "GET" || options.isAutoHead) && !options.handlerSetCacheControl;
37
37
  }
38
38
  function shouldWriteAppRouteHandlerCache(options) {
39
- return options.isProduction && options.revalidateSeconds !== null && options.revalidateSeconds > 0 && options.revalidateSeconds !== Infinity && options.dynamicConfig !== "force-dynamic" && shouldApplyAppRouteHandlerRevalidateHeader(options);
39
+ return options.isProduction && options.revalidateSeconds !== null && options.revalidateSeconds > 0 && options.revalidateSeconds !== Infinity && options.dynamicConfig !== "force-dynamic" && !options.isDraftMode && shouldApplyAppRouteHandlerRevalidateHeader(options);
40
40
  }
41
41
  function resolveAppRouteHandlerSpecialError(error, requestUrl, options) {
42
42
  if (!(error && typeof error === "object" && "digest" in error)) return null;
@@ -39,12 +39,14 @@ type LazyLoadableSlot = {
39
39
  configLayouts?: readonly unknown[];
40
40
  loading?: unknown;
41
41
  error?: unknown;
42
+ notFound?: unknown;
42
43
  __loadPage?: LazyModuleThunk | null;
43
44
  __loadDefault?: LazyModuleThunk | null;
44
45
  __loadLayout?: LazyModuleThunk | null;
45
46
  __loadConfigLayouts?: LazyModuleLoaderArray | null;
46
47
  __loadLoading?: LazyModuleThunk | null;
47
- __loadError?: LazyModuleThunk | null; /** Hydrated only after an intercept matches, not with the slot's base modules. */
48
+ __loadError?: LazyModuleThunk | null;
49
+ __loadNotFound?: LazyModuleThunk | null; /** Hydrated only after an intercept matches, not with the slot's base modules. */
48
50
  intercepts?: LazyLoadableIntercept[];
49
51
  };
50
52
  type LazyLoadableRoute = {
@@ -64,6 +64,7 @@ function ensureAppRouteModulesLoaded(route) {
64
64
  pushArrayLoads(loads, slot.configLayouts, slot.__loadConfigLayouts);
65
65
  pushFieldLoad(loads, slot, "loading", slot.__loadLoading);
66
66
  pushFieldLoad(loads, slot, "error", slot.__loadError);
67
+ pushFieldLoad(loads, slot, "notFound", slot.__loadNotFound);
67
68
  }
68
69
  if (loads.length === 0) {
69
70
  route.__loaded = true;
@@ -1,5 +1,5 @@
1
- import { VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
2
1
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
2
+ import { VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
3
3
 
4
4
  //#region src/server/app-rsc-cache-busting.d.ts
5
5
  /**
@@ -34,7 +34,7 @@ declare function getDigestForWellKnownError(error: unknown): string | undefined;
34
34
  * djb2 hash matching Next.js's string-hash package for RSC error digests.
35
35
  */
36
36
  declare function errorDigest(input: string): string;
37
- declare function sanitizeErrorForClient(error: unknown, nodeEnv?: string | undefined): unknown;
37
+ declare function sanitizeErrorForClient(error: unknown, nodeEnv?: "development" | "production" | "test"): unknown;
38
38
  declare function createRscOnErrorHandler(options: CreateRscOnErrorHandlerOptions): (error: unknown) => string | undefined;
39
39
  //#endregion
40
40
  export { createRscOnErrorHandler, errorDigest, getDigestForWellKnownError, hasDigest, sanitizeErrorForClient };
@@ -1,6 +1,7 @@
1
1
  import { isNavigationSignalError } from "../utils/navigation-signal.js";
2
2
  import { resolveAppPageSpecialError } from "./app-page-execution.js";
3
3
  //#region src/server/app-rsc-errors.ts
4
+ const ORIGINAL_SERVER_ERROR = Symbol.for("vinext.originalServerError");
4
5
  function hasDigest(error) {
5
6
  return Boolean(error && typeof error === "object" && "digest" in error);
6
7
  }
@@ -39,7 +40,13 @@ function sanitizeErrorForClient(error, nodeEnv = process.env.NODE_ENV) {
39
40
  if (resolveAppPageSpecialError(error)) return error;
40
41
  if (nodeEnv !== "production") return error;
41
42
  const sanitized = /* @__PURE__ */ new Error("An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error.");
42
- sanitized.digest = errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));
43
+ sanitized.digest = hasDigest(error) ? String(error.digest) : errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));
44
+ Object.defineProperty(sanitized, ORIGINAL_SERVER_ERROR, {
45
+ configurable: false,
46
+ enumerable: false,
47
+ value: error,
48
+ writable: false
49
+ });
43
50
  return sanitized;
44
51
  }
45
52
  function createRscOnErrorHandler(options) {
@@ -51,7 +58,10 @@ function createRscOnErrorHandler(options) {
51
58
  console.error("[vinext] RSC serialization error: a non-plain object was passed from a Server Component to a Client Component.\n\nCommon causes:\n * Passing a module namespace (import * as X) directly as a prop.\n Unlike Next.js (webpack), Vite produces real ESM module namespace objects\n which are not serializable. Fix: pass individual values instead,\n e.g. <Comp value={module.value} />\n * Passing a class instance (new Foo()) as a prop.\n Fix: convert to a plain object, e.g. { id: foo.id, name: foo.name }\n * Passing a Date, Map, or Set. Use .toISOString(), [...map.entries()], etc.\n * Passing Object.create(null). Use { ...obj } to restore a prototype.\n\nOriginal error:", error.message);
52
59
  return;
53
60
  }
54
- if (options.requestInfo && options.errorContext && error) options.reportRequestError(error instanceof Error ? error : new Error(getThrownValueMessage(error)), options.requestInfo, options.errorContext);
61
+ if (options.requestInfo && options.errorContext && error) {
62
+ const reportableError = typeof error === "object" && ORIGINAL_SERVER_ERROR in error ? Reflect.get(error, ORIGINAL_SERVER_ERROR) : error;
63
+ options.reportRequestError(reportableError instanceof Error ? reportableError : new Error(getThrownValueMessage(reportableError)), options.requestInfo, options.errorContext);
64
+ }
55
65
  if (hasDigest(error)) return String(error.digest);
56
66
  if (error) {
57
67
  const digest = errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));
@@ -1,9 +1,9 @@
1
1
  import { NextHeader, NextI18nConfig, NextRedirect, NextRewrite } from "../config/next-config.js";
2
2
  import { ImageConfig } from "./image-optimization.js";
3
3
  import { ClientReuseManifestParseResult } from "./client-reuse-manifest.js";
4
+ import { AppRscRenderMode } from "./app-rsc-render-mode.js";
4
5
  import { RootParams } from "../shims/root-params.js";
5
6
  import { AppMiddlewareContext, ApplyAppMiddlewareResult } from "./app-middleware.js";
6
- import { AppRscRenderMode } from "./app-rsc-render-mode.js";
7
7
  import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
8
8
  import { AppPrerenderRootParamNamesMap, AppPrerenderStaticParamsMap } from "./app-prerender-endpoints.js";
9
9
  import { AppRouteTreePrefetchRoute, PrefetchInliningConfig } from "./app-route-tree-prefetch.js";
@@ -48,6 +48,7 @@ type DispatchMatchedPageOptions<TRoute> = {
48
48
  actionFailed?: boolean;
49
49
  handlerStart: number;
50
50
  interceptionContext: string | null;
51
+ interceptionPathname: string;
51
52
  isProgressiveActionRender: boolean;
52
53
  isRscRequest: boolean;
53
54
  middlewareContext: AppRscMiddlewareContext;
@@ -87,12 +88,13 @@ type DispatchMatchedRouteHandlerOptions<TRoute> = {
87
88
  route: TRoute;
88
89
  searchParams: URLSearchParams;
89
90
  };
90
- type HandleProgressiveActionRequestOptions = {
91
+ type HandleProgressiveActionRequestOptions<TRoute> = {
91
92
  actionId: string | null;
92
93
  cleanPathname: string;
93
94
  contentType: string;
94
95
  middlewareContext: AppRscMiddlewareContext;
95
96
  request: Request;
97
+ routeMatch: AppRscRouteMatch<TRoute> | null;
96
98
  };
97
99
  /**
98
100
  * Side-effect headers captured during a progressive (no-JS) server action's
@@ -114,7 +116,7 @@ type ProgressiveActionFormStateResult = ({
114
116
  formState: null;
115
117
  kind: "form-state";
116
118
  } & ProgressiveActionSideEffects);
117
- type HandleServerActionRequestOptions = {
119
+ type HandleServerActionRequestOptions<TRoute> = {
118
120
  actionId: string | null;
119
121
  cleanPathname: string;
120
122
  contentType: string;
@@ -123,6 +125,8 @@ type HandleServerActionRequestOptions = {
123
125
  middlewareContext: AppRscMiddlewareContext;
124
126
  mountedSlotsHeader: string | null;
125
127
  request: Request;
128
+ routeMatch: AppRscRouteMatch<TRoute> | null;
129
+ routePathname: string;
126
130
  searchParams: URLSearchParams;
127
131
  };
128
132
  type RenderNotFoundOptions<TRoute> = {
@@ -183,15 +187,16 @@ type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
183
187
  * Node server and dev included, not just the Cloudflare worker entry.
184
188
  */
185
189
  registerCacheAdapters: (env?: Record<string, unknown>) => void;
186
- handleProgressiveActionRequest?: (options: HandleProgressiveActionRequestOptions) => Promise<Response | ProgressiveActionFormStateResult | null>;
190
+ handleProgressiveActionRequest?: (options: HandleProgressiveActionRequestOptions<TRoute>) => Promise<Response | ProgressiveActionFormStateResult | null>;
187
191
  handleMetadataRouteRequest?: (cleanPathname: string) => Promise<Response | null>;
188
192
  createPprFallbackShells?: (route: Pick<AppRscHandlerRoute, "params" | "pattern" | "rootParamNames">, params: AppPageParams) => AppPagePprFallbackCacheShell[];
189
- handleServerActionRequest?: (options: HandleServerActionRequestOptions) => Promise<Response | null>;
193
+ handleServerActionRequest?: (options: HandleServerActionRequestOptions<TRoute>) => Promise<Response | null>;
190
194
  i18nConfig: NextI18nConfig | null;
191
195
  imageConfig?: ImageConfig;
192
196
  isDev: boolean;
193
197
  loadPrerenderPagesRoutes?: () => Promise<unknown>;
194
198
  matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;
199
+ matchRequestRoute?: (pathname: string) => AppRscRouteMatch<TRoute> | null;
195
200
  runMiddleware?: (options: RunAppMiddlewareOptions) => Promise<ApplyAppMiddlewareResult>;
196
201
  publicFiles: ReadonlySet<string>;
197
202
  prefetchInlining?: PrefetchInliningConfig;
@@ -3,9 +3,10 @@ import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base
3
3
  import { getRequestExecutionContext } from "../shims/request-context.js";
4
4
  import { VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
5
5
  import { ACTION_REVALIDATED_HEADER } from "./headers.js";
6
- import { isExternalUrl, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
6
+ import { requestContextFromRequest } from "../config/request-context.js";
7
+ import { isExternalUrl } from "../utils/external-url.js";
7
8
  import { notFoundResponse } from "./http-error-responses.js";
8
- import { applyConfigHeadersToResponse, cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute } from "./request-pipeline.js";
9
+ import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute } from "./request-pipeline.js";
9
10
  import { headersContextFromRequest } from "../shims/headers.js";
10
11
  import { ensureFetchPatch, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
11
12
  import { mergeRewriteQuery } from "../utils/query.js";
@@ -19,17 +20,20 @@ import "./app-page-response.js";
19
20
  import { parseNextHttpErrorDigest } from "./next-error-digest.js";
20
21
  import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
21
22
  import { getRenderedConcreteUrlPathsForRoute } from "./pregenerated-concrete-paths.js";
22
- import { flattenErrorCauses } from "../utils/error-cause.js";
23
- import { pickRootParams, setRootParams } from "../shims/root-params.js";
24
23
  import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
25
24
  import { buildPageCacheTags } from "./implicit-tags.js";
26
25
  import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
26
+ import { pickRootParams, setRootParams } from "../shims/root-params.js";
27
27
  import { createRouteTreePrefetchResponse, isRouteTreePrefetchRequest } from "./app-route-tree-prefetch.js";
28
+ import { flattenErrorCauses } from "../utils/error-cause.js";
28
29
  import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
29
30
  import { normalizeRscRequest } from "./app-rsc-request-normalization.js";
30
31
  import { runWithPrerenderWorkUnit } from "./prerender-work-unit-setup.js";
31
32
  //#region src/server/app-rsc-handler.ts
32
33
  const STATIC_METADATA_CONFIG_HEADER_OVERRIDES = /* @__PURE__ */ new Set(["cache-control"]);
34
+ const HAS_CONFIG_HEADERS = process.env.__VINEXT_HAS_CONFIG_HEADERS !== "false";
35
+ const HAS_CONFIG_REDIRECTS = process.env.__VINEXT_HAS_CONFIG_REDIRECTS !== "false";
36
+ const HAS_CONFIG_REWRITES = process.env.__VINEXT_HAS_CONFIG_REWRITES !== "false";
33
37
  function applyMiddlewareContextToResponse(response, middlewareContext) {
34
38
  if (!middlewareContext.headers && middlewareContext.status == null) return response;
35
39
  const headers = new Headers(response.headers);
@@ -61,12 +65,14 @@ function redirectDestinationWithBasePath(destination, basePath, hadBasePath) {
61
65
  return basePath + destination;
62
66
  }
63
67
  async function applyRewrite(options, cleanPathname) {
64
- if (!options.rewrites.length) return null;
65
- const rewritten = matchRewrite(cleanPathname, options.rewrites, options.requestContext, options.basePathState);
68
+ if (!HAS_CONFIG_REWRITES || !options.rewrites.length) return null;
69
+ const sourcePathname = options.paramsPathname ?? cleanPathname;
70
+ const configMatchers = await import("../config/config-matchers.js");
71
+ const rewritten = configMatchers.matchRewrite(sourcePathname, options.rewrites, options.requestContext, options.basePathState, options.paramsPathname);
66
72
  if (!rewritten) return null;
67
73
  if (isExternalUrl(rewritten)) {
68
74
  options.clearRequestContext();
69
- return proxyExternalRequest(options.request, rewritten);
75
+ return configMatchers.proxyExternalRequest(options.request, rewritten);
70
76
  }
71
77
  return rewritten;
72
78
  }
@@ -81,9 +87,10 @@ function requestContextForResolvedUrl(requestContext, resolvedUrl, baseUrl) {
81
87
  function pathnameForResolvedUrl(resolvedUrl) {
82
88
  return resolvedUrl.split("#", 1)[0].split("?", 1)[0];
83
89
  }
84
- function applyConfigHeadersToMiddlewareRedirect(response, options) {
90
+ async function applyConfigHeadersToMiddlewareRedirect(response, options) {
85
91
  if (response.status < 300 || response.status >= 400) return response;
86
- if (!options.configHeaders.length) return response;
92
+ if (!HAS_CONFIG_HEADERS || !options.configHeaders.length) return response;
93
+ const { applyConfigHeadersToResponse } = await import("./config-headers.js");
87
94
  const headers = new Headers();
88
95
  applyConfigHeadersToResponse(headers, {
89
96
  configHeaders: options.configHeaders,
@@ -130,6 +137,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
130
137
  const normalized = normalizeRscRequest(request, options.basePath, canHandleOutsideBasePath);
131
138
  if (normalized instanceof Response) return normalized;
132
139
  const { url, isRscRequest, interceptionContextHeader, mountedSlotsHeader, renderMode, clientReuseManifest, hadBasePath } = normalized;
140
+ const { requestCleanPathname } = normalized;
133
141
  let { pathname, cleanPathname } = normalized;
134
142
  let resolvedUrl = cleanPathname + url.search;
135
143
  const originalResolvedUrl = resolvedUrl;
@@ -139,6 +147,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
139
147
  basePath: options.basePath,
140
148
  hadBasePath
141
149
  };
150
+ let cleanPathnameIsRequestPathname = true;
151
+ const matchCleanPathname = () => cleanPathnameIsRequestPathname && options.matchRequestRoute ? options.matchRequestRoute(requestCleanPathname) : options.matchRoute(cleanPathname);
142
152
  if (pathname === "/__vinext/prerender/static-params" || pathname === "/__vinext/prerender/pages-static-paths") {
143
153
  const { handleAppPrerenderEndpoint } = await import("./app-prerender-endpoints.js");
144
154
  const prerenderEndpointResponse = await handleAppPrerenderEndpoint(request, {
@@ -152,13 +162,15 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
152
162
  });
153
163
  if (prerenderEndpointResponse) return prerenderEndpointResponse;
154
164
  }
155
- const trailingSlashRedirect = normalizeTrailingSlash(pathname, hadBasePath ? options.basePath : "", options.trailingSlash, url.search);
165
+ const trailingSlashRedirect = normalizeTrailingSlash(requestCleanPathname, hadBasePath ? options.basePath : "", options.trailingSlash, url.search);
156
166
  if (trailingSlashRedirect) return trailingSlashRedirect;
157
167
  const matchPathname = (p) => normalizeDefaultLocalePathname(p, options.i18nConfig, { hostname: url.hostname });
158
- const redirect = matchRedirect(matchPathname(stripRscSuffix(pathname)), options.configRedirects, preMiddlewareRequestContext, basePathState);
159
- if (redirect) {
160
- const destination = sanitizeDestination(redirectDestinationWithBasePath(redirect.destination, options.basePath, hadBasePath));
161
- const location = isRscRequest && request.headers.get("RSC") === "1" ? await createRscRedirectLocation(destination, request) : preserveRedirectDestinationQuery(destination, url.search);
168
+ const redirectPathname = matchPathname(requestCleanPathname);
169
+ const configMatchers = HAS_CONFIG_REDIRECTS && options.configRedirects.length ? await import("../config/config-matchers.js") : null;
170
+ const redirect = configMatchers ? configMatchers.matchRedirect(redirectPathname, options.configRedirects, preMiddlewareRequestContext, basePathState) : null;
171
+ if (configMatchers && redirect) {
172
+ const destination = configMatchers.sanitizeDestination(redirectDestinationWithBasePath(redirect.destination, options.basePath, hadBasePath));
173
+ const location = isRscRequest && request.headers.get("RSC") === "1" ? await createRscRedirectLocation(destination, request) : configMatchers.preserveRedirectDestinationQuery(destination, url.search);
162
174
  return new Response(null, {
163
175
  status: redirect.permanent ? 308 : 307,
164
176
  headers: { Location: location }
@@ -189,11 +201,12 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
189
201
  if (middlewareResult.kind === "response") return applyConfigHeadersToMiddlewareRedirect(middlewareResult.response, {
190
202
  basePathState,
191
203
  configHeaders: options.configHeaders,
192
- pathname: matchPathname(cleanPathname),
204
+ pathname: matchPathname(requestCleanPathname),
193
205
  requestContext: preMiddlewareRequestContext
194
206
  });
195
207
  cleanPathname = middlewareResult.cleanPathname;
196
208
  didMiddlewareRewrite = middlewareResult.rewritten;
209
+ if (didMiddlewareRewrite || cleanPathname !== normalized.cleanPathname) cleanPathnameIsRequestPathname = false;
197
210
  didMiddlewareRewritePathname = cleanPathname !== normalized.cleanPathname;
198
211
  if (middlewareResult.search !== null) url.search = middlewareResult.search;
199
212
  resolvedUrl = cleanPathname + url.search;
@@ -214,12 +227,14 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
214
227
  clearRequestContext: options.clearRequestContext,
215
228
  request: normalizedUserlandRequest,
216
229
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
230
+ paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
217
231
  rewrites: [rewrite]
218
232
  }, matchPathname(cleanPathname));
219
233
  if (beforeFilesRewrite instanceof Response) return beforeFilesRewrite;
220
234
  if (beforeFilesRewrite) {
221
235
  resolvedUrl = mergeRewriteQuery(resolvedUrl, beforeFilesRewrite);
222
236
  cleanPathname = pathnameForResolvedUrl(resolvedUrl);
237
+ cleanPathnameIsRequestPathname = false;
223
238
  filesystemRouteEligible = true;
224
239
  }
225
240
  }
@@ -238,14 +253,16 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
238
253
  clearRequestContext: options.clearRequestContext,
239
254
  request: normalizedUserlandRequest,
240
255
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
256
+ paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
241
257
  rewrites: [rewrite]
242
258
  }, matchPathname(cleanPathname));
243
259
  if (rewritten instanceof Response) return rewritten;
244
260
  if (!rewritten) continue;
245
261
  resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
246
262
  cleanPathname = pathnameForResolvedUrl(resolvedUrl);
263
+ cleanPathnameIsRequestPathname = false;
247
264
  filesystemRouteEligible = true;
248
- actionMatch = options.matchRoute(cleanPathname);
265
+ actionMatch = matchCleanPathname();
249
266
  if (actionMatch) break;
250
267
  }
251
268
  if (!actionMatch) for (const rewrite of options.configRewrites.fallback) {
@@ -254,14 +271,16 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
254
271
  clearRequestContext: options.clearRequestContext,
255
272
  request: normalizedUserlandRequest,
256
273
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
274
+ paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
257
275
  rewrites: [rewrite]
258
276
  }, matchPathname(cleanPathname));
259
277
  if (rewritten instanceof Response) return rewritten;
260
278
  if (!rewritten) continue;
261
279
  resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
262
280
  cleanPathname = pathnameForResolvedUrl(resolvedUrl);
281
+ cleanPathnameIsRequestPathname = false;
263
282
  filesystemRouteEligible = true;
264
- actionMatch = options.matchRoute(cleanPathname);
283
+ actionMatch = matchCleanPathname();
265
284
  if (actionMatch) break;
266
285
  }
267
286
  resolvedLateRewritesForAction = filesystemRouteEligible;
@@ -275,16 +294,17 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
275
294
  }
276
295
  if (filesystemRouteEligible && options.handleMetadataRouteRequest) {
277
296
  const metadataRouteResponse = await options.handleMetadataRouteRequest(cleanPathname);
278
- if (metadataRouteResponse) {
297
+ if (metadataRouteResponse && HAS_CONFIG_HEADERS && options.configHeaders.length) {
298
+ const { applyConfigHeadersToResponse } = await import("./config-headers.js");
279
299
  applyConfigHeadersToResponse(metadataRouteResponse.headers, {
280
300
  basePathState,
281
301
  configHeaders: options.configHeaders,
282
302
  overwriteExisting: STATIC_METADATA_CONFIG_HEADER_OVERRIDES,
283
- pathname: matchPathname(cleanPathname),
303
+ pathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
284
304
  requestContext: preMiddlewareRequestContext
285
305
  });
286
- return applyMiddlewareContextToResponse(metadataRouteResponse, middlewareContext);
287
306
  }
307
+ if (metadataRouteResponse) return applyMiddlewareContextToResponse(metadataRouteResponse, middlewareContext);
288
308
  }
289
309
  const publicFileResponse = filesystemRouteEligible ? resolvePublicFileRoute({
290
310
  cleanPathname,
@@ -306,7 +326,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
306
326
  searchParams: getResolvedSearchParams(),
307
327
  params: {}
308
328
  });
309
- const preActionMatch = filesystemRouteEligible ? options.matchRoute(cleanPathname) : null;
329
+ const preActionMatch = filesystemRouteEligible ? matchCleanPathname() : null;
310
330
  if (preActionMatch) setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));
311
331
  if (pagesDataRequest && didMiddlewareRewritePathname && preActionMatch) {
312
332
  const headers = new Headers();
@@ -327,7 +347,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
327
347
  cleanPathname,
328
348
  contentType,
329
349
  middlewareContext,
330
- request
350
+ request,
351
+ routeMatch: preActionMatch
331
352
  });
332
353
  else if (preActionMatch?.route.__loadPage && !preActionMatch.route.__loadRouteHandler) return createMissingServerActionResponse(options, null);
333
354
  }
@@ -351,6 +372,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
351
372
  middlewareContext,
352
373
  mountedSlotsHeader,
353
374
  request,
375
+ routeMatch: preActionMatch,
376
+ routePathname: cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname,
354
377
  searchParams: getResolvedSearchParams()
355
378
  }) : null;
356
379
  if (serverActionResponse) return serverActionResponse;
@@ -390,16 +413,18 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
390
413
  clearRequestContext: options.clearRequestContext,
391
414
  request: normalizedUserlandRequest,
392
415
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
416
+ paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
393
417
  rewrites: [rewrite]
394
418
  }, matchPathname(cleanPathname));
395
419
  if (afterFilesRewrite instanceof Response) return afterFilesRewrite;
396
420
  if (!afterFilesRewrite) continue;
397
421
  resolvedUrl = mergeRewriteQuery(resolvedUrl, afterFilesRewrite);
398
422
  cleanPathname = pathnameForResolvedUrl(resolvedUrl);
423
+ cleanPathnameIsRequestPathname = false;
399
424
  filesystemRouteEligible = true;
400
425
  const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
401
426
  if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
402
- match = options.matchRoute(cleanPathname);
427
+ match = matchCleanPathname();
403
428
  const rewrittenStaticPagesResponse = await renderPagesForMatchKind("static");
404
429
  if (rewrittenStaticPagesResponse) {
405
430
  options.clearRequestContext();
@@ -423,16 +448,18 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
423
448
  clearRequestContext: options.clearRequestContext,
424
449
  request: normalizedUserlandRequest,
425
450
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
451
+ paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
426
452
  rewrites: [rewrite]
427
453
  }, matchPathname(cleanPathname));
428
454
  if (fallbackRewrite instanceof Response) return fallbackRewrite;
429
455
  if (!fallbackRewrite) continue;
430
456
  resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
431
457
  cleanPathname = pathnameForResolvedUrl(resolvedUrl);
458
+ cleanPathnameIsRequestPathname = false;
432
459
  filesystemRouteEligible = true;
433
460
  const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
434
461
  if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
435
- match = options.matchRoute(cleanPathname);
462
+ match = matchCleanPathname();
436
463
  const rewrittenStaticPagesResponse = await renderPagesForMatchKind("static");
437
464
  if (rewrittenStaticPagesResponse) {
438
465
  options.clearRequestContext();
@@ -536,6 +563,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
536
563
  actionFailed,
537
564
  handlerStart,
538
565
  interceptionContext: interceptionContextHeader,
566
+ interceptionPathname: cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname,
539
567
  isProgressiveActionRender,
540
568
  isRscRequest,
541
569
  middlewareContext,
@@ -1,12 +1,13 @@
1
1
  import { ClientReuseManifestParseResult } from "./client-reuse-manifest.js";
2
- import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
3
2
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
3
+ import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
4
4
 
5
5
  //#region src/server/app-rsc-request-normalization.d.ts
6
6
  type NormalizedRscRequest = {
7
7
  /** Parsed URL. Callers may mutate `url.search` after middleware runs. */url: URL; /** Normalized pathname with basePath stripped. Used for all internal routing. */
8
8
  pathname: string; /** Pathname with `.rsc` suffix removed. Used for route matching and navigation context. */
9
- cleanPathname: string; /** True when the request targets a canonical `.rsc` payload URL. */
9
+ cleanPathname: string; /** Original encoded request pathname with basePath and `.rsc` removed. */
10
+ requestCleanPathname: string; /** True when the request targets a canonical `.rsc` payload URL. */
10
11
  isRscRequest: boolean; /** Sanitized X-Vinext-Interception-Context header (null bytes stripped). null when absent. */
11
12
  interceptionContextHeader: string | null; /** Normalized x-vinext-mounted-slots header (deduplicated, sorted). null when absent or blank. */
12
13
  mountedSlotsHeader: string | null; /** Semantic RSC payload mode. HTML requests always normalize to "navigation". */
@@ -50,14 +50,19 @@ function normalizeRscRequest(request, basePath, allowOutsideBasePath = false) {
50
50
  return badRequestResponse();
51
51
  }
52
52
  let pathname = normalizePath(decoded);
53
+ let requestPathname = url.pathname;
53
54
  let hadBasePath = true;
54
55
  if (basePath) {
55
- hadBasePath = hasBasePath(pathname, basePath);
56
+ hadBasePath = hasBasePath(requestPathname, basePath);
56
57
  if (!hadBasePath && !pathname.startsWith("/__vinext/") && !allowOutsideBasePath) return notFoundResponse();
57
- if (hadBasePath) pathname = stripBasePath(pathname, basePath);
58
+ if (hadBasePath) {
59
+ pathname = stripBasePath(pathname, basePath);
60
+ requestPathname = stripBasePath(requestPathname, basePath);
61
+ }
58
62
  }
59
63
  const isRscRequest = pathname.endsWith(".rsc") || request.headers.get("RSC") === "1";
60
64
  const cleanPathname = stripRscSuffix(pathname);
65
+ const requestCleanPathname = stripRscSuffix(requestPathname);
61
66
  const interceptionContextHeader = normalizeInterceptionContextHeader(request.headers.get(VINEXT_INTERCEPTION_CONTEXT_HEADER));
62
67
  const mountedSlotsHeader = normalizeMountedSlotsHeader(request.headers.get(VINEXT_MOUNTED_SLOTS_HEADER));
63
68
  const renderMode = isRscRequest ? parseAppRscRenderMode(request.headers.get(VINEXT_RSC_RENDER_MODE_HEADER)) : APP_RSC_RENDER_MODE_NAVIGATION;
@@ -67,6 +72,7 @@ function normalizeRscRequest(request, basePath, allowOutsideBasePath = false) {
67
72
  url,
68
73
  pathname,
69
74
  cleanPathname,
75
+ requestCleanPathname,
70
76
  isRscRequest,
71
77
  interceptionContextHeader,
72
78
  mountedSlotsHeader,
@@ -1,5 +1,5 @@
1
1
  import { NextHeader, NextI18nConfig } from "../config/next-config.js";
2
- import { RequestContext } from "../config/config-matchers.js";
2
+ import { RequestContext } from "../config/request-context.js";
3
3
 
4
4
  //#region src/server/app-rsc-response-finalizer.d.ts
5
5
  type FinalizeAppRscResponseOptions = {
@@ -32,6 +32,6 @@ type FinalizeAppRscResponseOptions = {
32
32
  * headers that throw on mutation, and Next.js does not apply config headers
33
33
  * to redirects regardless.
34
34
  */
35
- declare function finalizeAppRscResponse(response: Response, request: Request, options: FinalizeAppRscResponseOptions): Response;
35
+ declare function finalizeAppRscResponse(response: Response, request: Request, options: FinalizeAppRscResponseOptions): Promise<Response>;
36
36
  //#endregion
37
37
  export { finalizeAppRscResponse };