vinext 1.0.0 → 1.1.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 (263) hide show
  1. package/README.md +72 -1
  2. package/THIRD_PARTY_LICENSES.md +26 -0
  3. package/dist/build/app-page-static-eligibility.d.ts +15 -0
  4. package/dist/build/app-page-static-eligibility.js +82 -0
  5. package/dist/build/lifecycle.js +10 -10
  6. package/dist/build/pages-client-assets-module.js +6 -1
  7. package/dist/build/precompress.js +1 -1
  8. package/dist/build/prerender-paths.js +6 -85
  9. package/dist/build/prerender.d.ts +8 -1
  10. package/dist/build/prerender.js +167 -46
  11. package/dist/build/run-prerender.js +4 -3
  12. package/dist/build/server-entry.d.ts +2 -0
  13. package/dist/build/server-entry.js +7 -1
  14. package/dist/build/server-manifest.d.ts +7 -0
  15. package/dist/build/server-manifest.js +11 -1
  16. package/dist/cache/cache-adapters-virtual.d.ts +7 -1
  17. package/dist/cache/cache-adapters-virtual.js +3 -3
  18. package/dist/client/browser-globals.d.ts +4 -0
  19. package/dist/client/browser-globals.js +5 -0
  20. package/dist/client/navigation-runtime.d.ts +11 -1
  21. package/dist/client/navigation-runtime.js +3 -3
  22. package/dist/config/config-matchers.js +3 -1
  23. package/dist/config/dotenv.js +14 -3
  24. package/dist/config/next-config.d.ts +7 -0
  25. package/dist/config/next-config.js +18 -3
  26. package/dist/entries/app-rsc-entry.d.ts +2 -0
  27. package/dist/entries/app-rsc-entry.js +67 -45
  28. package/dist/index.d.ts +4 -1
  29. package/dist/index.js +200 -100
  30. package/dist/init-cloudflare.d.ts +1 -1
  31. package/dist/init-cloudflare.js +6 -6
  32. package/dist/init-platform.js +1 -1
  33. package/dist/init.js +4 -2
  34. package/dist/plugins/cache-flight-codec.d.ts +19 -0
  35. package/dist/plugins/cache-flight-codec.js +68 -0
  36. package/dist/plugins/commonjs-esm-facade.d.ts +35 -0
  37. package/dist/plugins/commonjs-esm-facade.js +80 -0
  38. package/dist/plugins/commonjs-syntax.d.ts +16 -0
  39. package/dist/plugins/commonjs-syntax.js +22 -0
  40. package/dist/plugins/fonts.d.ts +8 -11
  41. package/dist/plugins/fonts.js +71 -34
  42. package/dist/plugins/ignore-dynamic-requests.d.ts +11 -0
  43. package/dist/plugins/ignore-dynamic-requests.js +54 -3
  44. package/dist/plugins/import-meta-url.js +6 -6
  45. package/dist/plugins/og-asset-ownership.d.ts +2 -0
  46. package/dist/plugins/og-asset-ownership.js +24 -13
  47. package/dist/plugins/og-assets.d.ts +18 -0
  48. package/dist/plugins/og-assets.js +50 -8
  49. package/dist/plugins/og-harfbuzz.js +38 -27
  50. package/dist/plugins/optimize-imports.js +2 -1
  51. package/dist/plugins/require-context.d.ts +1 -0
  52. package/dist/plugins/require-context.js +28 -1
  53. package/dist/plugins/scan-build-css.d.ts +12 -0
  54. package/dist/plugins/scan-build-css.js +39 -0
  55. package/dist/plugins/strip-server-exports.d.ts +2 -0
  56. package/dist/plugins/strip-server-exports.js +3 -1
  57. package/dist/plugins/transform-result.d.ts +18 -0
  58. package/dist/plugins/transform-result.js +23 -2
  59. package/dist/plugins/typeof-window.d.ts +10 -0
  60. package/dist/plugins/typeof-window.js +33 -9
  61. package/dist/routing/app-route-graph.d.ts +0 -1
  62. package/dist/routing/app-route-graph.js +2 -4
  63. package/dist/routing/app-route-ids.d.ts +3 -0
  64. package/dist/routing/app-route-ids.js +6 -0
  65. package/dist/routing/file-matcher.d.ts +1 -0
  66. package/dist/routing/file-matcher.js +1 -1
  67. package/dist/server/api-handler.js +17 -7
  68. package/dist/server/app-bfcache-id.d.ts +1 -0
  69. package/dist/server/app-bfcache-id.js +7 -1
  70. package/dist/server/app-bfcache-identity.js +1 -2
  71. package/dist/server/app-browser-entry.js +15 -9
  72. package/dist/server/app-browser-history-controller.d.ts +2 -0
  73. package/dist/server/app-browser-history-controller.js +8 -0
  74. package/dist/server/app-browser-hydration.d.ts +1 -1
  75. package/dist/server/app-browser-hydration.js +2 -2
  76. package/dist/server/app-browser-interception-context.js +26 -2
  77. package/dist/server/app-browser-navigation-controller.d.ts +7 -1
  78. package/dist/server/app-browser-navigation-controller.js +94 -11
  79. package/dist/server/app-browser-state.js +1 -1
  80. package/dist/server/app-browser-stream.d.ts +1 -1
  81. package/dist/server/app-fallback-renderer.d.ts +2 -0
  82. package/dist/server/app-fallback-renderer.js +1 -0
  83. package/dist/server/app-history-state.d.ts +3 -1
  84. package/dist/server/app-history-state.js +9 -5
  85. package/dist/server/app-middleware.js +2 -1
  86. package/dist/server/app-optimistic-routing.js +1 -1
  87. package/dist/server/app-page-boundary-render.d.ts +5 -0
  88. package/dist/server/app-page-boundary-render.js +6 -4
  89. package/dist/server/app-page-cache-finalizer.d.ts +11 -0
  90. package/dist/server/app-page-cache-finalizer.js +41 -7
  91. package/dist/server/app-page-cache-render.d.ts +18 -0
  92. package/dist/server/app-page-cache-render.js +65 -44
  93. package/dist/server/app-page-cache.d.ts +5 -0
  94. package/dist/server/app-page-cache.js +27 -7
  95. package/dist/server/app-page-dispatch.d.ts +9 -1
  96. package/dist/server/app-page-dispatch.js +47 -30
  97. package/dist/server/app-page-element-builder.d.ts +7 -0
  98. package/dist/server/app-page-element-builder.js +27 -42
  99. package/dist/server/app-page-execution.d.ts +15 -12
  100. package/dist/server/app-page-execution.js +30 -40
  101. package/dist/server/app-page-head.d.ts +5 -0
  102. package/dist/server/app-page-head.js +9 -3
  103. package/dist/server/app-page-probe.d.ts +0 -109
  104. package/dist/server/app-page-probe.js +3 -136
  105. package/dist/server/app-page-render-identity.d.ts +0 -1
  106. package/dist/server/app-page-render-identity.js +1 -1
  107. package/dist/server/app-page-render-observation.js +2 -2
  108. package/dist/server/app-page-render.d.ts +13 -5
  109. package/dist/server/app-page-render.js +219 -118
  110. package/dist/server/app-page-request.d.ts +0 -1
  111. package/dist/server/app-page-request.js +1 -2
  112. package/dist/server/app-page-response.d.ts +4 -3
  113. package/dist/server/app-page-response.js +4 -3
  114. package/dist/server/app-page-route-wiring.d.ts +17 -5
  115. package/dist/server/app-page-route-wiring.js +55 -33
  116. package/dist/server/app-page-rsc-render-status.d.ts +48 -0
  117. package/dist/server/app-page-rsc-render-status.js +54 -0
  118. package/dist/server/app-page-search-params-observation.js +1 -1
  119. package/dist/server/app-page-stream.d.ts +15 -8
  120. package/dist/server/app-page-stream.js +7 -1
  121. package/dist/server/app-page-tracing.js +2 -1
  122. package/dist/server/app-pages-bridge.js +3 -2
  123. package/dist/server/app-render-abort-error.d.ts +3 -0
  124. package/dist/server/app-render-abort-error.js +8 -0
  125. package/dist/server/app-request-stage-dispatch.js +1 -1
  126. package/dist/server/app-request-stage-independent-entry.js +8 -11
  127. package/dist/server/app-response-header-provenance.d.ts +2 -0
  128. package/dist/server/app-response-header-provenance.js +10 -4
  129. package/dist/server/app-route-handler-cache.d.ts +2 -1
  130. package/dist/server/app-route-handler-cache.js +11 -7
  131. package/dist/server/app-route-handler-dispatch.js +11 -4
  132. package/dist/server/app-route-handler-execution.d.ts +9 -1
  133. package/dist/server/app-route-handler-execution.js +28 -13
  134. package/dist/server/app-route-handler-policy.js +2 -2
  135. package/dist/server/app-route-handler-response.d.ts +1 -1
  136. package/dist/server/app-route-handler-response.js +14 -5
  137. package/dist/server/app-router-entry.d.ts +2 -1
  138. package/dist/server/app-router-entry.js +8 -12
  139. package/dist/server/app-rsc-errors.d.ts +0 -1
  140. package/dist/server/app-rsc-errors.js +2 -6
  141. package/dist/server/app-rsc-handler.d.ts +5 -0
  142. package/dist/server/app-rsc-handler.js +229 -102
  143. package/dist/server/app-rsc-request-normalization.d.ts +4 -2
  144. package/dist/server/app-rsc-request-normalization.js +7 -4
  145. package/dist/server/app-rsc-response-finalizer.js +4 -1
  146. package/dist/server/app-rsc-response-stage.d.ts +1 -1
  147. package/dist/server/app-rsc-response-stage.js +6 -4
  148. package/dist/server/app-rsc-route-matching.d.ts +9 -1
  149. package/dist/server/app-rsc-route-matching.js +37 -20
  150. package/dist/server/app-server-action-execution.d.ts +2 -1
  151. package/dist/server/app-server-action-execution.js +1 -1
  152. package/dist/server/app-ssr-entry.d.ts +3 -2
  153. package/dist/server/app-ssr-entry.js +9 -7
  154. package/dist/server/app-ssr-search-params-gate.js +1 -1
  155. package/dist/server/app-ssr-stream.d.ts +6 -1
  156. package/dist/server/app-ssr-stream.js +35 -16
  157. package/dist/server/app-worker-stages.d.ts +2 -2
  158. package/dist/server/app-worker-stages.js +3 -3
  159. package/dist/server/cache-control.js +3 -11
  160. package/dist/server/cacheability-request.js +56 -52
  161. package/dist/server/config-headers.js +3 -1
  162. package/dist/server/dev-server.js +23 -5
  163. package/dist/server/headers.d.ts +16 -0
  164. package/dist/server/headers.js +19 -1
  165. package/dist/server/http-error-responses.js +1 -0
  166. package/dist/server/image-optimization.d.ts +16 -0
  167. package/dist/server/image-optimization.js +26 -6
  168. package/dist/server/isr-cache.d.ts +2 -0
  169. package/dist/server/isr-cache.js +8 -3
  170. package/dist/server/metadata-route-response.js +94 -37
  171. package/dist/server/middleware-matcher-pattern.js +8 -4
  172. package/dist/server/middleware-response-headers.js +2 -0
  173. package/dist/server/multi-stage.d.ts +8 -0
  174. package/dist/server/navigation-planner.js +1 -1
  175. package/dist/server/node-response-signal.d.ts +16 -0
  176. package/dist/server/node-response-signal.js +26 -0
  177. package/dist/server/open-redirect.d.ts +47 -0
  178. package/dist/server/open-redirect.js +74 -1
  179. package/dist/server/pages-api-route.js +8 -2
  180. package/dist/server/pages-asset-tags.d.ts +1 -0
  181. package/dist/server/pages-asset-tags.js +73 -22
  182. package/dist/server/pages-client-assets.d.ts +2 -0
  183. package/dist/server/pages-page-data.d.ts +6 -1
  184. package/dist/server/pages-page-data.js +71 -65
  185. package/dist/server/pages-page-handler.js +50 -15
  186. package/dist/server/pages-page-response.js +3 -1
  187. package/dist/server/pages-request-pipeline.d.ts +2 -1
  188. package/dist/server/pages-request-pipeline.js +20 -5
  189. package/dist/server/pages-request-stage-entry.js +14 -8
  190. package/dist/server/prerender-manifest.d.ts +6 -0
  191. package/dist/server/prerender-manifest.js +1 -1
  192. package/dist/server/prod-server.d.ts +8 -7
  193. package/dist/server/prod-server.js +152 -78
  194. package/dist/server/request-pipeline.d.ts +20 -8
  195. package/dist/server/request-pipeline.js +21 -7
  196. package/dist/server/response-compression.d.ts +43 -0
  197. package/dist/server/response-compression.js +111 -0
  198. package/dist/server/response-stage-cacheability.js +1 -1
  199. package/dist/server/seed-cache.js +10 -7
  200. package/dist/server/socket-error-backstop.d.ts +14 -0
  201. package/dist/server/socket-error-backstop.js +27 -4
  202. package/dist/server/worker-revalidation-context.d.ts +2 -1
  203. package/dist/server/worker-revalidation-context.js +1 -0
  204. package/dist/server/workers-tracing.d.ts +17 -0
  205. package/dist/server/workers-tracing.js +48 -8
  206. package/dist/shims/cache-adapter-instantiate.d.ts +50 -0
  207. package/dist/shims/cache-adapter-instantiate.js +118 -0
  208. package/dist/shims/cache-callable-runtime.d.ts +2 -40
  209. package/dist/shims/cache-callable-runtime.js +50 -168
  210. package/dist/shims/cache-flight-arguments.d.ts +22 -0
  211. package/dist/shims/cache-flight-arguments.js +56 -0
  212. package/dist/shims/cache-request-state.d.ts +18 -14
  213. package/dist/shims/cache-request-state.js +33 -21
  214. package/dist/shims/cache-runtime.d.ts +6 -19
  215. package/dist/shims/cache-runtime.js +168 -226
  216. package/dist/shims/cache.d.ts +3 -2
  217. package/dist/shims/cache.js +8 -5
  218. package/dist/shims/cacheability-classification.d.ts +8 -1
  219. package/dist/shims/cacheability-classification.js +2 -2
  220. package/dist/shims/cdn-cache.d.ts +10 -1
  221. package/dist/shims/cdn-cache.js +16 -9
  222. package/dist/shims/error-boundary-navigation.d.ts +7 -0
  223. package/dist/shims/error-boundary-navigation.js +19 -1
  224. package/dist/shims/error-boundary.d.ts +10 -10
  225. package/dist/shims/error-boundary.js +26 -7
  226. package/dist/shims/error.d.ts +4 -18
  227. package/dist/shims/error.js +17 -10
  228. package/dist/shims/error.react-server.d.ts +4 -6
  229. package/dist/shims/error.react-server.js +4 -1
  230. package/dist/shims/fetch-cache.d.ts +6 -0
  231. package/dist/shims/fetch-cache.js +23 -4
  232. package/dist/shims/form.js +1 -1
  233. package/dist/shims/headers.d.ts +19 -69
  234. package/dist/shims/headers.js +82 -183
  235. package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -2
  236. package/dist/shims/internal/app-page-props-cache-key.js +24 -15
  237. package/dist/shims/internal/cache-context-accessor.d.ts +16 -0
  238. package/dist/shims/internal/cache-context-accessor.js +15 -0
  239. package/dist/shims/internal/headers-state.d.ts +73 -0
  240. package/dist/shims/internal/headers-state.js +157 -0
  241. package/dist/shims/metadata.js +3 -3
  242. package/dist/shims/navigation-errors.d.ts +6 -0
  243. package/dist/shims/navigation-errors.js +11 -1
  244. package/dist/shims/navigation.d.ts +7 -0
  245. package/dist/shims/navigation.js +16 -6
  246. package/dist/shims/request-context.d.ts +9 -0
  247. package/dist/shims/request-state-types.d.ts +2 -1
  248. package/dist/shims/root-params.js +1 -1
  249. package/dist/shims/server.js +52 -2
  250. package/dist/shims/thenable-params.d.ts +4 -0
  251. package/dist/shims/thenable-params.js +25 -3
  252. package/dist/shims/unified-request-context.d.ts +1 -1
  253. package/dist/shims/unified-request-context.js +1 -0
  254. package/dist/utils/encode-cache-tag.d.ts +1 -0
  255. package/dist/utils/encode-cache-tag.js +11 -1
  256. package/dist/utils/mdx-scan.d.ts +5 -0
  257. package/dist/utils/mdx-scan.js +8 -1
  258. package/dist/utils/regex-safety.d.ts +10 -0
  259. package/dist/utils/regex-safety.js +70 -18
  260. package/dist/utils/vite-cli-invocation.js +8 -1
  261. package/package.json +8 -4
  262. package/dist/server/metadata-route-cache-policy.d.ts +0 -5
  263. package/dist/server/metadata-route-cache-policy.js +0 -6
