vinext 1.1.0 → 1.2.0

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 (234) hide show
  1. package/README.md +21 -9
  2. package/dist/build/client-build-config.d.ts +10 -0
  3. package/dist/build/client-build-config.js +18 -2
  4. package/dist/build/pages-client-assets-module.d.ts +8 -0
  5. package/dist/build/pages-client-assets-module.js +21 -1
  6. package/dist/build/prerender-paths.js +5 -3
  7. package/dist/build/run-prerender.js +1 -1
  8. package/dist/build/ssr-manifest.d.ts +2 -0
  9. package/dist/build/ssr-manifest.js +6 -2
  10. package/dist/check.js +7 -6
  11. package/dist/cli.js +2 -1
  12. package/dist/client/client-redirect-matcher.d.ts +14 -0
  13. package/dist/client/client-redirect-matcher.js +37 -0
  14. package/dist/client/client-redirects.d.ts +27 -0
  15. package/dist/client/client-redirects.js +28 -0
  16. package/dist/client/client-rewrites.d.ts +2 -1
  17. package/dist/client/client-rewrites.js +1 -1
  18. package/dist/config/config-matchers.d.ts +26 -11
  19. package/dist/config/config-matchers.js +78 -81
  20. package/dist/config/destination-params.d.ts +47 -0
  21. package/dist/config/destination-params.js +116 -0
  22. package/dist/config/next-config.d.ts +7 -0
  23. package/dist/config/next-config.js +3 -0
  24. package/dist/entries/app-rsc-entry.d.ts +4 -0
  25. package/dist/entries/app-rsc-entry.js +20 -6
  26. package/dist/entries/pages-client-entry.js +3 -1
  27. package/dist/entries/pages-server-entry.js +13 -37
  28. package/dist/index.d.ts +3 -1
  29. package/dist/index.js +134 -43
  30. package/dist/init-cloudflare.d.ts +9 -0
  31. package/dist/init-cloudflare.js +107 -31
  32. package/dist/init-platform.d.ts +4 -0
  33. package/dist/init-platform.js +27 -2
  34. package/dist/init.d.ts +1 -0
  35. package/dist/init.js +67 -3
  36. package/dist/plugins/ast-scope.d.ts +7 -0
  37. package/dist/plugins/ast-scope.js +59 -3
  38. package/dist/plugins/cache-flight-codec.d.ts +1 -1
  39. package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
  40. package/dist/plugins/dynamic-preload-metadata.js +9 -8
  41. package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
  42. package/dist/plugins/ignore-dynamic-requests.js +3 -4
  43. package/dist/plugins/middleware-server-only.d.ts +5 -4
  44. package/dist/plugins/middleware-server-only.js +8 -5
  45. package/dist/plugins/pages-node-externals.js +1 -1
  46. package/dist/plugins/rsc-scan-glob-imports.d.ts +19 -0
  47. package/dist/plugins/rsc-scan-glob-imports.js +50 -0
  48. package/dist/plugins/strip-server-exports.js +262 -98
  49. package/dist/plugins/transform-result.d.ts +9 -5
  50. package/dist/plugins/transitive-externals.js +1 -1
  51. package/dist/plugins/typeof-window.d.ts +2 -2
  52. package/dist/plugins/use-cache-callable.js +8 -2
  53. package/dist/plugins/worker-server-only-imports.d.ts +20 -0
  54. package/dist/plugins/worker-server-only-imports.js +31 -0
  55. package/dist/plugins/worker-use-server.d.ts +25 -0
  56. package/dist/plugins/worker-use-server.js +129 -0
  57. package/dist/server/api-handler.d.ts +1 -0
  58. package/dist/server/api-handler.js +2 -1
  59. package/dist/server/app-browser-action-result.d.ts +1 -1
  60. package/dist/server/app-browser-action-result.js +9 -2
  61. package/dist/server/app-browser-navigation-controller.js +1 -1
  62. package/dist/server/app-browser-server-action-client.js +1 -1
  63. package/dist/server/app-middleware.d.ts +11 -0
  64. package/dist/server/app-middleware.js +17 -2
  65. package/dist/server/app-page-cache.d.ts +1 -1
  66. package/dist/server/app-page-cache.js +1 -1
  67. package/dist/server/app-page-dispatch.d.ts +3 -1
  68. package/dist/server/app-page-dispatch.js +4 -3
  69. package/dist/server/app-page-ppr-runtime.js +1 -1
  70. package/dist/server/app-page-render-observation.js +1 -1
  71. package/dist/server/app-page-request.js +53 -15
  72. package/dist/server/app-page-route-wiring.js +2 -2
  73. package/dist/server/app-pages-bridge.d.ts +1 -1
  74. package/dist/server/app-pages-bridge.js +2 -3
  75. package/dist/server/app-prerender-endpoints.js +9 -6
  76. package/dist/server/app-request-stage-dispatch.js +6 -2
  77. package/dist/server/app-request-stage-independent-entry.js +25 -5
  78. package/dist/server/app-response-stage-entry.js +10 -2
  79. package/dist/server/app-route-handler-cache.d.ts +1 -0
  80. package/dist/server/app-route-handler-cache.js +1 -0
  81. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  82. package/dist/server/app-route-handler-dispatch.js +5 -2
  83. package/dist/server/app-route-handler-execution.d.ts +1 -0
  84. package/dist/server/app-route-handler-execution.js +1 -0
  85. package/dist/server/app-route-handler-runtime.d.ts +4 -1
  86. package/dist/server/app-route-handler-runtime.js +45 -24
  87. package/dist/server/app-router-entry.js +24 -5
  88. package/dist/server/app-rsc-cache-busting.js +1 -1
  89. package/dist/server/app-rsc-errors.js +20 -16
  90. package/dist/server/app-rsc-handler.d.ts +7 -0
  91. package/dist/server/app-rsc-handler.js +85 -35
  92. package/dist/server/app-rsc-response-stage.js +4 -2
  93. package/dist/server/app-segment-config.d.ts +2 -1
  94. package/dist/server/app-server-action-execution.d.ts +2 -1
  95. package/dist/server/app-server-action-execution.js +61 -22
  96. package/dist/server/app-ssr-entry.js +2 -1
  97. package/dist/server/app-worker-stages.d.ts +5 -0
  98. package/dist/server/app-worker-stages.js +1 -1
  99. package/dist/server/cacheability-request.js +2 -2
  100. package/dist/server/client-build-files.d.ts +16 -0
  101. package/dist/server/client-build-files.js +36 -0
  102. package/dist/server/client-reuse-manifest.js +1 -1
  103. package/dist/server/dev-server.js +38 -27
  104. package/dist/server/dev-stack-sourcemap.js +18 -23
  105. package/dist/server/document-initial-head.d.ts +0 -11
  106. package/dist/server/document-initial-head.js +1 -1
  107. package/dist/server/forwarded-middleware-context.d.ts +5 -0
  108. package/dist/server/forwarded-middleware-context.js +22 -0
  109. package/dist/server/headers.d.ts +4 -1
  110. package/dist/server/headers.js +4 -1
  111. package/dist/server/http-conditional.d.ts +11 -0
  112. package/dist/server/http-conditional.js +10 -1
  113. package/dist/server/http-error-responses.d.ts +1 -1
  114. package/dist/server/image-optimization.d.ts +38 -0
  115. package/dist/server/image-optimization.js +93 -4
  116. package/dist/server/isr-cache.d.ts +10 -0
  117. package/dist/server/isr-cache.js +41 -6
  118. package/dist/server/metadata-route-response.js +9 -8
  119. package/dist/server/middleware-matcher.d.ts +2 -0
  120. package/dist/server/middleware-matcher.js +23 -2
  121. package/dist/server/middleware-runtime.d.ts +13 -0
  122. package/dist/server/middleware-runtime.js +33 -20
  123. package/dist/server/middleware.d.ts +1 -1
  124. package/dist/server/middleware.js +3 -1
  125. package/dist/server/multi-stage.d.ts +11 -0
  126. package/dist/server/normalize-path.d.ts +0 -13
  127. package/dist/server/normalize-path.js +1 -34
  128. package/dist/server/pages-api-route.d.ts +3 -2
  129. package/dist/server/pages-api-route.js +4 -3
  130. package/dist/server/pages-cache-tag.d.ts +12 -0
  131. package/dist/server/pages-cache-tag.js +19 -0
  132. package/dist/server/pages-client-assets.d.ts +2 -0
  133. package/dist/server/pages-data-route.d.ts +10 -0
  134. package/dist/server/pages-data-route.js +19 -2
  135. package/dist/server/pages-document-asset-props.d.ts +5 -1
  136. package/dist/server/pages-document-asset-props.js +13 -5
  137. package/dist/server/pages-document-splice.d.ts +19 -0
  138. package/dist/server/pages-document-splice.js +55 -0
  139. package/dist/server/pages-i18n.d.ts +12 -1
  140. package/dist/server/pages-i18n.js +18 -4
  141. package/dist/server/pages-node-compat.d.ts +16 -5
  142. package/dist/server/pages-node-compat.js +20 -12
  143. package/dist/server/pages-page-data.d.ts +32 -24
  144. package/dist/server/pages-page-data.js +50 -120
  145. package/dist/server/pages-page-handler.d.ts +0 -6
  146. package/dist/server/pages-page-handler.js +188 -126
  147. package/dist/server/pages-page-response.d.ts +12 -6
  148. package/dist/server/pages-page-response.js +41 -34
  149. package/dist/server/pages-request-pipeline.d.ts +10 -2
  150. package/dist/server/pages-request-pipeline.js +37 -18
  151. package/dist/server/pages-request-stage-entry.d.ts +6 -0
  152. package/dist/server/pages-request-stage-entry.js +71 -12
  153. package/dist/server/pages-response-stage-entry.js +4 -0
  154. package/dist/server/pages-revalidate.js +1 -1
  155. package/dist/server/pages-router-entry.js +4 -3
  156. package/dist/server/prerender-manifest.d.ts +3 -3
  157. package/dist/server/prerender-manifest.js +4 -3
  158. package/dist/server/prerender-work-unit-setup.js +4 -0
  159. package/dist/server/prod-server.d.ts +12 -0
  160. package/dist/server/prod-server.js +199 -69
  161. package/dist/server/proper-error.d.ts +4 -0
  162. package/dist/server/proper-error.js +31 -0
  163. package/dist/server/request-pipeline.d.ts +4 -1
  164. package/dist/server/request-pipeline.js +3 -2
  165. package/dist/server/revalidation-request.d.ts +1 -0
  166. package/dist/server/revalidation-request.js +1 -1
  167. package/dist/server/rsc-stream-hints.js +31 -2
  168. package/dist/server/seed-cache.d.ts +1 -0
  169. package/dist/server/seed-cache.js +5 -4
  170. package/dist/server/server-reference-loader.d.ts +4 -0
  171. package/dist/server/server-reference-loader.js +29 -0
  172. package/dist/server/socket-error-backstop.d.ts +9 -1
  173. package/dist/server/socket-error-backstop.js +46 -17
  174. package/dist/server/static-file-signal.d.ts +15 -4
  175. package/dist/server/static-file-signal.js +46 -12
  176. package/dist/server/worker-image-optimization.d.ts +34 -0
  177. package/dist/server/worker-image-optimization.js +86 -0
  178. package/dist/server/worker-stages.d.ts +1 -1
  179. package/dist/server/worker-stages.js +2 -2
  180. package/dist/server/worker-utils.d.ts +8 -3
  181. package/dist/server/worker-utils.js +12 -7
  182. package/dist/shims/app-router-scroll.js +4 -1
  183. package/dist/shims/app-router-tree-context.d.ts +5 -0
  184. package/dist/shims/app-router-tree-context.js +27 -0
  185. package/dist/shims/cache-callable-runtime.d.ts +4 -2
  186. package/dist/shims/cache-callable-runtime.js +21 -12
  187. package/dist/shims/cache-handler.js +1 -9
  188. package/dist/shims/cache-runtime.d.ts +6 -1
  189. package/dist/shims/cache-runtime.js +2 -1
  190. package/dist/shims/cache.d.ts +2 -2
  191. package/dist/shims/cache.js +40 -13
  192. package/dist/shims/cdn-cache.d.ts +8 -0
  193. package/dist/shims/cdn-cache.js +17 -1
  194. package/dist/shims/disable-smooth-scroll.d.ts +3 -0
  195. package/dist/shims/disable-smooth-scroll.js +36 -0
  196. package/dist/shims/document-placeholders.d.ts +19 -0
  197. package/dist/shims/document-placeholders.js +45 -0
  198. package/dist/shims/document.js +21 -5
  199. package/dist/shims/dynamic-preload-chunks.d.ts +1 -0
  200. package/dist/shims/dynamic-preload-chunks.js +13 -9
  201. package/dist/shims/dynamic.d.ts +1 -1
  202. package/dist/shims/dynamic.js +60 -8
  203. package/dist/shims/fetch-cache-state.d.ts +66 -0
  204. package/dist/shims/fetch-cache-state.js +92 -0
  205. package/dist/shims/fetch-cache.d.ts +3 -67
  206. package/dist/shims/fetch-cache.js +160 -125
  207. package/dist/shims/head.d.ts +10 -6
  208. package/dist/shims/head.js +15 -13
  209. package/dist/shims/image.js +2 -1
  210. package/dist/shims/internal/work-store-scope.d.ts +5 -0
  211. package/dist/shims/internal/work-store-scope.js +24 -0
  212. package/dist/shims/navigation.js +31 -5
  213. package/dist/shims/request-context.d.ts +2 -0
  214. package/dist/shims/request-state-types.d.ts +2 -1
  215. package/dist/shims/router.js +12 -20
  216. package/dist/shims/server.d.ts +16 -0
  217. package/dist/shims/server.js +24 -4
  218. package/dist/shims/unified-request-context.d.ts +1 -1
  219. package/dist/shims/url-utils.d.ts +2 -0
  220. package/dist/shims/url-utils.js +3 -1
  221. package/dist/utils/client-runtime-metadata.js +1 -1
  222. package/dist/utils/hash.d.ts +7 -0
  223. package/dist/utils/hash.js +11 -1
  224. package/dist/utils/package-name.d.ts +6 -0
  225. package/dist/utils/package-name.js +12 -1
  226. package/dist/utils/plugin-rsc-version.d.ts +4 -0
  227. package/dist/utils/plugin-rsc-version.js +15 -0
  228. package/dist/utils/prerender-output-paths.js +15 -4
  229. package/dist/utils/public-file-path.d.ts +10 -2
  230. package/dist/utils/public-file-path.js +13 -9
  231. package/dist/utils/public-routes.js +2 -2
  232. package/dist/utils/react-version.d.ts +3 -0
  233. package/dist/utils/react-version.js +1 -1
  234. package/package.json +7 -3
