vinext 1.2.0 → 1.3.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 (283) hide show
  1. package/README.md +13 -10
  2. package/dist/build/client-build-config.d.ts +64 -3
  3. package/dist/build/client-build-config.js +131 -4
  4. package/dist/build/client-reference-groups.d.ts +163 -0
  5. package/dist/build/client-reference-groups.js +534 -0
  6. package/dist/build/module-dependency-cache.d.ts +31 -0
  7. package/dist/build/module-dependency-cache.js +51 -1
  8. package/dist/build/next-client-runtime-manifests.d.ts +10 -1
  9. package/dist/build/next-client-runtime-manifests.js +19 -4
  10. package/dist/build/nitro-public-files.d.ts +24 -0
  11. package/dist/build/nitro-public-files.js +60 -0
  12. package/dist/build/output-root-externals.d.ts +21 -0
  13. package/dist/build/output-root-externals.js +40 -0
  14. package/dist/build/pages-client-assets-module.js +1 -1
  15. package/dist/build/prerender-paths.js +6 -3
  16. package/dist/build/prerender.js +1 -1
  17. package/dist/build/server-actions-encryption-key.d.ts +23 -0
  18. package/dist/build/server-actions-encryption-key.js +101 -0
  19. package/dist/build/ssr-manifest.d.ts +3 -0
  20. package/dist/build/ssr-manifest.js +10 -1
  21. package/dist/check.js +5 -6
  22. package/dist/cli-dev-config.js +3 -3
  23. package/dist/cli.js +1 -1
  24. package/dist/client/client-rewrite-params.d.ts +9 -0
  25. package/dist/client/client-rewrite-params.js +20 -0
  26. package/dist/client/dev-error-overlay.js +2 -1
  27. package/dist/client/navigation-runtime.d.ts +25 -2
  28. package/dist/client/navigation-runtime.js +42 -11
  29. package/dist/client/vinext-next-data.d.ts +0 -1
  30. package/dist/config/config-matchers.d.ts +15 -40
  31. package/dist/config/config-matchers.js +195 -262
  32. package/dist/config/config-source.d.ts +34 -0
  33. package/dist/config/config-source.js +141 -0
  34. package/dist/config/header-params.d.ts +29 -0
  35. package/dist/config/header-params.js +106 -0
  36. package/dist/config/next-config.d.ts +7 -5
  37. package/dist/config/next-config.js +120 -7
  38. package/dist/entries/app-browser-entry.d.ts +14 -1
  39. package/dist/entries/app-browser-entry.js +26 -36
  40. package/dist/entries/app-rsc-entry.d.ts +2 -0
  41. package/dist/entries/app-rsc-entry.js +92 -57
  42. package/dist/entries/app-rsc-manifest.d.ts +10 -0
  43. package/dist/entries/app-rsc-manifest.js +20 -1
  44. package/dist/entries/app-ssr-entry.d.ts +4 -1
  45. package/dist/entries/app-ssr-entry.js +9 -2
  46. package/dist/entries/pages-client-entry.d.ts +1 -0
  47. package/dist/entries/pages-client-entry.js +6 -6
  48. package/dist/entries/pages-server-entry.js +17 -14
  49. package/dist/index.d.ts +11 -0
  50. package/dist/index.js +350 -175
  51. package/dist/init.d.ts +1 -1
  52. package/dist/init.js +103 -6
  53. package/dist/plugins/ast-utils.d.ts +53 -2
  54. package/dist/plugins/ast-utils.js +90 -2
  55. package/dist/plugins/cloudflare-dev-module-urls.d.ts +41 -0
  56. package/dist/plugins/cloudflare-dev-module-urls.js +271 -0
  57. package/dist/plugins/commonjs-esm-facade.js +2 -2
  58. package/dist/plugins/css-module-imports.js +13 -20
  59. package/dist/plugins/dynamic-preload-metadata.js +2 -3
  60. package/dist/plugins/extensionless-dynamic-import.js +2 -3
  61. package/dist/plugins/fonts.d.ts +1 -1
  62. package/dist/plugins/fonts.js +3 -3
  63. package/dist/plugins/ignore-dynamic-requests.js +2 -3
  64. package/dist/plugins/import-meta-url.js +3 -4
  65. package/dist/plugins/instrumentation-client.js +3 -2
  66. package/dist/plugins/middleware-export-validation.js +2 -3
  67. package/dist/plugins/og-harfbuzz.js +2 -3
  68. package/dist/plugins/optimize-imports.d.ts +25 -2
  69. package/dist/plugins/optimize-imports.js +109 -24
  70. package/dist/plugins/pages-node-externals.js +2 -3
  71. package/dist/plugins/remove-console.js +2 -18
  72. package/dist/plugins/require-condition-resolution.js +3 -3
  73. package/dist/plugins/require-context.js +2 -3
  74. package/dist/plugins/rsc-client-reference-loaders.d.ts +45 -1
  75. package/dist/plugins/rsc-client-reference-loaders.js +336 -18
  76. package/dist/plugins/strip-server-exports.js +3 -4
  77. package/dist/plugins/styled-jsx.js +2 -3
  78. package/dist/plugins/use-cache-callable.d.ts +26 -2
  79. package/dist/plugins/use-cache-callable.js +101 -36
  80. package/dist/plugins/worker-image-imports.d.ts +1 -0
  81. package/dist/plugins/worker-image-imports.js +31 -34
  82. package/dist/plugins/worker-use-server.js +38 -14
  83. package/dist/routing/app-route-graph.d.ts +1 -1
  84. package/dist/routing/browser-route-manifest.d.ts +43 -0
  85. package/dist/routing/browser-route-manifest.js +195 -0
  86. package/dist/routing/hashed-route-patterns.d.ts +4 -0
  87. package/dist/routing/hashed-route-patterns.js +22 -0
  88. package/dist/routing/optimistic-route-trie.d.ts +27 -0
  89. package/dist/routing/optimistic-route-trie.js +102 -0
  90. package/dist/routing/route-validation.d.ts +6 -1
  91. package/dist/routing/route-validation.js +26 -10
  92. package/dist/server/api-handler.js +1 -1
  93. package/dist/server/app-action-forwarding.d.ts +8 -0
  94. package/dist/server/app-action-forwarding.js +17 -3
  95. package/dist/server/app-browser-entry.js +149 -62
  96. package/dist/server/app-browser-error.d.ts +3 -1
  97. package/dist/server/app-browser-error.js +7 -2
  98. package/dist/server/app-browser-interception-context.d.ts +2 -2
  99. package/dist/server/app-browser-interception-context.js +1 -1
  100. package/dist/server/app-browser-mpa-navigation.d.ts +1 -0
  101. package/dist/server/app-browser-mpa-navigation.js +6 -5
  102. package/dist/server/app-browser-navigation-controller.d.ts +17 -6
  103. package/dist/server/app-browser-navigation-controller.js +88 -26
  104. package/dist/server/app-browser-prefetch-response.js +2 -2
  105. package/dist/server/app-browser-state.d.ts +2 -2
  106. package/dist/server/app-browser-state.js +1 -1
  107. package/dist/server/app-browser-supplemental-refresh.js +1 -1
  108. package/dist/server/app-browser-visible-commit.d.ts +4 -4
  109. package/dist/server/app-client-reference-preloader.d.ts +23 -0
  110. package/dist/server/app-client-reference-preloader.js +30 -7
  111. package/dist/server/app-fallback-renderer.js +2 -1
  112. package/dist/server/app-middleware.d.ts +6 -0
  113. package/dist/server/app-middleware.js +8 -10
  114. package/dist/server/app-optimistic-routing.d.ts +8 -10
  115. package/dist/server/app-optimistic-routing.js +4 -95
  116. package/dist/server/app-page-boundary-render.js +8 -1
  117. package/dist/server/app-page-cache-render.js +1 -0
  118. package/dist/server/app-page-dispatch.js +3 -1
  119. package/dist/server/app-page-render.js +4 -2
  120. package/dist/server/app-page-rsc-render-status.d.ts +1 -0
  121. package/dist/server/app-page-rsc-render-status.js +1 -0
  122. package/dist/server/app-page-search-params-observation.d.ts +1 -4
  123. package/dist/server/app-page-search-params-observation.js +8 -10
  124. package/dist/server/app-page-stream.d.ts +7 -0
  125. package/dist/server/app-page-stream.js +1 -0
  126. package/dist/server/app-pages-bridge.d.ts +2 -1
  127. package/dist/server/app-pages-bridge.js +12 -8
  128. package/dist/server/app-prerender-endpoints.js +1 -1
  129. package/dist/server/app-prerender-static-params.js +3 -2
  130. package/dist/server/app-render-abort-error.d.ts +19 -0
  131. package/dist/server/app-render-abort-error.js +31 -1
  132. package/dist/server/app-render-dependency.js +42 -2
  133. package/dist/server/app-request-stage-independent-entry.js +7 -7
  134. package/dist/server/app-response-stage-entry.js +5 -5
  135. package/dist/server/app-route-handler-dispatch.js +3 -1
  136. package/dist/server/app-route-handler-execution.d.ts +2 -0
  137. package/dist/server/app-route-handler-execution.js +9 -2
  138. package/dist/server/app-route-handler-middleware-context.d.ts +2 -1
  139. package/dist/server/app-route-handler-middleware-context.js +3 -3
  140. package/dist/server/app-route-handler-response.d.ts +2 -1
  141. package/dist/server/app-route-handler-response.js +2 -2
  142. package/dist/server/app-route-handler-runtime.d.ts +2 -0
  143. package/dist/server/app-route-handler-runtime.js +21 -4
  144. package/dist/server/app-route-module-loader.js +7 -6
  145. package/dist/server/app-route-tree.d.ts +20 -0
  146. package/dist/server/app-route-tree.js +18 -0
  147. package/dist/server/app-router-entry.js +7 -7
  148. package/dist/server/app-rsc-cache-busting.d.ts +16 -0
  149. package/dist/server/app-rsc-cache-busting.js +29 -12
  150. package/dist/server/app-rsc-combined-handler.js +8 -1
  151. package/dist/server/app-rsc-errors.d.ts +7 -0
  152. package/dist/server/app-rsc-errors.js +9 -2
  153. package/dist/server/app-rsc-handler.d.ts +4 -1
  154. package/dist/server/app-rsc-handler.js +151 -135
  155. package/dist/server/app-rsc-request-normalization.js +3 -3
  156. package/dist/server/app-rsc-response-finalizer.d.ts +5 -0
  157. package/dist/server/app-rsc-response-finalizer.js +4 -1
  158. package/dist/server/app-rsc-response-stage.js +5 -3
  159. package/dist/server/app-rsc-route-matching.d.ts +1 -0
  160. package/dist/server/app-rsc-route-matching.js +1 -1
  161. package/dist/server/app-server-action-execution.d.ts +23 -6
  162. package/dist/server/app-server-action-execution.js +51 -57
  163. package/dist/server/app-ssr-entry.d.ts +6 -0
  164. package/dist/server/app-ssr-entry.js +21 -11
  165. package/dist/server/app-ssr-stream.d.ts +7 -0
  166. package/dist/server/app-ssr-stream.js +13 -1
  167. package/dist/server/app-visited-response-cache.js +2 -2
  168. package/dist/server/config-headers.js +13 -4
  169. package/dist/server/defer-until-stream-consumed.d.ts +2 -1
  170. package/dist/server/defer-until-stream-consumed.js +3 -1
  171. package/dist/server/dev-server.js +1 -1
  172. package/dist/server/image-optimization.js +1 -0
  173. package/dist/server/isolate-shared-promise.d.ts +10 -0
  174. package/dist/server/isolate-shared-promise.js +33 -0
  175. package/dist/server/isr-cache.js +3 -2
  176. package/dist/server/metadata-route-response.js +2 -2
  177. package/dist/server/middleware-matcher-pattern.d.ts +0 -1
  178. package/dist/server/middleware-matcher-pattern.js +11 -140
  179. package/dist/server/middleware-matcher.js +5 -6
  180. package/dist/server/middleware-response-headers.d.ts +31 -0
  181. package/dist/server/middleware-response-headers.js +57 -1
  182. package/dist/server/middleware-runtime.js +30 -17
  183. package/dist/server/navigation-planner.d.ts +2 -2
  184. package/dist/server/navigation-planner.js +1 -1
  185. package/dist/server/nitro-public-files-plugin.d.ts +38 -0
  186. package/dist/server/nitro-public-files-plugin.js +106 -0
  187. package/dist/server/nitro-public-files.d.ts +21 -0
  188. package/dist/server/nitro-public-files.js +39 -0
  189. package/dist/server/open-redirect.d.ts +11 -4
  190. package/dist/server/open-redirect.js +11 -4
  191. package/dist/server/pages-api-route.js +2 -2
  192. package/dist/server/pages-asset-tags.d.ts +5 -0
  193. package/dist/server/pages-asset-tags.js +9 -2
  194. package/dist/server/pages-client-assets.d.ts +4 -1
  195. package/dist/server/pages-data-route.js +2 -1
  196. package/dist/server/pages-i18n.d.ts +18 -0
  197. package/dist/server/pages-i18n.js +18 -2
  198. package/dist/server/pages-node-compat.d.ts +5 -3
  199. package/dist/server/pages-node-compat.js +35 -16
  200. package/dist/server/pages-page-data.js +1 -1
  201. package/dist/server/pages-page-handler.js +1 -1
  202. package/dist/server/pages-page-response.js +1 -1
  203. package/dist/server/pages-request-pipeline.d.ts +6 -1
  204. package/dist/server/pages-request-pipeline.js +35 -39
  205. package/dist/server/pages-request-stage-entry.js +20 -10
  206. package/dist/server/pages-response-stage-entry.js +1 -1
  207. package/dist/server/pages-revalidate.js +3 -2
  208. package/dist/server/pages-router-entry.js +2 -2
  209. package/dist/server/prod-server.d.ts +2 -2
  210. package/dist/server/prod-server.js +74 -36
  211. package/dist/server/proxy-trust.d.ts +6 -0
  212. package/dist/server/proxy-trust.js +12 -6
  213. package/dist/server/request-pipeline.d.ts +5 -0
  214. package/dist/server/request-pipeline.js +12 -1
  215. package/dist/server/rsc-stream-hints.d.ts +1 -1
  216. package/dist/server/rsc-stream-hints.js +21 -3
  217. package/dist/server/server-reference-loader.js +10 -1
  218. package/dist/server/static-file-cache.js +15 -3
  219. package/dist/server/worker-image-optimization.js +19 -6
  220. package/dist/server/worker-utils.js +1 -1
  221. package/dist/shims/cache-handler.js +3 -2
  222. package/dist/shims/cache-request-state.d.ts +40 -3
  223. package/dist/shims/cache-request-state.js +70 -5
  224. package/dist/shims/cache-runtime.js +47 -19
  225. package/dist/shims/cache.d.ts +2 -2
  226. package/dist/shims/cache.js +17 -8
  227. package/dist/shims/cdn-purge-routes.d.ts +24 -0
  228. package/dist/shims/cdn-purge-routes.js +77 -0
  229. package/dist/shims/dynamic.js +17 -4
  230. package/dist/shims/form.js +8 -3
  231. package/dist/shims/head.js +1 -1
  232. package/dist/shims/headers.js +2 -2
  233. package/dist/shims/image-props.d.ts +93 -0
  234. package/dist/shims/image-props.js +323 -0
  235. package/dist/shims/image.d.ts +4 -18
  236. package/dist/shims/image.js +4 -319
  237. package/dist/shims/internal/headers-state.d.ts +7 -0
  238. package/dist/shims/internal/headers-state.js +14 -2
  239. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +4 -1
  240. package/dist/shims/internal/hybrid-client-route-owner-direct.js +32 -15
  241. package/dist/shims/internal/hybrid-client-route-owner.js +9 -8
  242. package/dist/shims/link-prefetch.js +5 -4
  243. package/dist/shims/link.js +7 -5
  244. package/dist/shims/navigation.d.ts +1 -1
  245. package/dist/shims/navigation.js +21 -10
  246. package/dist/shims/og.js +35 -10
  247. package/dist/shims/request-context.d.ts +13 -0
  248. package/dist/shims/router.js +28 -52
  249. package/dist/shims/server.d.ts +42 -8
  250. package/dist/shims/server.js +99 -15
  251. package/dist/shims/thenable-params.d.ts +6 -1
  252. package/dist/shims/thenable-params.js +11 -2
  253. package/dist/shims/unified-request-context.d.ts +5 -0
  254. package/dist/shims/unified-request-context.js +2 -0
  255. package/dist/shims/url-utils.d.ts +7 -0
  256. package/dist/shims/url-utils.js +12 -3
  257. package/dist/utils/asset-prefix.d.ts +7 -0
  258. package/dist/utils/asset-prefix.js +10 -1
  259. package/dist/utils/client-build-manifest.js +12 -5
  260. package/dist/utils/client-runtime-metadata.d.ts +1 -0
  261. package/dist/utils/client-runtime-metadata.js +15 -2
  262. package/dist/utils/domain-locale.js +1 -1
  263. package/dist/utils/lazy-chunks.d.ts +4 -0
  264. package/dist/utils/manifest-paths.d.ts +14 -0
  265. package/dist/utils/manifest-paths.js +22 -1
  266. package/dist/utils/path-to-regexp.d.ts +21 -0
  267. package/dist/{server/middleware-path-to-regexp.js → utils/path-to-regexp.js} +14 -11
  268. package/dist/utils/plugin-react-version.d.ts +15 -0
  269. package/dist/utils/plugin-react-version.js +64 -0
  270. package/dist/utils/plugin-rsc-version.d.ts +2 -0
  271. package/dist/utils/plugin-rsc-version.js +28 -2
  272. package/dist/utils/public-routes.d.ts +2 -0
  273. package/dist/utils/public-routes.js +18 -7
  274. package/dist/utils/react-version.d.ts +7 -0
  275. package/dist/utils/react-version.js +39 -16
  276. package/package.json +6 -6
  277. package/dist/build/nitro-route-rules.d.ts +0 -47
  278. package/dist/build/nitro-route-rules.js +0 -79
  279. package/dist/plugins/cache-flight-codec.d.ts +0 -19
  280. package/dist/plugins/cache-flight-codec.js +0 -68
  281. package/dist/server/middleware-path-to-regexp.d.ts +0 -13
  282. package/dist/utils/regex-safety.d.ts +0 -17
  283. package/dist/utils/regex-safety.js +0 -789