@@ -4,15 +4,16 @@ import { PRERENDER_REVALIDATE_HEADER, VINEXT_MW_CTX_HEADER, VINEXT_PRERENDER_ROU
4
4
  import { 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
+ import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
7
8
  import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
8
9
  import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base-path.js";
9
10
  import { patternToNextFormat } from "../routing/route-validation.js";
10
11
  import { getRequestExecutionContext } from "../shims/request-context.js";
11
12
  import "./app-rsc-vary.js";
12
- import { ACTION_REVALIDATED_HEADER, FLIGHT_HEADERS, VINEXT_PARAMS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER } from "./headers.js";
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";
13
14
  import { isInterceptionMatchedUrlPath, normalizePath } from "./normalize-path.js";
14
- import { badRequestResponse, notFoundResponse } from "./http-error-responses.js";
15
- import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, resolvePublicFileRoute } from "./request-pipeline.js";
15
+ import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } from "./http-error-responses.js";
16
+ import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, normalizeTrailingSlash, normalizeTrailingSlashPathname, resolvePublicFileRoute } from "./request-pipeline.js";
16
17
  import { normalizeDefaultLocalePathname } from "./pages-i18n.js";
17
18
  import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
18
19
  import { markRouteCacheabilityDynamic, preserveRouteCacheabilityResponsePolicy } from "../shims/cacheability-classification.js";