@@ -1,20 +1,22 @@
1
1
  import { preserveFullyBufferedBodyMetadata } from "./fully-buffered-response.js";
2
2
  import { closeAfterResponse, closeAfterResponseWithBody, createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
3
3
  import { PRERENDER_REVALIDATE_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER, VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
4
- import { hasMiddlewareRequestHeaderOverrides } from "../utils/middleware-request-headers.js";
4
+ import { buildRequestHeadersFromMiddlewareResponse, hasMiddlewareRequestHeaderOverrides } from "../utils/middleware-request-headers.js";
5
5
  import { requestContextFromRequest } from "../config/request-context.js";
6
6
  import { isExternalUrl } from "../utils/external-url.js";
7
7
  import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
8
- import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
8
+ import { normalizePathnameForRouteMatch, normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
9
9
  import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base-path.js";
10
10
  import { patternToNextFormat } from "../routing/route-validation.js";
11
11
  import { getRequestExecutionContext } from "../shims/request-context.js";
12
12
  import "./app-rsc-vary.js";
13
13
  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";
14
+ import { runOutsideWorkStoreScope } from "../shims/internal/work-store-scope.js";
14
15
  import { isInterceptionMatchedUrlPath, normalizePath } from "./normalize-path.js";
15
16
  import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } from "./http-error-responses.js";
16
17
  import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, normalizeTrailingSlashPathname, resolvePublicFileRoute } from "./request-pipeline.js";
17
18
  import { normalizeDefaultLocalePathname } from "./pages-i18n.js";
19
+ import { buildNextDataNotFoundResponse, normalizePagesDataRequest } from "./pages-data-route.js";
18
20
  import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
19
21
  import { markRouteCacheabilityDynamic, preserveRouteCacheabilityResponsePolicy } from "../shims/cacheability-classification.js";
20
22
  import { NEVER_CACHE_CONTROL, applyCdnResponseHeaders, captureCdnResponsePolicyOverrides, isCdnResponsePolicyHeader, reconcileCdnResponseHeadersAfterOuterPolicy } from "./cache-control.js";
@@ -22,9 +24,8 @@ import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
22
24
  import { getDraftModeCookieHeader, getEffectiveRequestCookieHeader, getHeadersContext, hasEffectiveRequestCookieChanges, headersContextFromRequest, isDraftModeEnabled, isDraftModeRequest, runWithHeadersContext } from "../shims/headers.js";
23
25
  import { mergeRewriteQuery } from "../utils/query.js";
24
26
  import { getScriptNonceFromHeaderSources } from "./csp.js";
25
- import { buildNextDataNotFoundResponse, normalizePagesDataRequest } from "./pages-data-route.js";
26
27
  import { traceFindPageComponents } from "./pages-execution-tracing.js";
27
- import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isImageOptimizationPath, resolveDevImageRedirect } from "./image-optimization.js";
28
+ import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isImageOptimizationPath, markImageOptimizationSignal, resolveDevImageRedirect } from "./image-optimization.js";
28
29
  import { parseCacheabilityManifest } from "./cacheability-manifest.js";