@@ -11,7 +11,7 @@ export declare function isOpenRedirectShaped(rawPathname: string): boolean;
11
11
  /**
12
12
  * What a request entry answers for a raw path containing a backslash or a
13
13
  * repeated slash: Next.js's 308, or a 404 when the collapsed path would still
14
- * be open-redirect shaped.
14
+ * be open-redirect shaped or the raw target is not origin-form.
15
15
  */
16
16
  export type RepeatedSlashRedirect = {
17
17
  status: 308;
@@ -33,17 +33,24 @@ export type RepeatedSlashRedirect = {
33
33
  * `//evil.com` → `/evil.com`. Percent-encoded `%2F`/`%5C` are not touched and
34
34
  * keep falling through to `isOpenRedirectShaped` (404), as in Next.js.
35
35
  *
36
- * The Location is always same-origin. Absolute-form request targets
37
- * (`GET http://host//x`) are left alone. A collapsed path that still starts
36
+ * The Location is always same-origin. A collapsed path that still starts
38
37
  * with an encoded slash or backslash (`//%2Fevil.com`, `/.//%2Fevil.com`) is
39
38
  * never echoed into a Location or routed: it gets a 404 instead.
40
39
  *
40
+ * A raw Node request target that is not origin-form (`GET http://evil.example/x`,
41
+ * which Node's parser accepts, or `OPTIONS *`) also gets a 404. Next.js never
42
+ * routes these either: it 308s absolute-form targets to their own URL (the
43
+ * `//` after the scheme trips the same check) and 500s `OPTIONS *`. Routing
44
+ * them would let the request line choose the origin of `request.url` that
45
+ * middleware and handlers see, bypassing the Host trust policy. Request-based
46
+ * entries always pass a pathname.
47
+ *
41
48
  * @param rawUrl - The raw request target: pathname plus optional `?query`
42
49
  */
43
50
  export declare function getRepeatedSlashRedirect(rawUrl: string): RepeatedSlashRedirect | null;
44
51
  /**
45
52
  * Build the Response for a raw request path containing a backslash or a
46
- * repeated slash. See `getRepeatedSlashRedirect`.
53
+ * repeated slash, or a non-origin-form target. See `getRepeatedSlashRedirect`.
47
54
  */
48
55
  export declare function repeatedSlashRedirectResponse(rawUrl: string): Response | null;
49
56
  /**
@@ -34,15 +34,22 @@ const REDIRECT_LOCATION_BASE = "http://vinext.invalid";
34
34
  * `//evil.com` → `/evil.com`. Percent-encoded `%2F`/`%5C` are not touched and
35
35
  * keep falling through to `isOpenRedirectShaped` (404), as in Next.js.
36
36
  *
37
- * The Location is always same-origin. Absolute-form request targets
38
- * (`GET http://host//x`) are left alone. A collapsed path that still starts
37
+ * The Location is always same-origin. A collapsed path that still starts
39
38
  * with an encoded slash or backslash (`//%2Fevil.com`, `/.//%2Fevil.com`) is
40
39
  * never echoed into a Location or routed: it gets a 404 instead.
41
40
  *
41
+ * A raw Node request target that is not origin-form (`GET http://evil.example/x`,
42
+ * which Node's parser accepts, or `OPTIONS *`) also gets a 404. Next.js never
43
+ * routes these either: it 308s absolute-form targets to their own URL (the
44
+ * `//` after the scheme trips the same check) and 500s `OPTIONS *`. Routing
45
+ * them would let the request line choose the origin of `request.url` that
46
+ * middleware and handlers see, bypassing the Host trust policy. Request-based
47
+ * entries always pass a pathname.
48
+ *
42
49
  * @param rawUrl - The raw request target: pathname plus optional `?query`
43
50
  */
44
51
  function getRepeatedSlashRedirect(rawUrl) {
45
- if (!rawUrl.startsWith("/")) return null;
52
+ if (!rawUrl.startsWith("/")) return { status: 404 };
46
53
  const urlParts = rawUrl.split("?");
47
54
  const pathname = urlParts[0];
48
55
  if (!REPEATED_SLASH_OR_BACKSLASH_RE.test(pathname)) return null;
@@ -62,7 +69,7 @@ function repeatedSlashRedirectHeaders(location) {
62
69
  }
63
70
  /**
64
71
  * Build the Response for a raw request path containing a backslash or a
65
- * repeated slash. See `getRepeatedSlashRedirect`.
72
+ * repeated slash, or a non-origin-form target. See `getRepeatedSlashRedirect`.
66
73
  */
67
74
  function repeatedSlashRedirectResponse(rawUrl) {
68
75
  const redirect = getRepeatedSlashRedirect(rawUrl);
@@ -1,8 +1,8 @@
1
+ import { internalServerErrorResponse } from "./http-error-responses.js";
2
+ import { cloneRequestWithUrl } from "./request-pipeline.js";
1
3
  import { getRequestExecutionContext, runWithExecutionContext } from "../shims/request-context.js";
2
4
  import "./server-globals.js";
3
5
  import { NextRequest } from "../shims/server.js";
4
- import { internalServerErrorResponse } from "./http-error-responses.js";
5
- import { cloneRequestWithUrl } from "./request-pipeline.js";
6
6
  import { markRouteCacheabilityExplicitResponsePolicy } from "../shims/cacheability-classification.js";
7
7
  import { hasCdnResponsePolicy } from "./cache-control.js";
8
8
  import { mergeRouteParamsIntoQuery, parseQueryString, urlQueryToSearchParams } from "../utils/query.js";
@@ -9,6 +9,11 @@
9
9
  * unit-testable and lives in a normal typed module rather than a codegen
10
10
  * template string.
11
11
  */
12
+ /**
13
+ * Fallback for when no build-time `sharedChunks` list is registered. Prefers
14
+ * the chunk-name based list the build writes into the SSR manifest; the file
15
+ * name scan only matches `[name]-[hash]` names, not hash-only ones.
16
+ */
12
17
  export declare function getSharedChunkFiles(manifest: Record<string, string[]>): string[];
13
18
  /**
14
19
  * Resolve the effective SSR manifest: prefer the caller-supplied object and
@@ -1,6 +1,6 @@
1
1
  import { appendDeploymentIdQuery } from "../utils/deployment-id.js";
2
2
  import { createNonceAttribute } from "./html.js";
3
- import { assetServingUrlFromBaseAnchored } from "../utils/manifest-paths.js";
3
+ import { SSR_MANIFEST_SHARED_CHUNKS_KEY, assetServingUrlFromBaseAnchored } from "../utils/manifest-paths.js";
4
4
  import { getPagesClientAssets } from "./pages-client-assets.js";
5
5
  //#region src/server/pages-asset-tags.ts
6
6
  /**
@@ -55,7 +55,14 @@ function findModuleKey(manifest, moduleId) {
55
55
  }
56
56
  return matchedKey;
57
57
  }
58
+ /**
59
+ * Fallback for when no build-time `sharedChunks` list is registered. Prefers
60
+ * the chunk-name based list the build writes into the SSR manifest; the file
61
+ * name scan only matches `[name]-[hash]` names, not hash-only ones.
62
+ */
58
63
  function getSharedChunkFiles(manifest) {
64
+ const recorded = manifest[SSR_MANIFEST_SHARED_CHUNKS_KEY];
65
+ if (recorded) return recorded;
59
66
  const cached = sharedChunkFiles.get(manifest);
60
67
  if (cached) return cached;
61
68
  const files = /* @__PURE__ */ new Set();
@@ -186,7 +193,7 @@ function collectAssetTags(options) {
186
193
  const files = getManifestFilesForModule(m, id);
187
194
  if (files) for (let fi = 0; fi < files.length; fi++) allFiles.push(files[fi]);
188
195
  }
189
- const sharedFiles = m === runtimeAssets.ssrManifest && runtimeAssets.sharedChunks ? runtimeAssets.sharedChunks : getSharedChunkFiles(m);
196
+ const sharedFiles = runtimeAssets.sharedChunks ?? getSharedChunkFiles(m);
190
197
  for (const file of sharedFiles) allFiles.push(file);
191
198
  } else for (const akey in m) {
192
199
  const avals = m[akey];
@@ -4,7 +4,10 @@ export type PagesClientAssets = {
4
4
  clientEntry?: string;
5
5
  appBootstrapPreinitModules?: string[];
6
6
  ssrManifest?: Record<string, string[]>;
7
- /** Build-time shared file list, valid only for this ssrManifest object. */
7
+ /**
8
+ * Shared Pages chunk files (framework, vinext runtime, client entry) keyed on
9
+ * chunk names from this client build, in the SSR-manifest key-space.
10
+ */
8
11
  sharedChunks?: string[];
9
12
  cssGraph?: Record<string, {
10
13
  imports?: string[];
@@ -1,6 +1,7 @@
1
1
  import { MIDDLEWARE_SKIP_HEADER } from "../utils/protocol-headers.js";
2
2
  import { addBasePathToPathname, hasBasePath, stripBasePath } from "../utils/base-path.js";
3
3
  import { NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
4
+ import { cloneRequestWithUrl } from "./request-pipeline.js";
4
5
  //#region src/server/pages-data-route.ts
5
6
  /**
6
7
  * Helpers for the Pages Router `/_next/data/{buildId}/{...page}.json` endpoint.
@@ -191,7 +192,7 @@ function normalizePagesDataRequest(request, buildId, basePath = "", trailingSlas
191
192
  normalizedUrl.pathname = hadBasePath ? addBasePathToPathname(pagePathname, basePath) : pagePathname;
192
193
  return {
193
194
  isDataReq: true,
194
- request: new Request(normalizedUrl, request),
195
+ request: cloneRequestWithUrl(request, normalizedUrl.href),
195
196
  normalizedPathname: pagePathname,
196
197
  search: reqUrl.search,
197
198
  notFoundResponse: null
@@ -63,12 +63,30 @@ export declare function detectPathnameLocale(pathname: string, locales: readonly
63
63
  * `:locale`. After normalisation the request looks like `/en/to-sv` and
64
64
  * the rule matches with `:locale=en`.
65
65
  *
66
+ * `restoreRootTrailingSlash` makes the root `/en/` rather than `/en`; header
67
+ * callers compute it with `shouldRestoreLocaleRootTrailingSlash`. Redirect
68
+ * and rewrite callers do not pass it yet.
69
+ *
66
70
  * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
67
71
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts
68
72
  */
69
73
  export declare function normalizeDefaultLocalePathname(pathname: string, i18n: NextI18nConfig | null | undefined, options?: {
70
74
  hostname?: string | null;
75
+ restoreRootTrailingSlash?: boolean;
71
76
  }): string;
77
+ /**
78
+ * Whether Next.js re-adds the root's trailing slash after splicing in the
79
+ * default locale: the raw request pathname (basePath included, so `/docs`
80
+ * stays `/docs/en` while `/docs/` becomes `/docs/en/`) ends with `/`, and
81
+ * `trailingSlash` is on without `skipProxyUrlNormalize`.
82
+ *
83
+ * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
84
+ * (`hadTrailingSlash` + `maybeAddTrailingSlash`).
85
+ */
86
+ export declare function shouldRestoreLocaleRootTrailingSlash(rawPathname: string, config: {
87
+ trailingSlash?: boolean;
88
+ skipProxyUrlNormalize?: boolean;
89
+ }): boolean;
72
90
  /**
73
91
  * Extract locale prefix from a URL path.
74
92
  * e.g. /fr/about -> { locale: "fr", url: "/about", hadPrefix: true }
@@ -51,6 +51,10 @@ function detectPathnameLocale(pathname, locales) {
51
51
  * `:locale`. After normalisation the request looks like `/en/to-sv` and
52
52
  * the rule matches with `:locale=en`.
53
53
  *
54
+ * `restoreRootTrailingSlash` makes the root `/en/` rather than `/en`; header
55
+ * callers compute it with `shouldRestoreLocaleRootTrailingSlash`. Redirect
56
+ * and rewrite callers do not pass it yet.
57
+ *
54
58
  * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
55
59
  * https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/router-utils/resolve-routes.ts
56
60
  */
@@ -59,10 +63,22 @@ function normalizeDefaultLocalePathname(pathname, i18n, options = {}) {
59
63
  if (pathname.startsWith("/_next/") || pathname.startsWith("/__vinext/")) return pathname;
60
64
  if (detectPathnameLocale(pathname, i18n.locales)) return pathname;
61
65
  const defaultLocale = detectDomainLocale(i18n.domains, options.hostname ?? void 0)?.defaultLocale ?? i18n.defaultLocale;
62
- if (pathname === "/") return `/${defaultLocale}`;
66
+ if (pathname === "/") return options.restoreRootTrailingSlash ? `/${defaultLocale}/` : `/${defaultLocale}`;
63
67
  return `/${defaultLocale}${pathname}`;
64
68
  }
65
69
  /**
70
+ * Whether Next.js re-adds the root's trailing slash after splicing in the
71
+ * default locale: the raw request pathname (basePath included, so `/docs`
72
+ * stays `/docs/en` while `/docs/` becomes `/docs/en/`) ends with `/`, and
73
+ * `trailingSlash` is on without `skipProxyUrlNormalize`.
74
+ *
75
+ * Ported from Next.js: packages/next/src/server/lib/router-utils/resolve-routes.ts
76
+ * (`hadTrailingSlash` + `maybeAddTrailingSlash`).
77
+ */
78
+ function shouldRestoreLocaleRootTrailingSlash(rawPathname, config) {
79
+ return Boolean(config.trailingSlash && !config.skipProxyUrlNormalize && rawPathname.endsWith("/"));
80
+ }
81
+ /**
66
82
  * Extract locale prefix from a URL path.
67
83
  * e.g. /fr/about -> { locale: "fr", url: "/about", hadPrefix: true }
68
84
  * /about -> { locale: defaultLocale, url: "/about", hadPrefix: false }
@@ -243,4 +259,4 @@ function resolvePagesI18nRequest(url, i18nConfig, headers, hostname, basePath =
243
259
  };
244
260
  }
245
261
  //#endregion
246
- export { detectDomainLocale, detectLocaleFromAcceptLanguage, detectPathnameLocale, extractLocaleFromUrl, getLocaleRedirect, normalizeDefaultLocalePathname, parseCookieLocaleFromHeader, resolvePagesI18nRequest, stripI18nLocaleForApiRoute };
262
+ export { detectDomainLocale, detectLocaleFromAcceptLanguage, detectPathnameLocale, extractLocaleFromUrl, getLocaleRedirect, normalizeDefaultLocalePathname, parseCookieLocaleFromHeader, resolvePagesI18nRequest, shouldRestoreLocaleRootTrailingSlash, stripI18nLocaleForApiRoute };
@@ -15,15 +15,17 @@ export type PagesReqResRequest = Readable & {
15
15
  draftMode?: true;
16
16
  previewData: PagesPreviewData | false;
17
17
  };
18
+ type PagesReqResHeaderValue = string | number | boolean | string[];
18
19
  type PagesReqResHeaders = {
19
- [key: string]: string | number | boolean | string[];
20
+ [key: string]: PagesReqResHeaderValue;
20
21
  };
21
22
  export type PagesReqResResponse = Writable & {
22
23
  statusCode: number;
23
24
  readonly headersSent: boolean;
24
25
  writeHead: (code: number, headers?: PagesReqResHeaders) => PagesReqResResponse;
25
- setHeader: (name: string, value: string | number | boolean | string[]) => PagesReqResResponse;
26
- getHeader: (name: string) => string | number | boolean | string[] | undefined;
26
+ setHeader: (name: string, value: PagesReqResHeaderValue) => PagesReqResResponse;
27
+ appendHeader: (name: string, value: string | readonly string[]) => PagesReqResResponse;
28
+ getHeader: (name: string) => PagesReqResHeaderValue | undefined;
27
29
  status: (code: number) => PagesReqResResponse;
28
30
  json: (data: unknown) => void;
29
31
  send: (data: unknown) => void;
@@ -1,4 +1,5 @@
1
1
  import { parseCookieHeader } from "../utils/parse-cookie.js";
2
+ import { getRequestExecutionContext } from "../shims/request-context.js";
2
3
  import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
3
4
  import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT } from "./pages-body-parser-config.js";
4
5
  import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
@@ -13,6 +14,18 @@ const NO_BODY_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
13
14
  205,
14
15
  304
15
16
  ]);
17
+ const HTTP_TOKEN_PATTERN = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;
18
+ const INVALID_HEADER_VALUE_CHAR_PATTERN = /[^\t\x20-\x7e\x80-\xff]/;
19
+ function createNodeTypeError(code, message) {
20
+ return Object.assign(new TypeError(message), { code });
21
+ }
22
+ function validateAppendedHeader(name, value) {
23
+ if (typeof name !== "string" || !name || !HTTP_TOKEN_PATTERN.test(name)) throw createNodeTypeError("ERR_INVALID_HTTP_TOKEN", `Header name must be a valid HTTP token ["${String(name)}"]`);
24
+ for (const item of Array.isArray(value) ? value : [value]) {
25
+ if (item === void 0) throw createNodeTypeError("ERR_HTTP_INVALID_HEADER_VALUE", `Invalid value "undefined" for header "${name}"`);
26
+ if (INVALID_HEADER_VALUE_CHAR_PATTERN.test(String(item))) throw createNodeTypeError("ERR_INVALID_CHAR", `Invalid character in header content ["${name}"]`);
27
+ }
28
+ }
16
29
  async function readPagesRequestBodyWithLimit(request, maxBytes) {
17
30
  if (!request.body) return "";
18
31
  return readStreamAsTextWithLimit(request.body, maxBytes, () => {
@@ -120,9 +133,9 @@ var PagesResponseStream = class extends Writable {
120
133
  resolveResponse;
121
134
  rejectResponse;
122
135
  resStatusCode = 200;
123
- resHeaders = {};
124
- setCookieHeaders = [];
136
+ resHeaders = Object.create(null);
125
137
  resolved = false;
138
+ headWritten = false;
126
139
  controller = null;
127
140
  bufferedChunks = [];
128
141
  streamEnded = false;
@@ -150,15 +163,21 @@ var PagesResponseStream = class extends Writable {
150
163
  }
151
164
  writeHead(code, headers) {
152
165
  this.resStatusCode = code;
153
- if (headers) for (const [key, value] of Object.entries(headers)) this.setHeaderValue(key, value, { replaceSetCookie: true });
166
+ if (headers) for (const [key, value] of Object.entries(headers)) this.setHeaderValue(key, value, { append: false });
167
+ this.headWritten = true;
154
168
  return this;
155
169
  }
156
170
  setHeader(name, value) {
157
- this.setHeaderValue(name, value, { replaceSetCookie: true });
171
+ this.setHeaderValue(name, value, { append: false });
172
+ return this;
173
+ }
174
+ appendHeader(name, value) {
175
+ if (this.headWritten || this.headersSent) throw Object.assign(/* @__PURE__ */ new Error("Cannot append headers after they are sent to the client"), { code: "ERR_HTTP_HEADERS_SENT" });
176
+ validateAppendedHeader(name, value);
177
+ this.setHeaderValue(name, value, { append: true });
158
178
  return this;
159
179
  }
160
180
  getHeader(name) {
161
- if (name.toLowerCase() === "set-cookie") return this.setCookieHeaders.length > 0 ? this.setCookieHeaders : void 0;
162
181
  return this.resHeaders[name.toLowerCase()];
163
182
  }
164
183
  status(code) {
@@ -196,9 +215,7 @@ var PagesResponseStream = class extends Writable {
196
215
  return this;
197
216
  }
198
217
  getHeaders() {
199
- const headers = { ...this.resHeaders };
200
- if (this.setCookieHeaders.length > 0) headers["set-cookie"] = this.setCookieHeaders;
201
- return headers;
218
+ return { ...this.resHeaders };
202
219
  }
203
220
  setPreviewData(data, options = {}) {
204
221
  setPagesPreviewData(this, data, options);
@@ -250,13 +267,15 @@ var PagesResponseStream = class extends Writable {
250
267
  callback(error);
251
268
  }
252
269
  setHeaderValue(name, value, options) {
253
- if (name.toLowerCase() === "set-cookie") {
254
- const values = Array.isArray(value) ? value.map(String) : [String(value)];
255
- if (options.replaceSetCookie) this.setCookieHeaders.length = 0;
256
- this.setCookieHeaders.push(...values);
270
+ const key = name.toLowerCase();
271
+ const existing = this.resHeaders[key];
272
+ if (!options.append || existing === void 0) {
273
+ this.resHeaders[key] = value;
257
274
  return;
258
275
  }
259
- this.resHeaders[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : value;
276
+ const values = Array.isArray(existing) ? existing : [existing];
277
+ values.push(...Array.isArray(value) ? value : [value]);
278
+ this.resHeaders[key] = values;
260
279
  }
261
280
  releasePendingWrite(error) {
262
281
  const callback = this.pendingWrite;
@@ -267,8 +286,8 @@ var PagesResponseStream = class extends Writable {
267
286
  if (this.resolved) return;
268
287
  this.resolved = true;
269
288
  const headers = new Headers();
270
- for (const [key, value] of Object.entries(this.resHeaders)) headers.set(key, String(value));
271
- for (const cookie of this.setCookieHeaders) headers.append("set-cookie", cookie);
289
+ for (const [key, value] of Object.entries(this.resHeaders)) if (Array.isArray(value)) for (const item of value) headers.append(key, String(item));
290
+ else headers.set(key, String(value));
272
291
  if (NO_BODY_RESPONSE_STATUSES.has(this.resStatusCode)) {
273
292
  this.discardBody = true;
274
293
  this.bufferedChunks.length = 0;
@@ -359,10 +378,10 @@ function createPagesReqRes(options) {
359
378
  */
360
379
  function createPagesApiReqRes(options) {
361
380
  const { req, res, responsePromise } = createPagesReqRes(options);
362
- const trustedRevalidateOrigin = options.trustedRevalidateOrigin ?? new URL(options.request.url).origin;
363
381
  return {
364
382
  req,
365
383
  res: Object.assign(res, { async revalidate(urlPath, opts) {
384
+ const trustedRevalidateOrigin = options.trustedRevalidateOrigin ?? (getRequestExecutionContext()?.dispatchPagesRevalidate ? new URL(options.request.url).origin : void 0);
366
385
  await performOnDemandRevalidate(options.request.headers, urlPath, opts, trustedRevalidateOrigin, options.allowedRevalidateHeaderKeys);
367
386
  } }),
368
387
  responsePromise
@@ -1,7 +1,7 @@
1
1
  import { isUnknownRecord } from "../utils/record.js";
2
2
  import { isBotUserAgent } from "../utils/html-limited-bots.js";
3
- import { normalizePathnameForRouteMatch } from "../routing/utils.js";
4
3
  import { NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
4
+ import { normalizePathnameForRouteMatch } from "../routing/utils.js";
5
5
  import { isDangerousScheme } from "../shims/url-safety.js";
6
6
  import { extractLocaleFromUrl } from "./pages-i18n.js";
7
7
  import { buildNextDataPropsJsonResponse } from "./pages-data-route.js";
@@ -1,10 +1,10 @@
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 } from "../utils/protocol-headers.js";
4
+ import { NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_CACHE_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER } from "./headers.js";
4
5
  import { normalizePathnameForRouteMatch } from "../routing/utils.js";
5
6
  import { patternToNextFormat } from "../routing/route-validation.js";
6
7
  import { getRequestExecutionContext } from "../shims/request-context.js";
7
- import { NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_CACHE_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER } from "./headers.js";
8
8
  import { extractLocaleFromUrl, resolvePagesI18nRequest } from "./pages-i18n.js";
9
9
  import { buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, normalizePagesDataRequest, parseNextDataPathname } from "./pages-data-route.js";
10
10
  import { reportRequestError } from "./instrumentation.js";
@@ -1,6 +1,6 @@
1
1
  import { isBotUserAgent } from "../utils/html-limited-bots.js";
2
- import { getRequestExecutionContext } from "../shims/request-context.js";
3
2
  import { NEXTJS_CACHE_HEADER, VINEXT_REVALIDATED_CACHE_TAG_HEADER } from "./headers.js";
3
+ import { getRequestExecutionContext } from "../shims/request-context.js";
4
4
  import { reportRequestError } from "./instrumentation.js";
5
5
  import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
6
6
  import { markRouteCacheabilityExplicitResponsePolicy } from "../shims/cacheability-classification.js";
@@ -15,7 +15,7 @@ type PageRouteMatch = {
15
15
  dataKind?: PagesRouteDataKind;
16
16
  };
17
17
  };
18
- export declare function fetchWorkerFilesystemRoute(request: Request, requestPathname: string, phase: FilesystemRoutePhase, fetchAsset: (request: Request) => Promise<Response>, publicFiles: ReadonlySet<string>, basePath?: string, assetPathPrefix?: string, hadBasePath?: boolean): Promise<Response | false>;
18
+ export declare function fetchWorkerFilesystemRoute(request: Request, requestPathname: string, phase: FilesystemRoutePhase, fetchAsset: (request: Request) => Promise<Response>, publicFiles: ReadonlySet<string>, basePath?: string, assetPathPrefix?: string, pathnameHasBasePath?: boolean): Promise<Response | false>;
19
19
  export type MiddlewareResult = {
20
20
  continue: boolean;
21
21
  /** The pathname matches middleware, irrespective of request `has`/`missing` conditions. */
@@ -54,6 +54,11 @@ export type PagesPipelineDeps = {
54
54
  recordCacheability?: boolean;
55
55
  rawSearch?: string;
56
56
  configMatchPathname?: string;
57
+ /**
58
+ * `shouldRestoreLocaleRootTrailingSlash` for the raw request pathname
59
+ * (basePath included), which the basePath-stripped request no longer shows.
60
+ */
61
+ restoreLocaleRootTrailingSlash?: boolean;
57
62
  /**
58
63
  * Validate an on-demand revalidation credential using the runtime's
59
64
  * authoritative build secret. Production adapters must inject the verifier
@@ -1,19 +1,20 @@
1
1
  import { PRERENDER_REVALIDATE_HEADER } from "../utils/protocol-headers.js";
2
2
  import { requestContextFromRequest } from "../config/request-context.js";
3
3
  import { isExternalUrl } from "../utils/external-url.js";
4
- import { applyMiddlewareRequestHeaders, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, sanitizeDestination } from "../config/config-matchers.js";
5
- import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
6
- import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
7
4
  import { addBasePathToPathname, hasBasePath } from "../utils/base-path.js";
8
- import { patternToNextFormat } from "../routing/route-validation.js";
9
5
  import { VINEXT_PRERENDER_REWRITTEN_HEADER } from "./headers.js";
10
6
  import { methodNotAllowedResponse, notFoundStaticAssetResponse, sanitizeMethodNotAllowedHeaders } from "./http-error-responses.js";
11
7
  import { cloneRequestWithUrl, normalizeTrailingSlash } from "./request-pipeline.js";
8
+ import { applyMiddlewareRequestHeaders, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, sanitizeDestination } from "../config/config-matchers.js";
9
+ import { assetPrefixPathname, isAssetPrefixBuildAsset, isNextStaticPath } from "../utils/asset-prefix.js";
10
+ import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
11
+ import { patternToNextFormat } from "../routing/route-validation.js";
12
12
  import { detectPathnameLocale, normalizeDefaultLocalePathname, stripI18nLocaleForApiRoute } from "./pages-i18n.js";
13
13
  import { buildMiddlewarePrefetchSkipResponse } from "./pages-data-route.js";
14
14
  import { markRouteCacheabilityDynamic } from "../shims/cacheability-classification.js";
15
15
  import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
16
16
  import { mergeRewriteQuery } from "../utils/query.js";
17
+ import { withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
17
18
  import { setFrameworkRequestRoute } from "./request-tracing.js";
18
19
  import { applyConfigHeadersToHeaderRecord } from "./config-headers.js";
19
20
  import { finalizeMissingStaticAssetResponse, mergeHeaders } from "./worker-utils.js";
@@ -33,7 +34,7 @@ function headersFromRecord(record) {
33
34
  else headers.set(name, value);
34
35
  return headers;
35
36
  }
36
- async function fetchWorkerFilesystemRoute(request, requestPathname, phase, fetchAsset, publicFiles, basePath = "", assetPathPrefix = "", hadBasePath = true) {
37
+ async function fetchWorkerFilesystemRoute(request, requestPathname, phase, fetchAsset, publicFiles, basePath = "", assetPathPrefix = "", pathnameHasBasePath = true) {
37
38
  const isRetrievalMethod = request.method === "GET" || request.method === "HEAD";
38
39
  const assetUrl = new URL(request.url);
39
40
  assetUrl.pathname = requestPathname;
@@ -46,7 +47,8 @@ async function fetchWorkerFilesystemRoute(request, requestPathname, phase, fetch
46
47
  } catch {
47
48
  return false;
48
49
  }
49
- const isPublicFile = (phase !== "direct" || hadBasePath) && publicFiles.has(publicFileKey);
50
+ if (!pathnameHasBasePath && !isAssetPrefixBuildAsset(decodedAssetUrl.pathname, assetPathPrefix)) return false;
51
+ const isPublicFile = pathnameHasBasePath && publicFiles.has(publicFileKey);
50
52
  if (!isPublicFile && (requestPathname === "/api" || requestPathname.startsWith("/api/"))) return false;
51
53
  if (phase === "direct" && isRetrievalMethod && !isPublicFile) return false;
52
54
  if (!isPublicFile && !isNextStaticPath(decodedAssetUrl.pathname, basePath, assetPathPrefix)) return false;
@@ -79,7 +81,7 @@ function wrapMiddlewareWithBasePath(runMiddleware, basePath, hadBasePath) {
79
81
  return (request, ctx, opts) => {
80
82
  const mwUrl = new URL(request.url);
81
83
  mwUrl.pathname = addBasePathToPathname(mwUrl.pathname, basePath);
82
- return runMiddleware(new Request(mwUrl, request), ctx, opts);
84
+ return runMiddleware(cloneRequestWithUrl(request, mwUrl.toString()), ctx, opts);
83
85
  };
84
86
  }
85
87
  /**
@@ -118,6 +120,10 @@ async function runPagesRequest(request, deps) {
118
120
  const reqCtx = requestContextFromRequest(request);
119
121
  const requestHostname = i18nConfig ? url.hostname : "";
120
122
  const requestConfigMatchPathname = i18nConfig ? normalizeDefaultLocalePathname(requestConfigPathname, i18nConfig, { hostname: requestHostname }) : requestConfigPathname;
123
+ const requestHeaderMatchPathname = i18nConfig ? normalizeDefaultLocalePathname(requestConfigPathname, i18nConfig, {
124
+ hostname: requestHostname,
125
+ restoreRootTrailingSlash: deps.restoreLocaleRootTrailingSlash
126
+ }) : requestConfigPathname;
121
127
  if (configRedirects.length) {
122
128
  const redirect = matchRedirect(requestConfigMatchPathname, configRedirects, reqCtx, basePathState, conditionalRedirectCacheability);
123
129
  if (redirect) {
@@ -141,14 +147,16 @@ async function runPagesRequest(request, deps) {
141
147
  hadBasePath: resolvedPathnameHasBasePath
142
148
  });
143
149
  const middlewareHeaders = {};
150
+ let middlewareCookies = [];
144
151
  const mergeConfigHeadersIntoEarlyResponse = (response) => {
145
152
  if (configHeaders.length === 0) return response;
146
153
  const matchedConfigHeaders = {};
147
154
  applyConfigHeadersToHeaderRecord(matchedConfigHeaders, {
148
155
  configHeaders,
149
- pathname: requestConfigMatchPathname,
156
+ pathname: requestHeaderMatchPathname,
150
157
  requestContext: reqCtx,
151
158
  basePathState,
159
+ middlewareHeaders: response.headers,
152
160
  recordCacheability: deps.recordCacheability
153
161
  });
154
162
  return mergeHeaders(response, matchedConfigHeaders);
@@ -210,6 +218,8 @@ async function runPagesRequest(request, deps) {
210
218
  else if (existing) middlewareHeaders[key] = [existing, value];
211
219
  else middlewareHeaders[key] = [value];
212
220
  } else middlewareHeaders[key] = value;
221
+ const stagedCookies = middlewareHeaders["set-cookie"];
222
+ if (Array.isArray(stagedCookies)) middlewareCookies = [...stagedCookies];
213
223
  if (result.rewriteUrl) {
214
224
  resolvedUrl = result.rewriteUrl;
215
225
  resolvedPathnameIsRequestPathname = false;
@@ -249,26 +259,24 @@ async function runPagesRequest(request, deps) {
249
259
  };
250
260
  if (configHeaders.length) applyConfigHeadersToHeaderRecord(middlewareHeaders, {
251
261
  configHeaders,
252
- pathname: requestConfigMatchPathname,
262
+ pathname: requestHeaderMatchPathname,
253
263
  requestContext: reqCtx,
254
264
  basePathState,
255
265
  recordCacheability: deps.recordCacheability
256
266
  });
257
- if (isExternalUrl(resolvedUrl)) {
258
- const proxyResponse = await proxyExternal(request, resolvedUrl);
259
- return {
260
- type: "response",
261
- response: mergeHeaders(proxyResponse, middlewareHeaders, void 0)
262
- };
263
- }
267
+ const proxyConfigRewrite = async (destination) => ({
268
+ type: "response",
269
+ response: withExternalRewriteResponseHeaders(await proxyExternal(request, destination), new Headers(), middlewareCookies)
270
+ });
271
+ if (isExternalUrl(resolvedUrl)) return {
272
+ type: "response",
273
+ response: withExternalRewriteResponseHeaders(await proxyExternal(request, resolvedUrl), headersFromRecord(middlewareHeaders), middlewareCookies)
274
+ };
264
275
  let configRewriteFired = false;
265
276
  for (const rewrite of configRewrites.beforeFiles ?? []) {
266
277
  const rewritten = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), currentBasePathState(), configSourcePathname(), conditionalRewriteCacheability);
267
278
  if (rewritten) {
268
- if (isExternalUrl(rewritten)) return {
269
- type: "response",
270
- response: await proxyExternal(request, rewritten)
271
- };
279
+ if (isExternalUrl(rewritten)) return proxyConfigRewrite(rewritten);
272
280
  resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
273
281
  resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
274
282
  resolvedPathnameIsRequestPathname = false;
@@ -279,13 +287,13 @@ async function runPagesRequest(request, deps) {
279
287
  const initialFilesystemResult = await serveFilesystemRoute(resolvedPathname, resolvedPathnameIsRequestPathname ? "direct" : "beforeFiles");
280
288
  if (initialFilesystemResult) return initialFilesystemResult;
281
289
  const isMissingBuildAsset = () => isNextStaticPath(resolvedPathname, "", assetPrefixPathname(deps.assetPrefix ?? ""));
282
- const isOutsideBasePathUnclaimed = () => basePath && !hadBasePath && !configRewriteFired;
290
+ const isOutsideBasePathUnclaimed = () => basePath && !resolvedPathnameHasBasePath;
283
291
  const outOfBasePathNotFound = () => ({
284
292
  type: "response",
285
- response: isMissingBuildAsset() ? notFoundStaticAssetResponse(headersFromRecord(middlewareHeaders)) : new Response("This page could not be found", {
293
+ response: isMissingBuildAsset() ? notFoundStaticAssetResponse(headersFromRecord(middlewareHeaders)) : mergeHeaders(new Response("This page could not be found", {
286
294
  status: 404,
287
295
  headers: { "Content-Type": "text/html; charset=utf-8" }
288
- })
296
+ }), middlewareHeaders)
289
297
  });
290
298
  const handleResolvedApiRoute = async () => {
291
299
  if (isOutsideBasePathUnclaimed()) return null;
@@ -327,10 +335,7 @@ async function runPagesRequest(request, deps) {
327
335
  if (!pageMatch || pageMatch.route.isDynamic) for (const rewrite of configRewrites.afterFiles ?? []) {
328
336
  const rewritten = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), currentBasePathState(), configSourcePathname(), conditionalRewriteCacheability);
329
337
  if (rewritten) {
330
- if (isExternalUrl(rewritten)) return {
331
- type: "response",
332
- response: await proxyExternal(request, rewritten)
333
- };
338
+ if (isExternalUrl(rewritten)) return proxyConfigRewrite(rewritten);
334
339
  resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
335
340
  resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
336
341
  resolvedPathnameIsRequestPathname = false;
@@ -355,10 +360,7 @@ async function runPagesRequest(request, deps) {
355
360
  if ((isOutsideBasePathUnclaimed() || isDataReq || isDataRequest) && !renderPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
356
361
  const fallbackRewrite = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), currentBasePathState(), configSourcePathname(), conditionalRewriteCacheability);
357
362
  if (!fallbackRewrite) continue;
358
- if (isExternalUrl(fallbackRewrite)) return {
359
- type: "response",
360
- response: await proxyExternal(request, fallbackRewrite)
361
- };
363
+ if (isExternalUrl(fallbackRewrite)) return proxyConfigRewrite(fallbackRewrite);
362
364
  resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
363
365
  resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
364
366
  resolvedPathnameIsRequestPathname = false;
@@ -384,10 +386,7 @@ async function runPagesRequest(request, deps) {
384
386
  if (response.status === 404 && shouldDeferErrorPageOnMiss && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
385
387
  const fallbackRewrite = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), currentBasePathState(), configSourcePathname(), conditionalRewriteCacheability);
386
388
  if (!fallbackRewrite) continue;
387
- if (isExternalUrl(fallbackRewrite)) return {
388
- type: "response",
389
- response: await proxyExternal(request, fallbackRewrite)
390
- };
389
+ if (isExternalUrl(fallbackRewrite)) return proxyConfigRewrite(fallbackRewrite);
391
390
  resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
392
391
  resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
393
392
  resolvedPathnameIsRequestPathname = false;
@@ -437,10 +436,7 @@ async function runPagesRequest(request, deps) {
437
436
  if (!devPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
438
437
  const fallbackRewrite = matchRewrite(configSourcePathname(), [rewrite], rewriteRequestContext(), currentBasePathState(), configSourcePathname(), conditionalRewriteCacheability);
439
438
  if (!fallbackRewrite) continue;
440
- if (isExternalUrl(fallbackRewrite)) return {
441
- type: "response",
442
- response: await proxyExternal(request, fallbackRewrite)
443
- };
439
+ if (isExternalUrl(fallbackRewrite)) return proxyConfigRewrite(fallbackRewrite);
444
440
  resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
445
441
  resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
446
442
  resolvedPathnameIsRequestPathname = false;