@@ -36,6 +37,8 @@ import { setFrameworkRequestRoute, traceFrameworkRequest } from "./request-traci
36
37
  import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
37
38
  import { buildPageCacheTags } from "./implicit-tags.js";
38
39
  import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
40
+ import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
41
+ import { normalizeInterceptionContextHeader } from "./app-interception-context-header.js";
39
42
  import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
40
43
  import { pickRootParams, setRootParams } from "../shims/root-params.js";
41
44
  import { createRouteTreePrefetchResponse, isRouteTreePrefetchRequest } from "./app-route-tree-prefetch.js";
@@ -50,6 +53,33 @@ import { consumePagesResponseStagePolicyOwner, withoutResponseStageVary } from "
50
53
  const HAS_CONFIG_HEADERS = process.env.__VINEXT_HAS_CONFIG_HEADERS !== "false";
51
54
  const HAS_CONFIG_REDIRECTS = process.env.__VINEXT_HAS_CONFIG_REDIRECTS !== "false";
52
55
  const HAS_CONFIG_REWRITES = process.env.__VINEXT_HAS_CONFIG_REWRITES !== "false";
56
+ /**
57
+ * Decode an interception context to the canonical source pathname it names.
58
+ * Throws for any value the client could not send back as its context header.
59
+ */
60
+ function decodeInterceptionSourcePathname(context) {
61
+ if (!isInterceptionMatchedUrlPath(context)) throw new Error("Invalid interception source pathname");
62
+ if (new URL(context, "http://n").pathname !== context) throw new Error("Interception source is not a parsed URL pathname");
63
+ const decodedSourcePathname = normalizePathnameForRouteMatchStrict(context);
64
+ if (/[\t\n\r]/.test(decodedSourcePathname)) throw new Error("Interception source contains a stripped URL character");
65
+ if (hasUrlParserDotSegment(decodedSourcePathname)) throw new Error("Interception source contains a URL dot segment");
66
+ const sourcePathname = normalizePath(decodedSourcePathname);
67
+ if (sourcePathname !== decodedSourcePathname) throw new Error("Non-canonical interception source pathname");
68
+ return sourcePathname;
69
+ }
70
+ /**
71
+ * Whether a server-derived context satisfies the whole inbound header
72
+ * contract, so the client can send it back unchanged on its next request.
73
+ */
74
+ function isValidInterceptionSourceContext(context) {
75
+ if (normalizeInterceptionContextHeader(context) !== context) return false;
76
+ try {
77
+ decodeInterceptionSourcePathname(context);
78
+ return true;
79
+ } catch {
80
+ return false;
81
+ }
82
+ }
53
83
  function ruleUsesUnkeyedRequestCondition(rule) {
54
84
  return [...rule.has ?? [], ...rule.missing ?? []].some((condition) => condition.type === "header" || condition.type === "cookie" || condition.type === "host");
55
85
  }
@@ -122,6 +152,26 @@ function applyMiddlewareContextToResponse(response, middlewareContext, appendToP
122
152
  headers
123
153
  }));
124
154
  }
155
+ /**
156
+ * Next.js answers a Link's segment prefetch of a page whose notFound(),
157
+ * forbidden() or unauthorized() it stored with a 200, so its router renders
158
+ * the page's fallback without loading the document. A shared response stage
159
+ * gives that prefetch the navigation's response, so the request's own headers
160
+ * decide the status here.
161
+ */
162
+ function withStoredSpecialErrorStatus(response, isSegmentPrefetch) {
163
+ const marker = response.headers.get(VINEXT_SPECIAL_ERROR_STATUS_HEADER);
164
+ if (marker === null) return response;
165
+ const headers = new Headers(response.headers);
166
+ headers.delete(VINEXT_SPECIAL_ERROR_STATUS_HEADER);
167
+ const storedStatus = Number(marker);
168
+ const status = !(storedStatus === 401 || storedStatus === 403 || storedStatus === 404) ? response.status : isSegmentPrefetch ? 200 : storedStatus;
169
+ return preserveFullyBufferedBodyMetadata(response, new Response(response.body, {
170
+ headers,
171
+ status,
172
+ statusText: status === response.status ? response.statusText : ""
173
+ }));
174
+ }
125
175
  function hasProperty(value, key) {
126
176
  return key in value;
127
177
  }
@@ -205,7 +255,8 @@ function requestWithoutRscSuffix(request) {
205
255
  url.pathname = pathname;
206
256
  return cloneRequestWithUrl(request, url.toString());
207
257
  }