29
30
  import { getRenderedConcreteUrlPathsForRoute } from "./pregenerated-concrete-paths.js";
30
31
  import { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, canonicalizeLoadingShellRscRequestHeaders, canonicalizePrewarmableRscRequestHeaders, createCanonicalRscRequestUrl, createRscRedirectLocation, createRscRequestUrl, hasRscCacheBustingSearchParam, resolveInvalidRscCacheBustingRequest, stripRscCacheBustingSearchParam, stripRscSuffix } from "./app-rsc-cache-busting.js";
@@ -33,6 +34,7 @@ import { consumeResponseStageLinkProvenance, copyLinkHeaderProvenance } from "./
33
34
  import "./app-page-response.js";
34
35
  import { parseNextHttpErrorDigest } from "./next-error-digest.js";
35
36
  import { traceAppPageRender } from "./app-page-tracing.js";
37
+ import { openForwardedMiddlewareContext } from "./forwarded-middleware-context.js";
36
38
  import { setFrameworkRequestRoute, traceFrameworkRequest } from "./request-tracing.js";
37
39
  import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
38
40
  import { buildPageCacheTags } from "./implicit-tags.js";
@@ -147,7 +149,7 @@ function applyMiddlewareContextToResponse(response, middlewareContext, appendToP
147
149
  const middlewareLink = middlewareContext.headers?.get("link");
148
150
  if (responseLink && middlewareLink) headers.set("link", `${middlewareLink}, ${responseLink}`);
149
151
  return preserveFullyBufferedBodyMetadata(response, new Response(response.body, {
150
- status: middlewareContext.status ?? response.status,
152
+ status: response.status === 304 ? 304 : middlewareContext.status ?? response.status,
151
153
  statusText: response.statusText,
152
154
  headers
153
155
  }));
@@ -165,7 +167,8 @@ function withStoredSpecialErrorStatus(response, isSegmentPrefetch) {
165
167
  const headers = new Headers(response.headers);
166
168
  headers.delete(VINEXT_SPECIAL_ERROR_STATUS_HEADER);
167
169
  const storedStatus = Number(marker);
168
- const status = !(storedStatus === 401 || storedStatus === 403 || storedStatus === 404) ? response.status : isSegmentPrefetch ? 200 : storedStatus;
170
+ const isStoredSpecialError = storedStatus === 401 || storedStatus === 403 || storedStatus === 404;
171
+ const status = response.status === 304 || !isStoredSpecialError ? response.status : isSegmentPrefetch ? 200 : storedStatus;
169
172
  return preserveFullyBufferedBodyMetadata(response, new Response(response.body, {
170
173
  headers,
171
174
  status,
@@ -204,8 +207,10 @@ async function applyRewrite(options, cleanPathname, recordCacheability = true) {
204
207
  if (isExternalUrl(rewritten)) {
205
208
  const validationResponse = await options.validateExternalRewriteRequest();
206
209
  if (validationResponse) return validationResponse;
210
+ const { requestWithMiddlewareContextHeaders } = await import("./app-middleware.js");
211
+ const proxyRequest = requestWithMiddlewareContextHeaders(options.request, options.middlewareContext);
207
212
  options.clearRequestContext();
208
- return configMatchers.proxyExternalRequest(options.request, rewritten);
213
+ return configMatchers.proxyExternalRequest(proxyRequest, rewritten);
209
214
  }
210
215
  return rewritten;
211
216
  }
@@ -220,6 +225,16 @@ function requestContextForResolvedUrl(requestContext, resolvedUrl, baseUrl) {
220
225
  function pathnameForResolvedUrl(resolvedUrl) {
221
226
  return resolvedUrl.split("#", 1)[0].split("?", 1)[0];
222
227
  }
228
+ /**
229
+ * Percent-encode the code points the URL parser encodes in a path (so `é`
230
+ * becomes `%C3%A9`) without resolving dot segments or `\`: Next.js only parses
231
+ * a rewrite destination's template, so a captured `../admin` stays verbatim.
232
+ */
233
+ function serializeResolvedUrl(resolvedUrl, base) {
234
+ const resolved = new URL(resolvedUrl, base);
235
+ stripRscCacheBustingSearchParam(resolved);
236
+ return pathnameForResolvedUrl(resolvedUrl).replace(/[\0-\x20"<>`{}^\x7F]|[^\0-\x7F]/gu, (char) => char.length === 1 && char >= "\ud800" && char <= "\udfff" ? "%EF%BF%BD" : encodeURIComponent(char)) + resolved.search + resolved.hash;
237
+ }
223
238
  async function applyConfigHeadersToMiddlewareRedirect(response, options) {
224
239
  if (response.status < 300 || response.status >= 400) return response;
225
240
  if (!HAS_CONFIG_HEADERS || !options.configHeaders.length) return response;
@@ -314,7 +329,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
314
329
  const { requestCleanPathname } = normalized;
315
330
  let { pathname, cleanPathname } = normalized;
316
331
  let resolvedUrl = cleanPathname + url.search;
317
- const originalResolvedUrl = resolvedUrl;
332
+ const originalResolvedUrl = serializeResolvedUrl(resolvedUrl, url);
318
333
  const getResolvedSearchParams = () => new URL(resolvedUrl, url).searchParams;
319
334
  const canonicalPathname = cleanPathname;
320
335
  const basePathState = {
@@ -354,15 +369,17 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
354
369
  });
355
370
  if (prerenderEndpointResponse) return prerenderEndpointResponse;
356
371
  }
357
- const trailingSlashRedirect = options.trailingSlash && options.isMetadataRoutePath && await options.isMetadataRoutePath(cleanPathname) ? null : normalizeTrailingSlash(requestCleanPathname, hadBasePath ? options.basePath : "", options.trailingSlash, url.search);
358
- if (trailingSlashRedirect) return trailingSlashRedirect;
372
+ if (!options.skipTrailingSlashRedirect) {
373
+ const trailingSlashRedirect = options.trailingSlash && options.isMetadataRoutePath && await options.isMetadataRoutePath(cleanPathname) ? null : normalizeTrailingSlash(requestCleanPathname, hadBasePath ? options.basePath : "", options.trailingSlash, url.search);
374
+ if (trailingSlashRedirect) return trailingSlashRedirect;
375
+ }
359
376
  const matchPathname = (p) => normalizeDefaultLocalePathname(p, options.i18nConfig, { hostname: url.hostname });
360
377
  const redirectPathname = matchPathname(requestCleanPathname);
361
378
  const configMatchers = HAS_CONFIG_REDIRECTS && options.configRedirects.length ? await import("../config/config-matchers.js") : null;
362
379
  const redirect = configMatchers ? configMatchers.matchRedirect(redirectPathname, options.configRedirects, preMiddlewareRequestContext, basePathState, dispatchResponseStage ? void 0 : markConditionalRedirectCacheability) : null;
363
380
  if (configMatchers && redirect) {
364
381
  const destination = configMatchers.sanitizeDestination(redirectDestinationWithBasePath(redirect.destination, options.basePath, hadBasePath));
365
- const location = isRscRequest && request.headers.get("RSC") === "1" ? await createRscRedirectLocation(destination, request) : configMatchers.preserveRedirectDestinationQuery(destination, url.search);
382
+ const location = isRscRequest && request.headers.get("RSC") === "1" ? await createRscRedirectLocation(destination, request) : configMatchers.preserveRedirectDestinationQuery(destination, url.search, redirect.destinationQuery);
366
383
  return new Response(null, {
367
384
  status: redirect.permanent ? 308 : 307,
368
385
  headers: { Location: location }
@@ -388,6 +405,11 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
388
405
  const isolatedMiddlewareRequest = isolatedMiddlewareSource ? requestWithoutRscCacheBustingSearchParam(requestWithoutRscSuffix(isolatedMiddlewareSource)) : void 0;
389
406
  let didMiddlewareRewrite = false;
390
407
  let didMiddlewareRewritePathname = false;
408
+ let resolvedPathnameHasBasePath = hadBasePath;
409
+ const currentBasePathState = () => ({
410
+ basePath: options.basePath,
411
+ hadBasePath: resolvedPathnameHasBasePath
412
+ });
391
413
  if (runMiddleware) {
392
414
  const middlewareResult = await runMiddleware({
393
415
  cleanPathname,
@@ -412,6 +434,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
412
434
  }
413
435
  cleanPathname = middlewareResult.cleanPathname;
414
436
  didMiddlewareRewrite = middlewareResult.rewritten;
437
+ if (didMiddlewareRewrite) resolvedPathnameHasBasePath = middlewareResult.rewriteHadBasePath ?? true;
415
438
  if (didMiddlewareRewrite || cleanPathname !== normalized.cleanPathname) cleanPathnameIsRequestPathname = false;
416
439
  didMiddlewareRewritePathname = cleanPathname !== normalized.cleanPathname;
417
440
  if (middlewareResult.search !== null) url.search = middlewareResult.search;
@@ -574,8 +597,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
574
597
  filesystemRouteEligible ||= didMiddlewareRewrite;
575
598
  for (const rewrite of options.configRewrites.beforeFiles) {
576
599
  const beforeFilesRewrite = await applyRewrite({
577
- basePathState,
600
+ basePathState: currentBasePathState(),
578
601
  clearRequestContext: options.clearRequestContext,
602
+ middlewareContext,
579
603
  request: normalizedUserlandRequest,
580
604
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
581
605
  paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
@@ -588,6 +612,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
588
612
  cleanPathname = pathnameForResolvedUrl(resolvedUrl);
589
613
  cleanPathnameIsRequestPathname = false;
590
614
  filesystemRouteEligible = true;
615
+ resolvedPathnameHasBasePath = !options.basePath || rewrite.basePath !== false;
591
616
  }
592
617
  }
593
618
  const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
@@ -601,8 +626,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
601
626
  let actionMatch = null;
602
627
  for (const rewrite of options.configRewrites.afterFiles) {
603
628
  const rewritten = await applyRewrite({
604
- basePathState,
629
+ basePathState: currentBasePathState(),
605
630
  clearRequestContext: options.clearRequestContext,
631
+ middlewareContext,
606
632
  request: normalizedUserlandRequest,
607
633
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
608
634
  paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
@@ -615,13 +641,15 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
615
641
  cleanPathname = pathnameForResolvedUrl(resolvedUrl);
616
642
  cleanPathnameIsRequestPathname = false;
617
643
  filesystemRouteEligible = true;
644
+ resolvedPathnameHasBasePath = !options.basePath || rewrite.basePath !== false;
618
645
  actionMatch = matchCleanPathname();
619
646
  if (actionMatch) break;
620
647
  }
621
648
  if (!actionMatch) for (const rewrite of options.configRewrites.fallback) {
622
649
  const rewritten = await applyRewrite({
623
- basePathState,
650
+ basePathState: currentBasePathState(),
624
651
  clearRequestContext: options.clearRequestContext,
652
+ middlewareContext,
625
653
  request: normalizedUserlandRequest,
626
654
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
627
655
  paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
@@ -634,6 +662,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
634
662
  cleanPathname = pathnameForResolvedUrl(resolvedUrl);
635
663
  cleanPathnameIsRequestPathname = false;
636
664
  filesystemRouteEligible = true;
665
+ resolvedPathnameHasBasePath = !options.basePath || rewrite.basePath !== false;
637
666
  actionMatch = matchCleanPathname();
638
667
  if (actionMatch) break;
639
668
  }
@@ -641,15 +670,29 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
641
670
  }
642
671
  const lateActionRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
643
672
  if (lateActionRscCacheBustingRedirect) return lateActionRscCacheBustingRedirect;
644
- if (filesystemRouteEligible && isImageOptimizationPath(cleanPathname)) {
645
- const imageRedirect = resolveDevImageRedirect(url, [...options.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...options.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES], options.imageConfig?.qualities, { isDev: options.isDev });
646
- if (!imageRedirect) return new Response("Invalid image optimization parameters", { status: 400 });
647
- return Response.redirect(new URL(imageRedirect, url.origin).href, 302);
648
- }
673
+ const serveImageEndpointIfMatched = () => {
674
+ if (!filesystemRouteEligible || !resolvedPathnameHasBasePath || !isImageOptimizationPath(cleanPathname)) return null;
675
+ const imageUrl = new URL(resolvedUrl, url);
676
+ const imageRedirect = resolveDevImageRedirect(imageUrl, [...options.imageConfig?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...options.imageConfig?.imageSizes ?? DEFAULT_IMAGE_SIZES], options.imageConfig?.qualities, { isDev: options.isDev });
677
+ const middlewareHeaders = new Headers();
678
+ mergeMiddlewareResponseHeaders(middlewareHeaders, middlewareContext.headers);
679
+ if (!imageRedirect) return new Response("Invalid image optimization parameters", {
680
+ status: 400,
681
+ headers: middlewareHeaders
682
+ });
683
+ const overrideHeaders = middlewareContext.requestHeaders ?? middlewareContext.headers;
684
+ return markImageOptimizationSignal(Response.redirect(new URL(imageRedirect, url.origin).href, 302), {
685
+ middlewareHeaders,
686
+ requestHeaders: overrideHeaders ? buildRequestHeadersFromMiddlewareResponse(request.headers, overrideHeaders) : null,
687
+ search: imageUrl.search
688
+ });
689
+ };
690
+ const imageEndpointResponse = serveImageEndpointIfMatched();
691
+ if (imageEndpointResponse) return imageEndpointResponse;
649
692
  const metadataRouteResponse = await renderMetadataRouteIfMatched();
650
693
  if (metadataRouteResponse) return composeResponseStageResponse(metadataRouteResponse);
651
694
  const publicFileResponse = filesystemRouteEligible ? resolvePublicFileRoute({
652
- cleanPathname,
695
+ cleanPathname: cleanPathnameIsRequestPathname ? cleanPathname : normalizePathnameForRouteMatch(cleanPathname),
653
696
  middlewareContext,
654
697
  pathname,
655
698
  publicFiles: options.publicFiles,
@@ -660,9 +703,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
660
703
  return publicFileResponse;
661
704
  }
662
705
  stripRscCacheBustingSearchParam(url);
663
- const resolved = new URL(resolvedUrl, url);
664
- stripRscCacheBustingSearchParam(resolved);
665
- resolvedUrl = resolved.pathname + resolved.search + resolved.hash;
706
+ resolvedUrl = serializeResolvedUrl(resolvedUrl, url);
666
707
  options.setNavigationContext({
667
708
  pathname: canonicalPathname,
668
709
  searchParams: getResolvedSearchParams(),
@@ -670,7 +711,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
670
711
  });
671
712
  const directPreActionMatch = filesystemRouteEligible ? matchCleanPathname() : null;
672
713
  const preActionRoutePathname = cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname;
673
- let interceptionSourceContext = interceptionContextHeader;
714
+ let interceptionSourceContext = interceptionSourcePathname !== null ? interceptionContextHeader : null;
674
715
  let interceptionSourceMatch = filesystemRouteEligible && interceptionSourcePathname !== null && interceptionContextHeader !== null ? options.matchInterceptRoute?.(preActionRoutePathname, interceptionContextHeader, interceptionIdHeader) ?? null : null;
675
716
  let hasVerifiedInterceptionSource = provesConcreteInterceptionSource(interceptionSourceMatch);
676
717
  if (interceptionIdHeader !== null && !hasVerifiedInterceptionSource) {
@@ -688,8 +729,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
688
729
  setInterceptionResponseUncacheable(true);
689
730
  };
690
731
  if (interceptionSourceMatch !== null && interceptionContextHeader !== null && interceptionSourcePathname !== null && !(interceptionSourceMatch.route === directPreActionMatch?.route && haveSamePageParams(interceptionSourceMatch.params, directPreActionMatch.params))) {
691
- const sourceRequestPathname = normalizeTrailingSlashPathname(interceptionContextHeader, options.trailingSlash) ?? interceptionContextHeader;
692
- const decodedSourceRequestPathname = normalizeTrailingSlashPathname(interceptionSourcePathname, options.trailingSlash) ?? interceptionSourcePathname;
732
+ const sourceRequestPathname = options.skipTrailingSlashRedirect ? interceptionContextHeader : normalizeTrailingSlashPathname(interceptionContextHeader, options.trailingSlash) ?? interceptionContextHeader;
733
+ const decodedSourceRequestPathname = options.skipTrailingSlashRedirect ? interceptionSourcePathname : normalizeTrailingSlashPathname(interceptionSourcePathname, options.trailingSlash) ?? interceptionSourcePathname;
693
734
  const adoptRewrittenInterceptionSource = (rewrittenPathname) => {
694
735
  const rewrittenInterceptionSourceMatch = isValidInterceptionSourceContext(rewrittenPathname) ? options.matchInterceptRoute?.(preActionRoutePathname, rewrittenPathname, interceptionIdHeader) ?? null : null;
695
736
  if (rewrittenInterceptionSourceMatch !== null) {
@@ -892,6 +933,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
892
933
  let match = preActionMatch;
893
934
  const renderPagesForMatchKind = async (matchKind) => {
894
935
  if (!filesystemRouteEligible) return null;
936
+ const pagesRouteUrl = cleanPathnameIsRequestPathname ? requestCleanPathname + resolvedUrl.slice(pathnameForResolvedUrl(resolvedUrl).length) : resolvedUrl;
895
937
  let sharedOuterPolicyNeedsReconciliation = false;
896
938
  const dispatchPagesResponseStage = dispatchResponseStage ? async (stageRequest, resourceKind, dataKind, hasRequestAwareDocument) => {
897
939
  const pagesOnDemandRevalidate = resourceKind === "page" && isOnDemandRevalidateRequest(stageRequest.headers.get("x-prerender-revalidate"));
@@ -921,7 +963,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
921
963
  requestOrigin: url.origin,
922
964
  resourceKind,
923
965
  requestUrl: request.url,
924
- resolvedUrl,
966
+ resolvedUrl: pagesRouteUrl,
925
967
  scriptNonce: scriptNonce ?? null
926
968
  }, { cache });
927
969
  const policyOwner = resourceKind === "page" ? consumePagesResponseStagePolicyOwner(response) : {
@@ -936,7 +978,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
936
978
  if (!responseStageHasContentLength) response.headers.delete("Content-Length");
937
979
  return response;
938
980
  } : void 0;
939
- const response = !isInterceptionMatch && (match === null || match.route.isDynamic) ? await options.renderPagesFallback?.({
981
+ const response = !isInterceptionMatch && (match === null || match.route.isDynamic) ? await runOutsideWorkStoreScope(() => options.renderPagesFallback?.({
940
982
  appRouteMatch: match ?? null,
941
983
  allowRscDocumentFallback: didMiddlewareRewritePathname || allowInternalRscDocumentFallback,
942
984
  dispatchPagesResponseStage,
@@ -944,11 +986,11 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
944
986
  isRscRequest,
945
987
  matchKind,
946
988
  middlewareContext,
947
- pathname: resolvedUrl,
989
+ pathname: pagesRouteUrl,
948
990
  pagesDataRequest,
949
991
  request,
950
992
  url
951
- }) ?? null : null;
993
+ })) ?? null : null;
952
994
  if (response) preserveRouteCacheabilityResponsePolicy();
953
995
  if (!response) return null;
954
996
  if (sharedOuterPolicyNeedsReconciliation) reconcileCdnResponseHeadersAfterOuterPolicy(response.headers, await loadOuterResponsePolicy());
@@ -972,8 +1014,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
972
1014
  }
973
1015
  if (!isInterceptionMatch && !resolvedLateRewritesForAction && (!match || match.route.isDynamic)) for (const rewrite of options.configRewrites.afterFiles) {
974
1016
  const afterFilesRewrite = await applyRewrite({
975
- basePathState,
1017
+ basePathState: currentBasePathState(),
976
1018
  clearRequestContext: options.clearRequestContext,
1019
+ middlewareContext,
977
1020
  request: normalizedUserlandRequest,
978
1021
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
979
1022
  paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
@@ -990,8 +1033,11 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
990
1033
  cleanPathnameIsRequestPathname = false;
991
1034
  invalidateInterceptionCacheProof();
992
1035
  filesystemRouteEligible = true;
1036
+ resolvedPathnameHasBasePath = !options.basePath || rewrite.basePath !== false;
993
1037
  const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
994
1038
  if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
1039
+ const rewrittenImageEndpointResponse = serveImageEndpointIfMatched();
1040
+ if (rewrittenImageEndpointResponse) return rewrittenImageEndpointResponse;
995
1041
  const rewrittenMetadataResponse = await renderMetadataRouteIfMatched();
996
1042
  if (rewrittenMetadataResponse) return composeResponseStageResponse(rewrittenMetadataResponse);
997
1043
  match = matchCleanPathname();
@@ -1014,8 +1060,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1014
1060
  }
1015
1061
  if (!resolvedLateRewritesForAction && !match) for (const rewrite of options.configRewrites.fallback) {
1016
1062
  const fallbackRewrite = await applyRewrite({
1017
- basePathState,
1063
+ basePathState: currentBasePathState(),
1018
1064
  clearRequestContext: options.clearRequestContext,
1065
+ middlewareContext,
1019
1066
  request: normalizedUserlandRequest,
1020
1067
  requestContext: requestContextForResolvedUrl(postMiddlewareRequestContext, resolvedUrl, url),
1021
1068
  paramsPathname: matchPathname(cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname),
@@ -1032,8 +1079,11 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1032
1079
  cleanPathnameIsRequestPathname = false;
1033
1080
  invalidateInterceptionCacheProof();
1034
1081
  filesystemRouteEligible = true;
1082
+ resolvedPathnameHasBasePath = !options.basePath || rewrite.basePath !== false;
1035
1083
  const claimedRscCacheBustingRedirect = await validateClaimedOutsideBasePathRsc();
1036
1084
  if (claimedRscCacheBustingRedirect) return claimedRscCacheBustingRedirect;
1085
+ const rewrittenImageEndpointResponse = serveImageEndpointIfMatched();
1086
+ if (rewrittenImageEndpointResponse) return rewrittenImageEndpointResponse;
1037
1087
  const rewrittenMetadataResponse = await renderMetadataRouteIfMatched();
1038
1088
  if (rewrittenMetadataResponse) return composeResponseStageResponse(rewrittenMetadataResponse);
1039
1089
  match = matchCleanPathname();
@@ -1226,7 +1276,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1226
1276
  cleanPathname,
1227
1277
  draftModeCookie,
1228
1278
  forceDynamic: route.forceDynamic === true,
1229
- interceptionContext: isRscRequest ? interceptionSourceContext : null,
1279
+ interceptionContext: interceptionSourceContext,
1230
1280
  interceptionId: interceptionIdHeader,
1231
1281
  isRscRequest,
1232
1282
  matchKind: responseStageMatchKind,
@@ -1250,7 +1300,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1250
1300
  actionError: normalizedProgressiveActionError,
1251
1301
  actionFailed,
1252
1302
  handlerStart,
1253
- interceptionContext: isRscRequest ? interceptionSourceContext : null,
1303
+ interceptionContext: interceptionSourceContext,
1254
1304
  interceptionId: interceptionIdHeader,
1255
1305
  interceptionPathname: cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname,
1256
1306
  isProgressiveActionRender,
@@ -1312,7 +1362,7 @@ function applyProgressiveActionSideEffects(response, sideEffects) {
1312
1362
  /** Build the request-only handler without retaining the response renderer graph. */
1313
1363
  function createAppRscRequestHandler(options) {
1314
1364
  const handleAppRscRequestLifecycle = async (rawRequest, ctx, allowInternalRscDocumentFallback = false, dispatchResponseStage, responseStageProbeMode = null, transportedPrerenderState) => {
1315
- const mwCtx = rawRequest.headers.get(VINEXT_MW_CTX_HEADER);
1365
+ const mwCtx = openForwardedMiddlewareContext(rawRequest.headers.get(VINEXT_MW_CTX_HEADER), options.devForwardedMiddlewareContextKey);
1316
1366
  const pagesDataUrl = new URL(rawRequest.url);
1317
1367
  const pagesDataInScope = !options.basePath || hasBasePath(pagesDataUrl.pathname, options.basePath);
1318
1368
  if (pagesDataInScope) pagesDataUrl.pathname = stripBasePath(pagesDataUrl.pathname, options.basePath);
@@ -3,6 +3,7 @@ import { closeAfterResponse, closeAfterResponseWithBody, createRequestContext, r
3
3
  import { VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
4
4
  import { getRequestExecutionContext } from "../shims/request-context.js";
5
5
  import "./headers.js";
6
+ import { runOutsideWorkStoreScope } from "../shims/internal/work-store-scope.js";
6
7
  import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders } from "./request-pipeline.js";
7
8
  import { applyEffectiveRequestCookieHeader, getDraftModeCookieHeader, headersContextFromRequest, restoreDraftModeTransition } from "../shims/headers.js";
8
9
  import { ensureFetchPatch, setCurrentFetchSoftTags } from "../shims/fetch-cache.js";
@@ -153,7 +154,8 @@ async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, sta
153
154
  const pageRequest = props.isDataRequest ? cloneRequestWithUrl(request, new URL(props.resolvedUrl, request.url).toString()) : request;
154
155
  const preHandlerHeaders = props.preHandlerHeaders === null ? void 0 : new Headers(props.preHandlerHeaders);
155
156
  preHandlerHeaders?.delete("Content-Length");
156
- let pagesResponse = await options.renderPagesFallback({
157
+ const renderPagesFallback = options.renderPagesFallback;
158
+ let pagesResponse = await runOutsideWorkStoreScope(() => renderPagesFallback({
157
159
  allowRscDocumentFallback: props.allowRscDocumentFallback,
158
160
  appRouteMatch: props.appRouteMatch ? { route: {
159
161
  isDynamic: props.appRouteMatch.isDynamic,
@@ -168,7 +170,7 @@ async function renderAppWorkerResponseStage(options, rawRequest, ctx, props, sta
168
170
  pagesDataRequest: props.isDataRequest ? request : null,
169
171
  request: pageRequest,
170
172
  url: new URL(props.requestUrl)
171
- });
173
+ }));
172
174
  if (!pagesResponse) return new Response("Invalid vinext App response stage", { status: 404 });
173
175
  if (preHandlerHeaders) pagesResponse = stripInheritedResponseStageCookies(pagesResponse, preHandlerHeaders);
174
176
  return pagesResponse;
@@ -1,4 +1,5 @@
1
- import { FetchCacheMode } from "../shims/fetch-cache.js";
1
+ import { FetchCacheMode } from "../shims/fetch-cache-state.js";
2
+ import "../shims/fetch-cache.js";
2
3
  //#region src/server/app-segment-config.d.ts
3
4
  type AppRouteSegmentDynamic = "auto" | "error" | "force-dynamic" | "force-static";
4
5
  type AppRouteSegmentConfigModule = {
@@ -1,7 +1,8 @@
1
1
  import { AppRscRenderMode } from "./app-rsc-render-mode.js";
2
2
  import { ActionRevalidationKind } from "../shims/cache-request-state.js";
3
3
  import { AppRenderErrorContextOverrides } from "./app-rsc-error-handler.js";
4
- import { FetchCacheMode } from "../shims/fetch-cache.js";
4
+ import { FetchCacheMode } from "../shims/fetch-cache-state.js";
5
+ import "../shims/fetch-cache.js";
5
6
  import { HeadersAccessPhase } from "../shims/internal/headers-state.js";
6
7
  import "../shims/headers.js";
7
8
  import { ReactFormState } from "react-dom/client";
@@ -1,3 +1,4 @@
1
+ import { runOutsideRequestScopes } from "../shims/internal/als-registry.js";
1
2
  import { VINEXT_MW_CTX_HEADER } from "../utils/protocol-headers.js";
2
3
  import { buildRequestHeadersFromMiddlewareResponse } from "../utils/middleware-request-headers.js";
3
4
  import { parseEdgeRequestCookieHeader } from "../utils/parse-cookie.js";
@@ -18,6 +19,7 @@ import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, createRscReques
18
19
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
19
20
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
20
21
  import { getNextErrorDigest, parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
22
+ import { hasDigest } from "./app-rsc-errors.js";
21
23
  import { buildAppPageTags } from "./implicit-tags.js";
22
24
  import "./app-page-stream.js";
23
25
  import { getSetCookieName } from "./cookie-utils.js";
@@ -28,6 +30,23 @@ import { createRootParamsUsageController, runWithRootParamsUsage } from "../shim
28
30
  import { createStaticGenerationHeadersContext } from "./app-static-generation.js";
29
31
  import { markAppRscResponseConfigHeadersApplied } from "./app-rsc-response-finalizer.js";
30
32
  //#region src/server/app-server-action-execution.ts
33
+ /**
34
+ * Run a server-reference load or decode outside every request scope.
35
+ *
36
+ * Server reference modules are imported on the first request that names them
37
+ * — `loadServerAction()` imports the action's module, and the decoders import
38
+ * any reference the body carries — and a dynamic `import()` carries
39
+ * AsyncLocalStorage into the module's top-level evaluation. Module-scope
40
+ * `cookies()`/`headers()` would then capture that first caller's request for
41
+ * every later caller in the isolate. Next.js evaluates action modules outside
42
+ * the request store, where those calls throw.
43
+ *
44
+ * The result is awaited inside the callback because `decodeReply()` returns a
45
+ * lazy thenable that only resolves (and imports) its references once awaited.
46
+ */
47
+ function loadOutsideRequestScopes(load) {
48
+ return runOutsideRequestScopes(async () => await load());
49
+ }
31
50
  function parseBoundProgressiveActionReference(body, referencePrefix) {
32
51
  const fieldPrefix = `$ACTION_${referencePrefix}:`;
33
52
  const chunks = /* @__PURE__ */ new Map();
@@ -473,6 +492,25 @@ function shouldUseForwardedActionRedirectStatus(options) {
473
492
  if (!options.currentRoute || !options.targetRoute || !options.resolveRouteRuntime) return false;
474
493
  return normalizeRuntime(options.resolveRouteRuntime(options.currentRoute)) !== normalizeRuntime(options.resolveRouteRuntime(options.targetRoute));
475
494
  }
495
+ /**
496
+ * A failed fetch action's result, as Next.js sends it: a rejected promise.
497
+ * React's Flight error channel reports the rejection through the render's
498
+ * onError and gives the client error its digest, where an Error value would
499
+ * reach the client without one.
500
+ */
501
+ function createRejectedActionResult(error) {
502
+ const result = Promise.reject(error);
503
+ result.catch(() => {});
504
+ return result;
505
+ }
506
+ /**
507
+ * In development the render's onError logs a rejected action result unless it
508
+ * already has a digest; log those here, so each failure is logged once. As in
509
+ * Next.js, a thrown string is not logged in development.
510
+ */
511
+ function logRejectedActionResult(error) {
512
+ if (process.env.NODE_ENV === "production" || hasDigest(error)) console.error("[vinext] Server action error:", error);
513
+ }
476
514
  function getActionHttpFallbackStatus(error) {
477
515
  const digest = getNextErrorDigest(error);
478
516
  if (!digest) return null;
@@ -559,7 +597,7 @@ async function handleProgressiveServerActionRequest(options) {
559
597
  clearRequestContext: options.clearRequestContext,
560
598
  getAndClearPendingCookies: options.getAndClearPendingCookies
561
599
  });
562
- const action = await options.decodeAction(body);
600
+ const action = await loadOutsideRequestScopes(() => options.decodeAction(body));
563
601
  if (!isAppServerActionFunction(action)) {
564
602
  if (options.hasPageRoute) return createActionNotFoundResponse(null, {
565
603
  clearRequestContext: options.clearRequestContext,
@@ -579,6 +617,7 @@ async function handleProgressiveServerActionRequest(options) {
579
617
  let actionRedirect = null;
580
618
  let actionError = void 0;
581
619
  let actionFailed = false;
620
+ let actionFailedWithError = false;
582
621
  let actionThrew = false;
583
622
  let actionResult;
584
623
  const rootParamsUsage = createRootParamsUsageController();
@@ -591,7 +630,8 @@ async function handleProgressiveServerActionRequest(options) {
591
630
  if (!actionRedirect) {
592
631
  actionError = error;
593
632
  actionFailed = true;
594
- if (!(getActionHttpFallbackStatus(error) !== null || isServerActionNotFoundError(error, null))) {
633
+ actionFailedWithError = getActionHttpFallbackStatus(error) === null && !isServerActionNotFoundError(error, null);
634
+ if (actionFailedWithError) {
595
635
  console.error("[vinext] Server action error:", error);
596
636
  options.reportRequestError(error, {
597
637
  path: options.cleanPathname,
@@ -616,6 +656,15 @@ async function handleProgressiveServerActionRequest(options) {
616
656
  const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());
617
657
  const actionDraftCookie = options.getDraftModeCookieHeader();
618
658
  const revalidationKind = resolveActionRevalidationKind(actionPendingCookies.length > 0 || Boolean(actionDraftCookie));
659
+ if (actionFailedWithError) {
660
+ options.clearRequestContext();
661
+ const headers = new Headers();
662
+ mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders);
663
+ headers.set("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
664
+ for (const cookie of actionPendingCookies) headers.append("Set-Cookie", cookie);
665
+ if (actionDraftCookie) headers.append("Set-Cookie", actionDraftCookie);
666
+ return internalServerErrorResponse(process.env.NODE_ENV === "production" ? void 0 : "Server action failed: " + getServerActionFailureMessage(actionError), { headers });
667
+ }
619
668
  if (actionFailed) return {
620
669
  kind: "form-state",
621
670
  formState: null,
@@ -627,7 +676,7 @@ async function handleProgressiveServerActionRequest(options) {
627
676
  };
628
677
  return {
629
678
  kind: "form-state",
630
- formState: await options.decodeFormState(actionResult, body) ?? null,
679
+ formState: await loadOutsideRequestScopes(() => options.decodeFormState(actionResult, body)) ?? null,
631
680
  pendingCookies: actionPendingCookies,
632
681
  draftCookie: actionDraftCookie,
633
682
  revalidationKind
@@ -680,29 +729,18 @@ async function handleProgressiveServerActionRequest(options) {
680
729
  * with status 500 carrying the rejected action result, so the nearest client
681
730
  * error boundary catches it (see action-handler.ts, the `isFetchAction` branch
682
731
  * of the generic error path). vinext mirrors that by rendering a Flight stream
683
- * with `returnValue: { ok: false }` and no page root (the action never ran, so
732
+ * with a rejected `returnValue: { ok: false }` and no page root (the action never ran, so
684
733
  * nothing was revalidated and the page render is skipped). A bare 413 plain
685
734
  * response would bypass the boundary and surface the wrong status/content-type.
686
735
  */
687
736
  async function renderFetchActionBodyExceededResponse(options) {
688
737
  const error = createBodyExceededError(options.maxActionBodySizeLabel);
689
- console.error("[vinext] Server action error:", error);
690
- options.reportRequestError(error, {
691
- path: options.cleanPathname,
692
- method: options.request.method,
693
- headers: Object.fromEntries(options.request.headers.entries())
694
- }, {
695
- routerKind: "App Router",
696
- routePath: options.currentRouteMatch?.route.pattern ?? options.cleanPathname,
697
- routeType: "action",
698
- renderSource: "react-server-components-payload",
699
- revalidateReason: void 0
700
- });
738
+ logRejectedActionResult(error);
701
739
  getAndClearActionRevalidationKind();
702
740
  options.getAndClearPendingCookies();
703
741
  const returnValue = {
704
742
  ok: false,
705
- data: options.sanitizeErrorForClient(error)
743
+ data: createRejectedActionResult(options.sanitizeErrorForClient(error))
706
744
  };
707
745
  const temporaryReferences = options.createTemporaryReferenceSet();
708
746
  const onRenderError = options.createRscOnErrorHandler(options.request, options.cleanPathname, options.currentRouteMatch?.route.pattern ?? options.cleanPathname, {
@@ -727,6 +765,7 @@ async function renderFetchActionBodyExceededResponse(options) {
727
765
  }
728
766
  async function handleServerActionRscRequest(options) {
729
767
  if (options.request.method.toUpperCase() !== "POST" || !options.actionId) return null;
768
+ const actionId = options.actionId;
730
769
  const csrfResponse = validateCsrfOrigin(options.request, options.allowedOrigins);
731
770
  if (csrfResponse) return csrfResponse;
732
771
  if (parseInt(options.request.headers.get("content-length") || "0", 10) > options.maxActionBodySize) {
@@ -738,7 +777,7 @@ async function handleServerActionRscRequest(options) {
738
777
  if (options.contentType.startsWith("multipart/form-data")) {
739
778
  let loadedAction;
740
779
  try {
741
- loadedAction = await options.loadServerAction(options.actionId);
780
+ loadedAction = await loadOutsideRequestScopes(() => options.loadServerAction(actionId));
742
781
  } catch (error) {
743
782
  if (isServerActionNotFoundError(error, options.actionId)) return createActionNotFoundResponse(options.actionId, {
744
783
  clearRequestContext: options.clearRequestContext,
@@ -768,7 +807,7 @@ async function handleServerActionRscRequest(options) {
768
807
  if (action === void 0) {
769
808
  let loadedAction;
770
809
  try {
771
- loadedAction = await options.loadServerAction(options.actionId);
810
+ loadedAction = await loadOutsideRequestScopes(() => options.loadServerAction(actionId));
772
811
  } catch (error) {
773
812
  if (isServerActionNotFoundError(error, options.actionId)) return createActionNotFoundResponse(options.actionId, {
774
813
  clearRequestContext: options.clearRequestContext,
@@ -783,7 +822,7 @@ async function handleServerActionRscRequest(options) {
783
822
  action = loadedAction;
784
823
  }
785
824
  const temporaryReferences = options.createTemporaryReferenceSet();
786
- const args = await options.decodeReply(body, { temporaryReferences });
825
+ const args = await loadOutsideRequestScopes(() => options.decodeReply(body, { temporaryReferences }));
787
826
  let returnValue;
788
827
  let actionRedirect = null;
789
828
  let actionStatus = 200;
@@ -815,10 +854,10 @@ async function handleServerActionRscRequest(options) {
815
854
  };
816
855
  } else {
817
856
  actionStatus = 500;
818
- console.error("[vinext] Server action error:", error);
857
+ logRejectedActionResult(error);
819
858
  returnValue = {
820
859
  ok: false,
821
- data: options.sanitizeErrorForClient(error)
860
+ data: createRejectedActionResult(options.sanitizeErrorForClient(error))
822
861
  };
823
862
  }
824
863
  }
@@ -27,6 +27,7 @@ import { createClientPageSsrSearchParamsSource } from "./app-page-search-params-
27
27
  import { runWithRootParamsScope } from "../shims/root-params.js";
28
28
  import { runWithNavigationContext } from "../shims/navigation-state.js";
29
29
  import { startCandidateSearchParamsGate } from "./app-ssr-search-params-gate.js";
30
+ import { withAppRouterTree } from "../shims/app-router-tree-context.js";
30
31
  import { BeforeInteractiveContext } from "../shims/before-interactive-context.js";
31
32
  import { renderBeforeInteractiveInlineScripts } from "./before-interactive-head.js";
32
33
  import { createInitialDevServerErrorScript } from "./dev-initial-server-error.js";
@@ -246,7 +247,7 @@ async function handleSsr(rscStream, navContext, fontData, options) {
246
247
  beforeInteractiveInlineScripts.push(script);
247
248
  };
248
249
  const treeWithBeforeInteractive = createElement(BeforeInteractiveContext.Provider, { value: registerBeforeInteractiveInlineScript }, ssrTree);
249
- const ssrRoot = withScriptNonce(treeWithBeforeInteractive, options?.scriptNonce);
250
+ const ssrRoot = withScriptNonce(withAppRouterTree(treeWithBeforeInteractive), options?.scriptNonce);
250
251
  const bootstrapModuleUrl = extractBootstrapModuleUrl(await import.meta.viteRsc.loadBootstrapScriptContent("index"));
251
252
  const errorMetaRenderer = createSsrErrorMetaRenderer({ basePath: options?.basePath });
252
253
  const pprFallbackShellSignal = options?.pprFallbackShellSignal;
@@ -18,6 +18,11 @@ type AppWorkerResponseStageEnvelope = {
18
18
  };
19
19
  type AppFullRequestWorkerResponseStageProps = AppWorkerResponseStageEnvelope & {
20
20
  kind: "app-full-request";
21
+ /**
22
+ * The public request is HEAD. It is dispatched as GET so a transport that
23
+ * applies HEAD semantics cannot drop the static-file signal's body.
24
+ */
25
+ headRequest: boolean;
21
26
  prerenderDiscovery: boolean;
22
27
  staticFileSignalToken: string;
23
28
  trustedPrerenderState: TrustedPrerenderState | null;