208
- function markUnverifiedInterceptionResponseUncacheable(response) {
258
+ /** Send a response with the never-cache policy, rebuilding immutable headers. */
259
+ function withNeverCacheControl(response) {
209
260
  const applyNoStore = (headers) => {
210
261
  applyCdnResponseHeaders(headers, { cacheControl: NEVER_CACHE_CONTROL });
211
262
  };
@@ -223,6 +274,13 @@ function markUnverifiedInterceptionResponseUncacheable(response) {
223
274
  }
224
275
  return markedResponse;
225
276
  }
277
+ const unmatchedRouteResponses = /* @__PURE__ */ new WeakSet();
278
+ /** Send an unmatched route's 404 with the never-cache policy, as Next.js does. */
279
+ function withUnmatchedRouteCacheControl(response) {
280
+ const markedResponse = withNeverCacheControl(response);
281
+ unmatchedRouteResponses.add(markedResponse);
282
+ return markedResponse;
283
+ }
226
284
  async function handleAppRscRequest(options, request, preMiddlewareRequestContext, middlewareContext, isDataRequest, isMiddlewareDataRequest, pagesDataRequest, dispatchInternalRequest, allowInternalRscDocumentFallback, dispatchResponseStage, responseStageProbeMode = null, setInterceptionResponseUncacheable = () => {}) {
227
285
  const handlerStart = process.env.NODE_ENV !== "production" ? performance.now() : 0;
228
286
  if (process.env.NODE_ENV !== "production") {
@@ -236,7 +294,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
236
294
  ...options.configRewrites.fallback,
237
295
  ...options.configHeaders
238
296
  ].some((rule) => rule.basePath === false);
239
- const normalized = normalizeRscRequest(request, options.basePath, canHandleOutsideBasePath);
297
+ const normalized = normalizeRscRequest(request, options.basePath, canHandleOutsideBasePath, options.assetPrefix);
240
298
  if (normalized instanceof Response) {
241
299
  if (request.headers.has("X-Vinext-Interception-Context") || request.headers.has("X-Vinext-Interception-Id")) setInterceptionResponseUncacheable(true);
242
300
  return normalized;
@@ -247,12 +305,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
247
305
  if (hasRawInterceptionContext) setInterceptionResponseUncacheable(true);
248
306
  let interceptionSourcePathname = null;
249
307
  if (isRscRequest && interceptionContextHeader !== null) try {
250
- if (!isInterceptionMatchedUrlPath(interceptionContextHeader)) throw new Error("Invalid interception source pathname");
251
- const decodedInterceptionSourcePathname = normalizePathnameForRouteMatchStrict(interceptionContextHeader);
252
- if (/[\t\n\r]/.test(decodedInterceptionSourcePathname)) throw new Error("Interception source contains a stripped URL character");
253
- if (hasUrlParserDotSegment(decodedInterceptionSourcePathname)) throw new Error("Interception source contains a URL dot segment");
254
- interceptionSourcePathname = normalizePath(decodedInterceptionSourcePathname);
255
- if (interceptionSourcePathname !== decodedInterceptionSourcePathname) throw new Error("Non-canonical interception source pathname");
308
+ interceptionSourcePathname = decodeInterceptionSourcePathname(interceptionContextHeader);
256
309
  } catch {
257
310
  options.clearRequestContext();
258
311
  setInterceptionResponseUncacheable(true);
@@ -281,10 +334,10 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
281
334
  });
282
335
  if (selectorCacheBustingRedirect) return selectorCacheBustingRedirect;
283
336
  }
284
- const provesConcreteInterceptionSource = (sourceMatch) => {
337
+ const provesConcreteInterceptionSource = (sourceMatch, sourceContext = interceptionContextHeader) => {
285
338
  if (sourceMatch === null) return false;
286
339
  if (sourceMatch.interceptionSourceIsConcrete !== void 0) return sourceMatch.interceptionSourceIsConcrete;
287
- return interceptionSourcePathname !== null && options.matchRoute(interceptionSourcePathname)?.route === sourceMatch.route;
340
+ return sourceContext !== null && (options.matchRequestRoute ?? options.matchRoute)(sourceContext)?.route === sourceMatch.route;
288
341
  };
289
342
  if (provesConcreteInterceptionSource(hadBasePath && hasRawInterceptionContext && interceptionContextHeader !== null ? options.matchInterceptRoute?.(requestCleanPathname, interceptionContextHeader, interceptionIdHeader) ?? null : null)) setInterceptionResponseUncacheable(false);
290
343
  if (pathname === "/__vinext/prerender/static-params" || pathname === "/__vinext/prerender/pages-static-paths" || pathname === "/__vinext/prerender/metadata-routes") {
@@ -460,7 +513,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
460
513
  isRscRequest,
461
514
  middlewareCookieOverlay,
462
515
  mountedSlotsHeader,
463
- protocolVersion: 10,
516
+ protocolVersion: 11,
464
517
  requestOrigin: url.origin,
465
518
  renderMode,
466
519
  resolvedUrl,
@@ -617,8 +670,9 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
617
670
  });
618
671
  const directPreActionMatch = filesystemRouteEligible ? matchCleanPathname() : null;
619
672
  const preActionRoutePathname = cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname;
620
- const interceptionSourceMatch = filesystemRouteEligible && interceptionSourcePathname !== null && interceptionContextHeader !== null ? options.matchInterceptRoute?.(preActionRoutePathname, interceptionContextHeader, interceptionIdHeader) ?? null : null;
621
- const hasVerifiedInterceptionSource = provesConcreteInterceptionSource(interceptionSourceMatch);
673
+ let interceptionSourceContext = interceptionContextHeader;
674
+ let interceptionSourceMatch = filesystemRouteEligible && interceptionSourcePathname !== null && interceptionContextHeader !== null ? options.matchInterceptRoute?.(preActionRoutePathname, interceptionContextHeader, interceptionIdHeader) ?? null : null;
675
+ let hasVerifiedInterceptionSource = provesConcreteInterceptionSource(interceptionSourceMatch);
622
676
  if (interceptionIdHeader !== null && !hasVerifiedInterceptionSource) {
623
677
  options.clearRequestContext();
624
678
  setInterceptionResponseUncacheable(true);
@@ -633,81 +687,142 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
633
687
  bypassInterceptionContextCache = true;
634
688
  setInterceptionResponseUncacheable(true);
635
689
  };
636
- if (interceptionSourceMatch !== null && interceptionSourcePathname !== null && runMiddleware && interceptionSourceMatch.route !== directPreActionMatch?.route) {
637
- const sourceUrl = new URL(userlandRequest.url);
638
- sourceUrl.search = new URL(resolvedUrl, url).search;
639
- sourceUrl.pathname = hadBasePath ? addBasePathToPathname(interceptionSourcePathname, options.basePath) : interceptionSourcePathname;
640
- const sourceRequest = userlandRequest.body ? userlandRequest.clone() : userlandRequest;
641
- const sourceMiddlewareRequest = cloneRequestWithUrl(sourceRequest, sourceUrl.href);
642
- sourceMiddlewareRequest.headers.delete(VINEXT_MW_CTX_HEADER);
643
- for (const header of FLIGHT_HEADERS) sourceMiddlewareRequest.headers.delete(header);
644
- const targetHeadersContext = getHeadersContext();
645
- const targetRequestHeaders = targetHeadersContext ? new Headers(targetHeadersContext.headers) : null;
646
- targetRequestHeaders?.delete(VINEXT_MW_CTX_HEADER);
647
- for (const header of FLIGHT_HEADERS) targetRequestHeaders?.delete(header);
648
- if (targetRequestHeaders) {
649
- const sourceHeaderNames = Array.from(sourceMiddlewareRequest.headers.keys());
650
- for (const header of sourceHeaderNames) sourceMiddlewareRequest.headers.delete(header);
651
- for (const [name, value] of targetRequestHeaders) sourceMiddlewareRequest.headers.append(name, value);
652
- }
653
- const sourceMiddlewareContext = {
654
- headers: null,
655
- requestHeaders: null,
656
- status: null
657
- };
658
- const sourceHeadersContext = headersContextFromRequest(sourceMiddlewareRequest, { draftModeSecret: options.draftModeSecret });
659
- let sourceMiddlewareResult;
660
- try {
661
- sourceMiddlewareResult = await runWithHeadersContext(sourceHeadersContext, () => runMiddleware({
662
- cleanPathname: interceptionSourcePathname,
663
- context: sourceMiddlewareContext,
664
- externalRewriteRequest: normalizedUserlandRequest,
665
- hadBasePath,
666
- isDataRequest: isMiddlewareDataRequest,
667
- request: sourceMiddlewareRequest,
668
- validateExternalRewriteRequest: () => validateClaimedOutsideBasePathRsc(true)
669
- }));
670
- } finally {
671
- if (sourceMiddlewareRequest.body && !sourceMiddlewareRequest.bodyUsed && !sourceMiddlewareRequest.body.locked) sourceMiddlewareRequest.body.cancel().catch(() => {});
672
- if (sourceRequest !== userlandRequest && sourceRequest.body && !sourceRequest.bodyUsed && !sourceRequest.body.locked) sourceRequest.body.cancel().catch(() => {});
673
- }
674
- if (!dispatchResponseStage && sourceMiddlewareResult.pathnameEligible) markRouteCacheabilityDynamic(sourceMiddlewareResult.matched ? "middleware matched this request" : "middleware is eligible for this pathname");
675
- if (sourceMiddlewareResult.kind === "response") {
676
- options.clearRequestContext();
677
- return sourceMiddlewareResult.response;
678
- }
679
- let sourceHeadersCompatible = true;
680
- if (targetRequestHeaders) {
681
- for (const [name, value] of targetRequestHeaders) if (sourceHeadersContext.headers.get(name) !== value) {
682
- sourceHeadersCompatible = false;
683
- break;
690
+ 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;
693
+ const adoptRewrittenInterceptionSource = (rewrittenPathname) => {
694
+ const rewrittenInterceptionSourceMatch = isValidInterceptionSourceContext(rewrittenPathname) ? options.matchInterceptRoute?.(preActionRoutePathname, rewrittenPathname, interceptionIdHeader) ?? null : null;
695
+ if (rewrittenInterceptionSourceMatch !== null) {
696
+ interceptionSourceMatch = rewrittenInterceptionSourceMatch;
697
+ interceptionSourceContext = rewrittenPathname;
684
698
  }
685
- }
686
- if (!targetHeadersContext || !targetRequestHeaders || !sourceHeadersCompatible || !haveSameRequestCookies(targetHeadersContext.cookies, sourceHeadersContext.cookies)) {
699
+ const rewrittenSourceMatch = options.matchRoute(rewrittenPathname);
700
+ return interceptionSourceMatch !== null && rewrittenSourceMatch?.route === interceptionSourceMatch.route && haveSamePageParams(rewrittenSourceMatch.params, interceptionSourceMatch.params);
701
+ };
702
+ if (configMatchers?.matchRedirect(matchPathname(sourceRequestPathname), options.configRedirects, preMiddlewareRequestContext, basePathState, dispatchResponseStage ? void 0 : markConditionalRedirectCacheability)) {
687
703
  options.clearRequestContext();
688
704
  return notFoundResponse();
689
705
  }
690
- let addedSourceHeader = false;
691
- for (const [name, value] of sourceHeadersContext.headers) if (!targetRequestHeaders.has(name)) {
692
- targetHeadersContext.headers.set(name, value);
693
- addedSourceHeader = true;
694
- }
695
- if (addedSourceHeader) {
696
- targetHeadersContext.readonlyHeaders = void 0;
697
- canUseSharedWorkerResponseStage = false;
706
+ let sourceRulesPathname = sourceRequestPathname;
707
+ if (runMiddleware) {
708
+ const sourceUrl = new URL(userlandRequest.url);
709
+ sourceUrl.search = new URL(resolvedUrl, url).search;
710
+ const sourceUrlPathname = hadBasePath && options.basePath ? sourceRequestPathname === "/" ? options.basePath : options.basePath + sourceRequestPathname : sourceRequestPathname;
711
+ sourceUrl.pathname = sourceUrlPathname;
712
+ if (sourceUrl.pathname !== sourceUrlPathname) {
713
+ options.clearRequestContext();
714
+ setInterceptionResponseUncacheable(true);
715
+ return badRequestResponse();
716
+ }
717
+ const sourceRequest = userlandRequest.body ? userlandRequest.clone() : userlandRequest;
718
+ const sourceMiddlewareRequest = cloneRequestWithUrl(sourceRequest, sourceUrl.href);
719
+ sourceMiddlewareRequest.headers.delete(VINEXT_MW_CTX_HEADER);
720
+ for (const header of FLIGHT_HEADERS) sourceMiddlewareRequest.headers.delete(header);
721
+ const targetHeadersContext = getHeadersContext();
722
+ const targetRequestHeaders = targetHeadersContext ? new Headers(targetHeadersContext.headers) : null;
723
+ targetRequestHeaders?.delete(VINEXT_MW_CTX_HEADER);
724
+ for (const header of FLIGHT_HEADERS) targetRequestHeaders?.delete(header);
725
+ if (targetRequestHeaders) {
726
+ const sourceHeaderNames = Array.from(sourceMiddlewareRequest.headers.keys());
727
+ for (const header of sourceHeaderNames) sourceMiddlewareRequest.headers.delete(header);
728
+ for (const [name, value] of targetRequestHeaders) sourceMiddlewareRequest.headers.append(name, value);
729
+ }
730
+ const sourceMiddlewareContext = {
731
+ headers: null,
732
+ requestHeaders: null,
733
+ status: null
734
+ };
735
+ const sourceHeadersContext = headersContextFromRequest(sourceMiddlewareRequest, { draftModeSecret: options.draftModeSecret });
736
+ let sourceMiddlewareResult;
737
+ try {
738
+ sourceMiddlewareResult = await runWithHeadersContext(sourceHeadersContext, () => runMiddleware({
739
+ cleanPathname: decodedSourceRequestPathname,
740
+ context: sourceMiddlewareContext,
741
+ externalRewriteRequest: normalizedUserlandRequest,
742
+ hadBasePath,
743
+ isDataRequest: isMiddlewareDataRequest,
744
+ request: sourceMiddlewareRequest,
745
+ validateExternalRewriteRequest: () => validateClaimedOutsideBasePathRsc(true)
746
+ }));
747
+ } finally {
748
+ if (sourceMiddlewareRequest.body && !sourceMiddlewareRequest.bodyUsed && !sourceMiddlewareRequest.body.locked) sourceMiddlewareRequest.body.cancel().catch(() => {});
749
+ if (sourceRequest !== userlandRequest && sourceRequest.body && !sourceRequest.bodyUsed && !sourceRequest.body.locked) sourceRequest.body.cancel().catch(() => {});
750
+ }
751
+ if (!dispatchResponseStage && sourceMiddlewareResult.pathnameEligible) markRouteCacheabilityDynamic(sourceMiddlewareResult.matched ? "middleware matched this request" : "middleware is eligible for this pathname");
752
+ if (sourceMiddlewareResult.kind === "response") {
753
+ options.clearRequestContext();
754
+ return sourceMiddlewareResult.response;
755
+ }
756
+ let sourceHeadersCompatible = true;
757
+ if (targetRequestHeaders) {
758
+ for (const [name, value] of targetRequestHeaders) if (sourceHeadersContext.headers.get(name) !== value) {
759
+ sourceHeadersCompatible = false;
760
+ break;
761
+ }
762
+ }
763
+ if (!targetHeadersContext || !targetRequestHeaders || !sourceHeadersCompatible || !haveSameRequestCookies(targetHeadersContext.cookies, sourceHeadersContext.cookies)) {
764
+ options.clearRequestContext();
765
+ return notFoundResponse();
766
+ }
767
+ let addedSourceHeader = false;
768
+ for (const [name, value] of sourceHeadersContext.headers) if (!targetRequestHeaders.has(name)) {
769
+ targetHeadersContext.headers.set(name, value);
770
+ addedSourceHeader = true;
771
+ }
772
+ if (addedSourceHeader) {
773
+ targetHeadersContext.readonlyHeaders = void 0;
774
+ canUseSharedWorkerResponseStage = false;
775
+ }
776
+ if (sourceMiddlewareResult.rewritten) {
777
+ if (sourceMiddlewareResult.search !== sourceUrl.search || !adoptRewrittenInterceptionSource(sourceMiddlewareResult.cleanPathname)) {
778
+ options.clearRequestContext();
779
+ return notFoundResponse();
780
+ }
781
+ sourceRulesPathname = sourceMiddlewareResult.cleanPathname;
782
+ }
698
783
  }
699
- if (sourceMiddlewareResult.rewritten) {
700
- const rewrittenSourceMatch = options.matchRoute(sourceMiddlewareResult.cleanPathname);
701
- if (sourceMiddlewareResult.search !== sourceUrl.search || rewrittenSourceMatch?.route !== interceptionSourceMatch.route || !haveSamePageParams(rewrittenSourceMatch.params, interceptionSourceMatch.params)) {
784
+ if (HAS_CONFIG_REWRITES && options.configRewrites.beforeFiles.length) {
785
+ const { matchRewrite } = await import("../config/config-matchers.js");
786
+ const sourceRewriteContext = requestContextForResolvedUrl(buildPostMwRequestContext(userlandRequest), resolvedUrl, url);
787
+ let didRewriteSource = false;
788
+ for (const rewrite of options.configRewrites.beforeFiles) {
789
+ const destination = matchRewrite(matchPathname(sourceRulesPathname), [rewrite], sourceRewriteContext, basePathState, matchPathname(sourceRulesPathname), dispatchResponseStage === void 0 ? markConditionalRewriteCacheability : void 0);
790
+ if (!destination) continue;
791
+ if (isExternalUrl(destination) || destination.includes("?")) {
792
+ options.clearRequestContext();
793
+ return notFoundResponse();
794
+ }
795
+ sourceRulesPathname = pathnameForResolvedUrl(destination);
796
+ didRewriteSource = true;
797
+ }
798
+ if (didRewriteSource && !adoptRewrittenInterceptionSource(sourceRulesPathname)) {
702
799
  options.clearRequestContext();
703
800
  return notFoundResponse();
704
801
  }
705
802
  }
706
803
  }
804
+ if (interceptionSourceMatch !== null) {
805
+ hasVerifiedInterceptionSource = provesConcreteInterceptionSource(interceptionSourceMatch, interceptionSourceContext);
806
+ if (!hasVerifiedInterceptionSource) {
807
+ if (interceptionIdHeader !== null) {
808
+ options.clearRequestContext();
809
+ setInterceptionResponseUncacheable(true);
810
+ return badRequestResponse();
811
+ }
812
+ interceptionSourceMatch = null;
813
+ interceptionSourceContext = null;
814
+ }
815
+ bypassInterceptionContextCache = hasRawInterceptionContext && !hasVerifiedInterceptionSource;
816
+ setInterceptionResponseUncacheable(bypassInterceptionContextCache);
817
+ }
707
818
  const interceptionPreActionMatch = filesystemRouteEligible && directPreActionMatch === null && isRscRequest && interceptionSourcePathname !== null ? interceptionSourceMatch : null;
708
819
  const preActionMatch = directPreActionMatch ?? interceptionPreActionMatch;
709
820
  const isInterceptionMatch = interceptionPreActionMatch !== null;
710
- if (preActionMatch) setRootParams(pickRootParams(preActionMatch.params, preActionMatch.route.rootParamNames));
821
+ const rendersRawRequestMatch = options.matchRawRequestRoute !== void 0 && (isPossibleAppRouteActionRequest(request) || isDraftModeRequest(request, options.draftModeSecret) || isDraftModeEnabled());
822
+ const usesRawRequestMatch = () => rendersRawRequestMatch && cleanPathnameIsRequestPathname && !isInterceptionMatch;
823
+ const renderedRouteMatch = (routeMatch) => routeMatch !== null && usesRawRequestMatch() ? options.matchRawRequestRoute(requestCleanPathname) ?? routeMatch : routeMatch;
824
+ const renderedPreActionMatch = renderedRouteMatch(preActionMatch);
825
+ if (renderedPreActionMatch) setRootParams(pickRootParams(renderedPreActionMatch.params, renderedPreActionMatch.route.rootParamNames));
711
826
  if (pagesDataRequest && didMiddlewareRewritePathname && preActionMatch && !preActionMatch.route.isDynamic) {
712
827
  const headers = new Headers();
713
828
  mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);
@@ -728,7 +843,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
728
843
  contentType,
729
844
  middlewareContext,
730
845
  request,
731
- routeMatch: preActionMatch
846
+ routeMatch: renderedPreActionMatch
732
847
  });
733
848
  else if (preActionMatch?.route.__loadPage && !preActionMatch.route.__loadRouteHandler) return createMissingServerActionResponse(options, null);
734
849
  }
@@ -760,13 +875,13 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
760
875
  actionId,
761
876
  cleanPathname,
762
877
  contentType,
763
- interceptionContext: interceptionContextHeader,
878
+ interceptionContext: interceptionSourceContext,
764
879
  isRscRequest,
765
880
  middlewareContext,
766
881
  mountedSlotsHeader,
767
882
  request,
768
883
  scriptNonce,
769
- routeMatch: preActionMatch,
884
+ routeMatch: renderedPreActionMatch,
770
885
  routePathname: preActionRoutePathname,
771
886
  dispatchRedirectTargetRequest: dispatchInternalRequest,
772
887
  sourceConfigHeaders,
@@ -802,7 +917,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
802
917
  matchKind,
803
918
  middlewareCookieOverlay,
804
919
  preHandlerHeaders: cache === "shared" && resourceKind === "page" && dataKind === "static" ? null : [...await loadPreHandlerResponseHeaders()],
805
- protocolVersion: 10,
920
+ protocolVersion: 11,
806
921
  requestOrigin: url.origin,
807
922
  resourceKind,
808
923
  requestUrl: request.url,
@@ -837,15 +952,18 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
837
952
  if (response) preserveRouteCacheabilityResponsePolicy();
838
953
  if (!response) return null;
839
954
  if (sharedOuterPolicyNeedsReconciliation) reconcileCdnResponseHeadersAfterOuterPolicy(response.headers, await loadOuterResponsePolicy());
840
- if (!pagesDataRequest || resolvedUrl === originalResolvedUrl) return dispatchPagesResponseStage ? markAppRscResponseConfigHeadersApplied(response) : response;
955
+ const isRewritten = resolvedUrl !== originalResolvedUrl;
956
+ const isPrerender = typeof process !== "undefined" && process.env?.VINEXT_PRERENDER === "1";
957
+ if ((!pagesDataRequest || !isRewritten) && !isPrerender) return dispatchPagesResponseStage ? markAppRscResponseConfigHeadersApplied(response) : response;
841
958
  const headers = new Headers(response.headers);
842
- headers.set("x-nextjs-rewrite", resolvedUrl);
843
- const rewrittenResponse = new Response(response.body, {
959
+ if (pagesDataRequest && isRewritten) headers.set("x-nextjs-rewrite", resolvedUrl);
960
+ if (isPrerender) headers.set(VINEXT_PRERENDER_REWRITTEN_HEADER, isRewritten ? "1" : "0");
961
+ const markedResponse = new Response(response.body, {
844
962
  headers,
845
963
  status: response.status,
846
964
  statusText: response.statusText
847
965
  });
848
- return dispatchPagesResponseStage ? markAppRscResponseConfigHeadersApplied(rewrittenResponse) : rewrittenResponse;
966
+ return dispatchPagesResponseStage ? markAppRscResponseConfigHeadersApplied(markedResponse) : markedResponse;
849
967
  };
850
968
  const staticPagesFallbackResponse = await renderPagesForMatchKind("static");
851
969
  if (staticPagesFallbackResponse) {
@@ -931,23 +1049,31 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
931
1049
  }
932
1050
  if (match) break;
933
1051
  }
934
- if (interceptionCacheProofInvalidated && interceptionContextHeader !== null) {
1052
+ if (interceptionCacheProofInvalidated && interceptionSourceContext !== null) {
935
1053
  const finalInterceptionTargetPathname = cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname;
936
- const finalInterceptionSourceMatch = filesystemRouteEligible && match !== null ? options.matchInterceptRoute?.(finalInterceptionTargetPathname, interceptionContextHeader, interceptionIdHeader) ?? null : null;
1054
+ const finalInterceptionSourceMatch = filesystemRouteEligible && match !== null ? options.matchInterceptRoute?.(finalInterceptionTargetPathname, interceptionSourceContext, interceptionIdHeader) ?? null : null;
937
1055
  const hasVerifiedFinalInterceptionSource = hasVerifiedInterceptionSource && interceptionSourceMatch !== null && provesConcreteInterceptionSource(finalInterceptionSourceMatch) && finalInterceptionSourceMatch?.route === interceptionSourceMatch.route && haveSamePageParams(finalInterceptionSourceMatch.params, interceptionSourceMatch.params);
938
1056
  if (interceptionIdHeader !== null && !hasVerifiedFinalInterceptionSource) {
939
1057
  options.clearRequestContext();
940
1058
  setInterceptionResponseUncacheable(true);
941
1059
  return badRequestResponse();
942
1060
  }
1061
+ if (!hasVerifiedFinalInterceptionSource) interceptionSourceContext = null;
943
1062
  bypassInterceptionContextCache = !hasVerifiedFinalInterceptionSource;
944
1063
  setInterceptionResponseUncacheable(bypassInterceptionContextCache);
945
1064
  }
1065
+ if ((!filesystemRouteEligible || !match) && isNextStaticPath(cleanPathname, "", assetPrefixPathname(options.assetPrefix ?? ""))) {
1066
+ options.clearRequestContext();
1067
+ const headers = new Headers();
1068
+ mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);
1069
+ applyCdnResponseHeaders(headers, { cacheControl: NEVER_CACHE_CONTROL });
1070
+ return notFoundStaticAssetResponse(headers);
1071
+ }
946
1072
  if (!filesystemRouteEligible) {
947
1073
  options.clearRequestContext();
948
1074
  const headers = new Headers();
949
1075
  mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);
950
- return notFoundResponse({ headers });
1076
+ return withUnmatchedRouteCacheControl(notFoundResponse({ headers }));
951
1077
  }
952
1078
  if (pagesDataRequest) {
953
1079
  options.clearRequestContext();
@@ -971,7 +1097,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
971
1097
  }
972
1098
  setFrameworkRequestRoute("/404", isRscRequest);
973
1099
  const notFoundResponseStage = transportedResponseStage ?? options.renderResponseStageLocally;
974
- if (notFoundResponseStage) return composeResponseStageResponse(await notFoundResponseStage(responseStageRequest(), {
1100
+ if (notFoundResponseStage) return withUnmatchedRouteCacheControl(await composeResponseStageResponse(await notFoundResponseStage(responseStageRequest(), {
975
1101
  kind: "app-not-found",
976
1102
  buildId: options.buildId,
977
1103
  cacheability: responseStageCacheability(resolvedUrl),
@@ -981,12 +1107,12 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
981
1107
  isRscRequest,
982
1108
  middlewareCookieOverlay,
983
1109
  mountedSlotsHeader,
984
- protocolVersion: 10,
1110
+ protocolVersion: 11,
985
1111
  requestOrigin: url.origin,
986
1112
  renderMode,
987
1113
  resolvedUrl,
988
1114
  scriptNonce: scriptNonce ?? null
989
- }));
1115
+ })));
990
1116
  const renderedNotFoundResponse = await traceAppPageRender("/404", "render", () => options.renderNotFound({
991
1117
  isRscRequest,
992
1118
  middlewareContext,
@@ -994,12 +1120,13 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
994
1120
  route: null,
995
1121
  scriptNonce
996
1122
  }));
997
- if (renderedNotFoundResponse) return renderedNotFoundResponse;
1123
+ if (renderedNotFoundResponse) return withUnmatchedRouteCacheControl(renderedNotFoundResponse);
998
1124
  options.clearRequestContext();
999
1125
  const headers = new Headers();
1000
1126
  mergeMiddlewareResponseHeaders(headers, middlewareContext.headers);
1001
- return notFoundResponse({ headers });
1127
+ return withUnmatchedRouteCacheControl(notFoundResponse({ headers }));
1002
1128
  }
1129
+ match = renderedRouteMatch(match);
1003
1130
  const { route, params } = match;
1004
1131
  const requestPathnameDiffersFromCachePath = requestCleanPathname !== cleanPathname;
1005
1132
  const rawRequestPathnameIsObservable = isInterceptionMatch || route.routeHandler != null || typeof route.__loadRouteHandler === "function";
@@ -1027,7 +1154,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1027
1154
  const prerenderRouteParams = prerenderRouteParamsMatch?.params ?? null;
1028
1155
  const isPrerenderFallbackShell = prerenderRouteParamsMatch?.kind === "fallback-shell";
1029
1156
  const renderParams = prerenderRouteParams ?? params;
1030
- const responseStageMatchKind = isInterceptionMatch ? "interception" : cleanPathnameIsRequestPathname && options.matchRequestRoute ? "request" : "resolved";
1157
+ const responseStageMatchKind = isInterceptionMatch ? "interception" : cleanPathnameIsRequestPathname && options.matchRequestRoute ? usesRawRequestMatch() ? "raw-request" : "request" : "resolved";
1031
1158
  const responseStageRoutePathname = isInterceptionMatch ? preActionRoutePathname : cleanPathnameIsRequestPathname ? requestCleanPathname || "/" : cleanPathname || "/";
1032
1159
  const matchedResponseStage = transportedResponseStage ?? options.renderResponseStageLocally;
1033
1160
  let runtimeFallbackShells = [];
@@ -1067,7 +1194,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1067
1194
  middlewareCookieOverlay,
1068
1195
  mountedSlotsHeader,
1069
1196
  params,
1070
- protocolVersion: 10,
1197
+ protocolVersion: 11,
1071
1198
  requestOrigin: url.origin,
1072
1199
  renderMode,
1073
1200
  resolvedUrl,
@@ -1088,7 +1215,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1088
1215
  searchParams: resolvedSearchParams
1089
1216
  });
1090
1217
  }
1091
- const pageResponse = matchedResponseStage ? await matchedResponseStage(responseStageRequest(), {
1218
+ const pageResponse = withStoredSpecialErrorStatus(matchedResponseStage ? await matchedResponseStage(responseStageRequest(), {
1092
1219
  kind: "app-page",
1093
1220
  buildId: options.buildId,
1094
1221
  cacheability: responseStageCacheability(resolvedUrl),
@@ -1099,14 +1226,14 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1099
1226
  cleanPathname,
1100
1227
  draftModeCookie,
1101
1228
  forceDynamic: route.forceDynamic === true,
1102
- interceptionContext: isRscRequest ? interceptionContextHeader : null,
1229
+ interceptionContext: isRscRequest ? interceptionSourceContext : null,
1103
1230
  interceptionId: interceptionIdHeader,
1104
1231
  isRscRequest,
1105
1232
  matchKind: responseStageMatchKind,
1106
1233
  middlewareCookieOverlay,
1107
1234
  mountedSlotsHeader,
1108
1235
  params,
1109
- protocolVersion: 10,
1236
+ protocolVersion: 11,
1110
1237
  requestOrigin: url.origin,
1111
1238
  renderMode,
1112
1239
  resolvedUrl,
@@ -1123,7 +1250,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1123
1250
  actionError: normalizedProgressiveActionError,
1124
1251
  actionFailed,
1125
1252
  handlerStart,
1126
- interceptionContext: isRscRequest ? interceptionContextHeader : null,
1253
+ interceptionContext: isRscRequest ? interceptionSourceContext : null,
1127
1254
  interceptionId: interceptionIdHeader,
1128
1255
  interceptionPathname: cleanPathnameIsRequestPathname ? requestCleanPathname : cleanPathname,
1129
1256
  isProgressiveActionRender,
@@ -1146,7 +1273,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
1146
1273
  scriptNonce,
1147
1274
  searchParams: resolvedSearchParams,
1148
1275
  renderMode
1149
- });
1276
+ }), isRscRequest && request.headers.get("Next-Router-Prefetch") === "1" && request.headers.has("Next-Router-Segment-Prefetch"));
1150
1277
  if (isProgressiveActionRender) return applyProgressiveActionSideEffects(pageResponse, progressiveActionFormState);
1151
1278
  return pageResponse;
1152
1279
  }
@@ -1250,7 +1377,7 @@ function createAppRscRequestHandler(options) {
1250
1377
  recordCacheability: dispatchResponseStage === void 0,
1251
1378
  requestContext: preMiddlewareRequestContext
1252
1379
  });
1253
- return interceptionResponseUncacheable ? markUnverifiedInterceptionResponseUncacheable(response) : response;
1380
+ return interceptionResponseUncacheable || unmatchedRouteResponses.has(response) ? withNeverCacheControl(response) : response;
1254
1381
  }, {
1255
1382
  cacheComponents: options.createPprFallbackShells !== void 0,
1256
1383
  route: () => new URL(request.url).pathname
@@ -35,7 +35,9 @@ export type NormalizedRscRequest = {
35
35
  *
36
36
  * 1. Parse URL
37
37
  * 2. Protocol-relative URL guard — on the raw pathname, BEFORE normalizePath collapses
38
- * `//` to `/`. If the guard ran after normalization, `//evil.com` → `/evil.com`
38
+ * `//` to `/`. Literal repeated slashes / backslashes get Next.js's 308 to the
39
+ * collapsed path; encoded leading `%2F` / `%5C` get a 404. If the guard ran after
40
+ * normalization, `//evil.com` → `/evil.com`
39
41
  * would bypass the check and reach the trailing-slash redirector, which echoes the
40
42
  * path into a `Location` header that browsers interpret as protocol-relative.
41
43
  * 3. Strict percent-decode each segment — throws on malformed sequences (→ 400). Must
@@ -55,6 +57,6 @@ export type NormalizedRscRequest = {
55
57
  * @returns A 400 or 404 Response for invalid or out-of-scope inputs,
56
58
  * or a NormalizedRscRequest for valid requests.
57
59
  */
58
- export declare function normalizeRscRequest(request: Request, basePath: string, allowOutsideBasePath?: boolean): Response | NormalizedRscRequest;
60
+ export declare function normalizeRscRequest(request: Request, basePath: string, allowOutsideBasePath?: boolean, assetPrefix?: string): Response | NormalizedRscRequest;
59
61
  //#endregion
60
62
  export { normalizeMountedSlotsHeader };
@@ -1,3 +1,4 @@
1
+ import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
1
2
  import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
2
3
  import { hasBasePath, stripBasePath } from "../utils/base-path.js";
3
4
  import { NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_INTERCEPTION_ID_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_RENDER_MODE_HEADER } from "./app-rsc-vary.js";
@@ -68,7 +69,9 @@ function tryNormalizeComparablePathAndSearch(value, basePath, baseUrl) {
68
69
  *
69
70
  * 1. Parse URL
70
71
  * 2. Protocol-relative URL guard — on the raw pathname, BEFORE normalizePath collapses
71
- * `//` to `/`. If the guard ran after normalization, `//evil.com` → `/evil.com`
72
+ * `//` to `/`. Literal repeated slashes / backslashes get Next.js's 308 to the
73
+ * collapsed path; encoded leading `%2F` / `%5C` get a 404. If the guard ran after
74
+ * normalization, `//evil.com` → `/evil.com`
72
75
  * would bypass the check and reach the trailing-slash redirector, which echoes the
73
76
  * path into a `Location` header that browsers interpret as protocol-relative.
74
77
  * 3. Strict percent-decode each segment — throws on malformed sequences (→ 400). Must
@@ -88,9 +91,9 @@ function tryNormalizeComparablePathAndSearch(value, basePath, baseUrl) {
88
91
  * @returns A 400 or 404 Response for invalid or out-of-scope inputs,
89
92
  * or a NormalizedRscRequest for valid requests.
90
93
  */
91
- function normalizeRscRequest(request, basePath, allowOutsideBasePath = false) {
94
+ function normalizeRscRequest(request, basePath, allowOutsideBasePath = false, assetPrefix = "") {
92
95
  const url = new URL(request.url);
93
- const protoGuard = guardProtocolRelativeUrl(url.pathname);
96
+ const protoGuard = guardProtocolRelativeUrl(url.pathname, url.search);
94
97
  if (protoGuard) return protoGuard;
95
98
  let decoded;
96
99
  try {
@@ -103,7 +106,7 @@ function normalizeRscRequest(request, basePath, allowOutsideBasePath = false) {
103
106
  let hadBasePath = true;
104
107
  if (basePath) {
105
108
  hadBasePath = hasBasePath(requestPathname, basePath);
106
- if (!hadBasePath && !pathname.startsWith("/__vinext/") && !allowOutsideBasePath) return notFoundResponse();
109
+ if (!hadBasePath && !pathname.startsWith("/__vinext/") && !allowOutsideBasePath && !isNextStaticPath(pathname, "", assetPrefixPathname(assetPrefix))) return notFoundResponse();
107
110
  if (hadBasePath) {
108
111
  pathname = stripBasePath(pathname, basePath);
109
112
  requestPathname = stripBasePath(requestPathname, basePath);
@@ -15,7 +15,10 @@ const configHeadersAlreadyApplied = /* @__PURE__ */ new WeakSet();
15
15
  function normalizeExplicitNonCacheablePolicy(headers) {
16
16
  if (!hasExplicitNonCacheableResponsePolicy(headers)) return;
17
17
  const cacheControl = headers.get("Cache-Control");
18
- applyCdnResponseHeaders(headers, { cacheControl: cacheControl && isNonCacheableCacheControl(cacheControl) ? cacheControl : NO_STORE_CACHE_CONTROL });
18
+ applyCdnResponseHeaders(headers, {
19
+ cacheControl: cacheControl && isNonCacheableCacheControl(cacheControl) ? cacheControl : NO_STORE_CACHE_CONTROL,
20
+ browserCacheControl: cacheControl ?? void 0
21
+ });
19
22
  }
20
23
  /** Mark a response whose final target pipeline has already applied config headers. */
21
24
  function markAppRscResponseConfigHeadersApplied(response) {