vinext 1.3.1 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/README.md +25 -22
  2. package/THIRD_PARTY_LICENSES.md +47 -0
  3. package/dist/_virtual/_rolldown/runtime.js +3 -2
  4. package/dist/build/prerender.js +4 -3
  5. package/dist/build/report.d.ts +0 -14
  6. package/dist/build/report.js +1 -51
  7. package/dist/check.js +4 -7
  8. package/dist/cli.js +3 -0
  9. package/dist/client/dev-error-overlay-store.d.ts +1 -0
  10. package/dist/client/dev-error-overlay.d.ts +2 -0
  11. package/dist/client/dev-error-overlay.js +20 -4
  12. package/dist/client/navigation-runtime.d.ts +13 -1
  13. package/dist/client/navigation-runtime.js +1 -1
  14. package/dist/config/config-matchers.js +2 -0
  15. package/dist/config/destination-params.d.ts +2 -1
  16. package/dist/config/destination-params.js +52 -2
  17. package/dist/config/next-config.d.ts +25 -0
  18. package/dist/config/next-config.js +82 -4
  19. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-codec.js +327 -0
  20. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-data.js +123 -0
  21. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/index.js +29 -0
  22. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/internal.js +134 -0
  23. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-codec.js +50 -0
  24. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data-generated.js +455 -0
  25. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data.js +147 -0
  26. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/big5-added.json.js +169 -0
  27. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp936.json.js +2584 -0
  28. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp949.json.js +2220 -0
  29. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp950.json.js +227 -0
  30. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/eucjp.json.js +425 -0
  31. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gb18030-ranges.json.js +427 -0
  32. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gbk-added.json.js +229 -0
  33. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/shiftjis.json.js +292 -0
  34. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf16.js +106 -0
  35. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf7.js +182 -0
  36. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/bom-handling.js +42 -0
  37. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/extend-node.js +147 -0
  38. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/index.js +94 -0
  39. package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/streams.js +95 -0
  40. package/dist/deps/.pnpm/safer-buffer@2.1.2/deps/safer-buffer/safer.js +45 -0
  41. package/dist/entries/app-rsc-entry.js +17 -49
  42. package/dist/entries/app-rsc-manifest.js +3 -4
  43. package/dist/entries/app-ssr-entry.js +1 -0
  44. package/dist/entries/pages-server-entry.js +36 -9
  45. package/dist/index.js +112 -90
  46. package/dist/init-cloudflare.d.ts +1 -3
  47. package/dist/init-cloudflare.js +10 -48
  48. package/dist/init-platform.d.ts +2 -0
  49. package/dist/init-platform.js +4 -0
  50. package/dist/plugins/extensionless-dynamic-import.js +6 -2
  51. package/dist/plugins/next-intl-catalog.d.ts +12 -0
  52. package/dist/plugins/next-intl-catalog.js +85 -0
  53. package/dist/plugins/pages-node-externals.d.ts +1 -0
  54. package/dist/plugins/pages-node-externals.js +1 -1
  55. package/dist/plugins/strip-server-exports.js +2 -1
  56. package/dist/plugins/use-cache-callable.d.ts +1 -1
  57. package/dist/plugins/use-cache-callable.js +136 -94
  58. package/dist/routing/app-route-graph.d.ts +6 -0
  59. package/dist/routing/app-route-graph.js +9 -1
  60. package/dist/server/api-handler.js +21 -5
  61. package/dist/server/app-bfcache-identity.js +1 -1
  62. package/dist/server/app-browser-entry.js +86 -66
  63. package/dist/server/app-browser-history-controller.d.ts +5 -4
  64. package/dist/server/app-browser-history-controller.js +93 -15
  65. package/dist/server/app-browser-navigation-controller.d.ts +2 -2
  66. package/dist/server/app-browser-navigation-controller.js +1 -2
  67. package/dist/server/app-browser-rsc-redirect.js +7 -7
  68. package/dist/server/app-browser-server-action-client.d.ts +2 -0
  69. package/dist/server/app-browser-server-action-client.js +5 -4
  70. package/dist/server/app-browser-state.d.ts +2 -4
  71. package/dist/server/app-browser-state.js +9 -4
  72. package/dist/server/app-browser-supplemental-refresh.js +16 -1
  73. package/dist/server/app-browser-visible-commit.d.ts +1 -1
  74. package/dist/server/app-browser-visible-commit.js +4 -14
  75. package/dist/server/app-elements-wire.d.ts +6 -38
  76. package/dist/server/app-elements-wire.js +4 -41
  77. package/dist/server/app-elements.d.ts +2 -2
  78. package/dist/server/app-elements.js +2 -2
  79. package/dist/server/app-history-state.d.ts +2 -2
  80. package/dist/server/app-history-state.js +5 -2
  81. package/dist/server/app-mounted-layouts.d.ts +21 -0
  82. package/dist/server/app-mounted-layouts.js +67 -0
  83. package/dist/server/app-optimistic-routing.d.ts +19 -1
  84. package/dist/server/app-optimistic-routing.js +43 -4
  85. package/dist/server/app-page-boundary-render.js +10 -14
  86. package/dist/server/app-page-boundary.js +2 -2
  87. package/dist/server/app-page-cache-finalizer.d.ts +12 -1
  88. package/dist/server/app-page-cache-finalizer.js +70 -29
  89. package/dist/server/app-page-cache.d.ts +13 -1
  90. package/dist/server/app-page-cache.js +31 -9
  91. package/dist/server/app-page-dispatch.d.ts +5 -11
  92. package/dist/server/app-page-dispatch.js +84 -155
  93. package/dist/server/app-page-element-builder.d.ts +2 -2
  94. package/dist/server/app-page-element-builder.js +13 -12
  95. package/dist/server/app-page-execution.d.ts +17 -52
  96. package/dist/server/app-page-execution.js +102 -95
  97. package/dist/server/app-page-head.d.ts +13 -0
  98. package/dist/server/app-page-head.js +44 -16
  99. package/dist/server/app-page-http-access-fallback-metadata.d.ts +1 -0
  100. package/dist/server/app-page-http-access-fallback-metadata.js +2 -2
  101. package/dist/server/app-page-layout-gate.d.ts +35 -0
  102. package/dist/server/app-page-layout-gate.js +50 -0
  103. package/dist/server/app-page-params.d.ts +0 -1
  104. package/dist/server/app-page-params.js +1 -14
  105. package/dist/server/app-page-probe.d.ts +3 -21
  106. package/dist/server/app-page-probe.js +4 -37
  107. package/dist/server/app-page-render.d.ts +2 -13
  108. package/dist/server/app-page-render.js +103 -234
  109. package/dist/server/app-page-request.d.ts +1 -3
  110. package/dist/server/app-page-request.js +1 -1
  111. package/dist/server/app-page-response.js +3 -3
  112. package/dist/server/app-page-route-wiring.d.ts +13 -6
  113. package/dist/server/app-page-route-wiring.js +86 -63
  114. package/dist/server/app-page-rsc-render-status.d.ts +27 -1
  115. package/dist/server/app-page-rsc-render-status.js +121 -13
  116. package/dist/server/app-page-stream.d.ts +12 -8
  117. package/dist/server/app-page-stream.js +4 -3
  118. package/dist/server/app-pages-bridge.d.ts +4 -0
  119. package/dist/server/app-pages-bridge.js +7 -3
  120. package/dist/server/app-render-dependency.d.ts +11 -4
  121. package/dist/server/app-render-dependency.js +86 -38
  122. package/dist/server/app-request-stage-dispatch.js +1 -1
  123. package/dist/server/app-request-stage-independent-entry.js +1 -1
  124. package/dist/server/app-route-handler-cache.js +2 -2
  125. package/dist/server/app-route-handler-dispatch.js +14 -9
  126. package/dist/server/app-route-handler-execution.js +11 -5
  127. package/dist/server/app-route-handler-policy.d.ts +1 -1
  128. package/dist/server/app-route-handler-policy.js +3 -3
  129. package/dist/server/app-route-handler-response.js +1 -1
  130. package/dist/server/app-route-handler-runtime.d.ts +1 -1
  131. package/dist/server/app-route-handler-runtime.js +28 -11
  132. package/dist/server/app-router-entry.js +1 -1
  133. package/dist/server/app-rsc-cache-busting.d.ts +12 -12
  134. package/dist/server/app-rsc-cache-busting.js +31 -72
  135. package/dist/server/app-rsc-error-handler.d.ts +2 -1
  136. package/dist/server/app-rsc-error-handler.js +10 -2
  137. package/dist/server/app-rsc-errors.d.ts +8 -0
  138. package/dist/server/app-rsc-errors.js +11 -1
  139. package/dist/server/app-rsc-handler.d.ts +5 -5
  140. package/dist/server/app-rsc-handler.js +80 -83
  141. package/dist/server/app-rsc-request-normalization.d.ts +10 -16
  142. package/dist/server/app-rsc-request-normalization.js +12 -18
  143. package/dist/server/app-rsc-response-finalizer.js +2 -2
  144. package/dist/server/app-rsc-response-stage.js +9 -15
  145. package/dist/server/app-server-action-execution.d.ts +3 -1
  146. package/dist/server/app-server-action-execution.js +15 -8
  147. package/dist/server/app-ssr-entry.d.ts +8 -0
  148. package/dist/server/app-ssr-entry.js +22 -16
  149. package/dist/server/app-ssr-stream.js +1 -1
  150. package/dist/server/app-visited-response-cache.d.ts +36 -1
  151. package/dist/server/app-visited-response-cache.js +46 -5
  152. package/dist/server/app-worker-stages.d.ts +37 -6
  153. package/dist/server/app-worker-stages.js +81 -9
  154. package/dist/server/artifact-compatibility.d.ts +0 -1
  155. package/dist/server/artifact-compatibility.js +1 -10
  156. package/dist/server/bfcache-identity.d.ts +7 -0
  157. package/dist/server/bfcache-identity.js +10 -1
  158. package/dist/server/cache-proof.d.ts +1 -115
  159. package/dist/server/cache-proof.js +1 -544
  160. package/dist/server/cacheability-manifest.js +1 -2
  161. package/dist/server/cacheability-request.js +13 -8
  162. package/dist/server/dev-origin-check.d.ts +2 -1
  163. package/dist/server/dev-origin-check.js +2 -1
  164. package/dist/server/dev-server.js +6 -4
  165. package/dist/server/headers.d.ts +6 -3
  166. package/dist/server/headers.js +9 -5
  167. package/dist/server/image-optimization.d.ts +5 -0
  168. package/dist/server/image-optimization.js +6 -1
  169. package/dist/server/isr-cache.d.ts +8 -2
  170. package/dist/server/isr-cache.js +30 -2
  171. package/dist/server/metadata-route-response.js +32 -15
  172. package/dist/server/middleware-matcher.js +19 -6
  173. package/dist/server/middleware-runtime.js +6 -2
  174. package/dist/server/multi-stage.d.ts +57 -12
  175. package/dist/server/multi-stage.js +13 -1
  176. package/dist/server/navigation-planner.js +1 -1
  177. package/dist/server/pages-api-route.js +28 -19
  178. package/dist/server/pages-media-type.d.ts +21 -1
  179. package/dist/server/pages-media-type.js +69 -5
  180. package/dist/server/pages-node-compat.d.ts +1 -1
  181. package/dist/server/pages-node-compat.js +54 -27
  182. package/dist/server/pages-page-data.js +2 -1
  183. package/dist/server/pages-page-handler.js +28 -26
  184. package/dist/server/pages-page-response.d.ts +9 -0
  185. package/dist/server/pages-page-response.js +18 -4
  186. package/dist/server/pages-request-pipeline.d.ts +8 -0
  187. package/dist/server/pages-request-pipeline.js +2 -2
  188. package/dist/server/pages-request-stage-entry.js +36 -14
  189. package/dist/server/pages-response-stage-entry.js +9 -3
  190. package/dist/server/pages-router-entry.js +3 -2
  191. package/dist/server/prod-server.d.ts +2 -2
  192. package/dist/server/prod-server.js +47 -9
  193. package/dist/server/request-error-log.d.ts +9 -0
  194. package/dist/server/request-error-log.js +13 -0
  195. package/dist/server/request-pipeline.d.ts +15 -4
  196. package/dist/server/request-pipeline.js +43 -15
  197. package/dist/server/rsc-completion-metadata.js +3 -0
  198. package/dist/server/shared-cache-identity.d.ts +23 -0
  199. package/dist/server/shared-cache-identity.js +36 -0
  200. package/dist/server/static-file-cache.d.ts +9 -0
  201. package/dist/server/static-file-cache.js +13 -2
  202. package/dist/server/worker-stages.d.ts +16 -3
  203. package/dist/server/worker-stages.js +23 -4
  204. package/dist/shims/cache-handler.js +2 -2
  205. package/dist/shims/cache-request-state.d.ts +23 -26
  206. package/dist/shims/cache-request-state.js +22 -57
  207. package/dist/shims/cache-runtime.d.ts +3 -1
  208. package/dist/shims/cache-runtime.js +94 -48
  209. package/dist/shims/cache.d.ts +16 -10
  210. package/dist/shims/cache.js +47 -36
  211. package/dist/shims/cacheability-classification.d.ts +2 -0
  212. package/dist/shims/cdn-cache.d.ts +22 -5
  213. package/dist/shims/client-hook-error.d.ts +2 -0
  214. package/dist/shims/client-hook-error.js +16 -1
  215. package/dist/shims/client-page-root.js +2 -2
  216. package/dist/shims/dynamic.js +9 -6
  217. package/dist/shims/error-boundary.js +2 -2
  218. package/dist/shims/fetch-cache-state.d.ts +5 -1
  219. package/dist/shims/fetch-cache-state.js +1 -3
  220. package/dist/shims/fetch-cache.d.ts +2 -1
  221. package/dist/shims/fetch-cache.js +39 -25
  222. package/dist/shims/form.js +2 -2
  223. package/dist/shims/headers.d.ts +10 -24
  224. package/dist/shims/headers.js +22 -70
  225. package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
  226. package/dist/shims/internal/navigation-untracked.js +1 -1
  227. package/dist/shims/link.js +8 -11
  228. package/dist/shims/metadata.d.ts +23 -21
  229. package/dist/shims/metadata.js +62 -24
  230. package/dist/shims/navigation-server.js +1 -1
  231. package/dist/shims/navigation.d.ts +74 -7
  232. package/dist/shims/navigation.js +184 -31
  233. package/dist/shims/navigation.react-server.js +2 -2
  234. package/dist/shims/request-state-types.d.ts +3 -2
  235. package/dist/shims/slot.d.ts +16 -0
  236. package/dist/shims/slot.js +44 -9
  237. package/dist/shims/unified-request-context.d.ts +7 -1
  238. package/dist/shims/unified-request-context.js +3 -3
  239. package/dist/utils/cache-control-metadata.d.ts +5 -0
  240. package/dist/utils/cache-control-metadata.js +9 -1
  241. package/dist/utils/cache-life-profiles.d.ts +33 -0
  242. package/dist/utils/cache-life-profiles.js +111 -0
  243. package/dist/utils/middleware-request-headers.d.ts +14 -3
  244. package/dist/utils/middleware-request-headers.js +54 -7
  245. package/dist/utils/project.d.ts +2 -2
  246. package/dist/utils/project.js +3 -16
  247. package/dist/utils/regex.d.ts +5 -0
  248. package/dist/utils/regex.js +11 -1
  249. package/dist/utils/text-stream.d.ts +10 -5
  250. package/dist/utils/text-stream.js +6 -6
  251. package/package.json +2 -1
  252. package/dist/build/layout-classification-types.d.ts +0 -60
  253. package/dist/build/layout-classification-types.js +0 -1
  254. package/dist/build/layout-classification.d.ts +0 -62
  255. package/dist/build/layout-classification.js +0 -98
  256. package/dist/build/route-classification-injector.d.ts +0 -33
  257. package/dist/build/route-classification-injector.js +0 -59
  258. package/dist/build/route-classification-manifest.d.ts +0 -54
  259. package/dist/build/route-classification-manifest.js +0 -143
  260. package/dist/server/app-browser-client-reuse-manifest.d.ts +0 -11
  261. package/dist/server/app-browser-client-reuse-manifest.js +0 -101
  262. package/dist/server/app-layout-param-observation.d.ts +0 -42
  263. package/dist/server/app-layout-param-observation.js +0 -168
  264. package/dist/server/client-reuse-manifest.d.ts +0 -103
  265. package/dist/server/client-reuse-manifest.js +0 -209
  266. package/dist/server/skip-cache-proof.d.ts +0 -60
  267. package/dist/server/skip-cache-proof.js +0 -168
  268. package/dist/server/static-layout-client-reuse-proof.d.ts +0 -14
  269. package/dist/server/static-layout-client-reuse-proof.js +0 -33
  270. package/dist/utils/sorted-array.d.ts +0 -8
  271. package/dist/utils/sorted-array.js +0 -20
@@ -1,9 +1,10 @@
1
1
  import { VINEXT_PRERENDER_SECRET_HEADER, VINEXT_REVALIDATE_HOST_HEADER } from "../utils/protocol-headers.js";
2
+ import { applyMiddlewareResponseHeadersToRequest } from "../utils/middleware-request-headers.js";
2
3
  import { requestContextFromRequest } from "../config/request-context.js";
3
4
  import { hasBasePath, stripBasePath } from "../utils/base-path.js";
4
5
  import { VINEXT_CACHEABILITY_PROBE_QUERY_PARAM, VINEXT_EXPECTED_WORKER_VERSION_HEADER } from "./headers.js";
5
6
  import { notFoundStaticAssetResponse } from "./http-error-responses.js";
6
- import { attachRequestCfMetadata, cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders, guardProtocolRelativeUrl } from "./request-pipeline.js";
7
+ import { attachRequestCfMetadata, cloneRequestWithUrl, filterInternalHeaders, guardProtocolRelativeUrl, haveSameHeaders, stripRequestUrlFragment, withRequestHeaders } from "./request-pipeline.js";
7
8
  import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
8
9
  import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
9
10
  import { runWithExecutionContext } from "../shims/request-context.js";
@@ -22,7 +23,8 @@ import { resolveClientBuildFile } from "./client-build-files.js";
22
23
  import { createWorkerRevalidationContext } from "./worker-revalidation-context.js";
23
24
  import { createWorkerPrerenderDiscoveryContext, createWorkerPrerenderReadinessResponse, isWorkerPrerenderDiscoveryPath } from "./worker-prerender-discovery.js";
24
25
  import { getPagesResponseStageCacheDisposition } from "./pages-response-stage.js";
25
- import "./worker-stages.js";
26
+ import { adapterUsesSharedCacheIdentity, pagesCacheIdentityOrigin, pagesPageSharesAcrossHosts } from "./shared-cache-identity.js";
27
+ import { createSharedPagesPageCacheIdentity } from "./worker-stages.js";
26
28
  import { consumePagesResponseStagePolicyOwner, prependResponseStageAdditiveHeaders, withResponseStageVary, withoutResponseStageVary } from "./response-stage-policy.js";
27
29
  import * as configuredCdnCacheAdapters from "virtual:vinext-cdn-cache-adapter";
28
30
  import { registerConfiguredImageOptimizer } from "virtual:vinext-image-adapters";
@@ -34,10 +36,14 @@ import * as pagesEntry from "virtual:vinext-pages-request-entry";
34
36
  * The public pages-router-entry delegates here. Multi-stage hosts import the
35
37
  * named request handler directly and provide their response-stage dispatcher.
36
38
  */
37
- function haveSameHeaders(first, second) {
38
- const firstEntries = [...first];
39
- const secondEntries = [...second];
40
- return firstEntries.length === secondEntries.length && firstEntries.every(([name, value], index) => name === secondEntries[index]?.[0] && value === secondEntries[index]?.[1]);
39
+ /**
40
+ * Whether middleware's request-header overrides changed the request. Next.js
41
+ * also copies ordinary middleware response headers onto the request; like a
42
+ * client's own headers, those do not opt the render out of the shared stage.
43
+ */
44
+ function hasRequestHeaderOverrides(originalHeaders, requestHeaders, middlewareResponseHeaders) {
45
+ const expectedHeaders = middlewareResponseHeaders ? applyMiddlewareResponseHeadersToRequest(originalHeaders, middlewareResponseHeaders) : originalHeaders;
46
+ return !haveSameHeaders(expectedHeaders, requestHeaders);
41
47
  }
42
48
  function captureOuterResponsePolicyHeaders(stagedHeaders, transportedPolicyHeaders) {
43
49
  return captureCdnResponsePolicyOverrides(stagedHeaders, new Headers(transportedPolicyHeaders ?? []));
@@ -90,6 +96,7 @@ function handleRequestStageLocally(request, env, ctx, dispatchResponseStage) {
90
96
  return handleRequest(request, env, ctx, (stageRequest, props, _options, stageEnv, stageCtx) => dispatchResponseStage(stageRequest, stageEnv, stageCtx, props), true, "worker", ctx?.assets).then((response) => applyCdnResponseIdentityHeaders(response, originalRequest));
91
97
  }
92
98
  function handleRequest(request, env, platformCtx, dispatchResponseStage, forceCacheBypass, defaultHostRuntime, assets) {
99
+ request = stripRequestUrlFragment(request);
93
100
  const url = new URL(request.url);
94
101
  const trace = async () => {
95
102
  await pagesEntry.__ensureInstrumentation?.(platformCtx);
@@ -151,7 +158,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
151
158
  const expectedWorkerVersion = request.headers.get(VINEXT_EXPECTED_WORKER_VERSION_HEADER);
152
159
  if (expectedWorkerVersion) filteredHeaders.set(VINEXT_EXPECTED_WORKER_VERSION_HEADER, expectedWorkerVersion);
153
160
  }
154
- request = cloneRequestWithHeaders(request, filteredHeaders);
161
+ request = withRequestHeaders(request, filteredHeaders);
155
162
  const url = new URL(request.url);
156
163
  let pathname = url.pathname;
157
164
  if (ctx.isPrerenderPathDiscovery && isWorkerPrerenderDiscoveryPath(pathname)) return trackedDispatchResponseStage(request, {
@@ -162,7 +169,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
162
169
  resolvedRoutePathname: pathname
163
170
  },
164
171
  kind: "pages-prerender-discovery",
165
- protocolVersion: 5,
172
+ protocolVersion: 6,
166
173
  requestHost: url.host,
167
174
  stagedHeaders: null
168
175
  }, { cache: "bypass" }, env, ctx);
@@ -212,6 +219,7 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
212
219
  requestContext: requestContextFromRequest(request)
213
220
  });
214
221
  let speculativeRenderRequest = null;
222
+ let middlewareResponseHeaders;
215
223
  const deps = {
216
224
  assetPrefix: vinextConfig?.assetPrefix,
217
225
  basePath,
@@ -233,7 +241,15 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
233
241
  authorizeOnDemandRevalidate: typeof authorizeOnDemandRevalidate === "function" ? authorizeOnDemandRevalidate : void 0,
234
242
  matchApiRoute: typeof matchApiRoute === "function" ? matchApiRoute : null,
235
243
  matchPageRoute: typeof matchPageRoute === "function" ? matchPageRoute : null,
236
- runMiddleware: typeof runMiddleware === "function" ? wrapMiddlewareWithBasePath(runMiddleware, basePath, hadBasePath) : null,
244
+ runMiddleware: typeof runMiddleware === "function" ? async (middlewareInput, middlewareCtx, middlewareOptions) => {
245
+ const result = await wrapMiddlewareWithBasePath(runMiddleware, basePath, hadBasePath)(middlewareInput, middlewareCtx, middlewareOptions);
246
+ middlewareResponseHeaders = void 0;
247
+ if (result.responseHeaders) {
248
+ middlewareResponseHeaders = new Headers();
249
+ for (const [key, value] of result.responseHeaders) middlewareResponseHeaders.append(key, value);
250
+ }
251
+ return result;
252
+ } : null,
237
253
  renderPage: (req, resolvedUrl, options, stagedHeaders) => {
238
254
  if (options?.renderErrorPageOnMiss === false && req.body !== null && !req.bodyUsed) speculativeRenderRequest = req;
239
255
  const stageRequest = speculativeRenderRequest === req && req.body !== null && !req.bodyUsed ? attachRequestCfMetadata(req.clone(), req) : req;
@@ -242,11 +258,12 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
242
258
  authorizeOnDemandRevalidate: typeof authorizeOnDemandRevalidate === "function" ? authorizeOnDemandRevalidate : void 0,
243
259
  hasRequestAwareDocument: hasRequestAwareDocument === true,
244
260
  request: req,
245
- requestHeadersChanged: !haveSameHeaders(filteredHeaders, req.headers),
261
+ requestHeadersChanged: hasRequestHeaderOverrides(filteredHeaders, req.headers, middlewareResponseHeaders),
246
262
  routeDataKind: matchedPage?.route.dataKind,
247
263
  stagedHeaders
248
264
  });
249
265
  const isSharedStaticPage = cache === "shared" && matchedPage?.route.dataKind === "static";
266
+ const sharedAcrossHosts = (cache === "shared" || probeMode !== null) && pagesPageSharesAcrossHosts(matchedPage?.route) && adapterUsesSharedCacheIdentity();
250
267
  const transportedPolicyHeaders = isSharedStaticPage ? withoutResponseStageVary(responseStagePolicyHeaders) : withResponseStageVary(responseStagePolicyHeaders, stagedHeaders?.get("Vary"));
251
268
  const responseStageProps = () => ({
252
269
  buildId: pagesEntry.buildId,
@@ -257,17 +274,22 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
257
274
  resolvedRoutePathname: new URL(resolvedUrl, req.url).pathname
258
275
  },
259
276
  kind: "pages-page",
260
- protocolVersion: 5,
277
+ protocolVersion: 6,
261
278
  requestHost: new URL(req.url).host,
262
279
  renderOptions: isDataReq ? {
263
280
  ...options,
264
281
  originalUrl: originalRenderUrl
265
282
  } : options ?? null,
266
283
  resolvedUrl,
284
+ sharedAcrossHosts,
267
285
  stagedHeaders: isSharedStaticPage ? null : [...stagedHeaders ?? new Headers()]
268
286
  });
269
287
  const isHeadRequest = req.method.toUpperCase() === "HEAD";
270
- const responsePromise = trackedDispatchResponseStage(stageRequest, responseStageProps(), { cache }, env, ctx).then((response) => {
288
+ const props = responseStageProps();
289
+ const responsePromise = trackedDispatchResponseStage(stageRequest, props, cache === "shared" && sharedAcrossHosts ? {
290
+ cache,
291
+ cacheIdentity: createSharedPagesPageCacheIdentity(stageRequest, props, pagesCacheIdentityOrigin(stageRequest.url, i18nConfig))
292
+ } : { cache }, env, ctx).then((response) => {
271
293
  const consumed = consumePagesResponseStagePolicyOwner(response);
272
294
  if (cache === "shared") {
273
295
  if (isSharedStaticPage && stagedHeaders) prependResponseStageAdditiveHeaders(consumed.response.headers, stagedHeaders);
@@ -297,14 +319,14 @@ async function handleRequestImpl(request, env, platformCtx, dispatchResponseStag
297
319
  resolvedRoutePathname: new URL(apiUrl, req.url).pathname
298
320
  },
299
321
  kind: "pages-api",
300
- protocolVersion: 5,
322
+ protocolVersion: 6,
301
323
  requestHost: new URL(req.url).host,
302
324
  stagedHeaders: [...stagedHeaders]
303
325
  });
304
326
  const cache = forceCacheBypass || probeMode ? "bypass" : getPagesResponseStageCacheDisposition({
305
327
  authorizeOnDemandRevalidate: typeof authorizeOnDemandRevalidate === "function" ? authorizeOnDemandRevalidate : void 0,
306
328
  request: req,
307
- requestHeadersChanged: !haveSameHeaders(filteredHeaders, req.headers),
329
+ requestHeadersChanged: hasRequestHeaderOverrides(filteredHeaders, req.headers, middlewareResponseHeaders),
308
330
  stagedHeaders
309
331
  });
310
332
  const dispatched = trackedDispatchResponseStage(req, responseStageProps(), { cache }, env, ctx);
@@ -1,7 +1,7 @@
1
1
  import { preserveFullyBufferedBodyMetadata } from "./fully-buffered-response.js";
2
2
  import "../shims/unified-request-context.js";
3
3
  import { runWithExecutionContext } from "../shims/request-context.js";
4
- import { beginRouteCacheability } from "../shims/cacheability-classification.js";
4
+ import { beginRouteCacheability, markRouteCacheabilityDynamic } from "../shims/cacheability-classification.js";
5
5
  import { validateCdnRequest } from "./cache-control.js";
6
6
  import { createWorkerRevalidationContext } from "./worker-revalidation-context.js";
7
7
  import { createWorkerPrerenderReadinessResponse } from "./worker-prerender-discovery.js";
@@ -57,6 +57,12 @@ async function renderPagesResponse(request, env, platformCtx, props, stagedHeade
57
57
  ...ctx,
58
58
  isStoredEntryRegeneration: true
59
59
  };
60
+ let runtimeDataKind;
61
+ const runtimeDataKindIsRequestTime = () => {
62
+ if (props.kind !== "pages-page") return false;
63
+ runtimeDataKind ??= pagesEntry.getRuntimePageDataKind(props.resolvedUrl, request);
64
+ return runtimeDataKind === "server" || runtimeDataKind === "initial";
65
+ };
60
66
  const render = async (cacheabilityContext) => {
61
67
  if (props.kind === "pages-prerender-discovery") {
62
68
  const readinessResponse = createWorkerPrerenderReadinessResponse(cacheabilityContext, request);
@@ -77,6 +83,7 @@ async function renderPagesResponse(request, env, platformCtx, props, stagedHeade
77
83
  });
78
84
  }
79
85
  if (typeof pagesEntry.renderPage !== "function") return new Response("This page could not be found", { status: 404 });
86
+ if (props.sharedAcrossHosts && runtimeDataKindIsRequestTime()) runWithExecutionContext(cacheabilityContext, () => markRouteCacheabilityDynamic("getInitialProps render shares a cache entry across hosts"));
80
87
  return stripStreamedHtmlContentLength(await pagesEntry.renderPage(request, props.resolvedUrl, null, cacheabilityContext, renderHeaders, props.renderOptions ?? void 0, initialResponseHeaders));
81
88
  };
82
89
  const handle = async (cacheabilityContext) => stripInheritedResponseStageCookies(await render(cacheabilityContext), renderHeaders);
@@ -94,9 +101,8 @@ async function renderPagesResponse(request, env, platformCtx, props, stagedHeade
94
101
  resolvedRoutePathname: props.cacheability.resolvedRoutePathname
95
102
  }, handle);
96
103
  if (props.kind !== "pages-page") return response;
97
- const runtimeDataKind = pagesEntry.getRuntimePageDataKind(props.resolvedUrl, request);
98
104
  const headers = new Headers(response.headers);
99
- headers.set(PAGES_RESPONSE_STAGE_POLICY_OWNER_HEADER, runtimeDataKind === "server" || runtimeDataKind === "initial" ? "request-time" : "static");
105
+ headers.set(PAGES_RESPONSE_STAGE_POLICY_OWNER_HEADER, runtimeDataKindIsRequestTime() ? "request-time" : "static");
100
106
  return preserveFullyBufferedBodyMetadata(response, new Response(response.body, {
101
107
  headers,
102
108
  status: response.status,
@@ -1,5 +1,5 @@
1
1
  import { VINEXT_CACHEABILITY_PROBE_HEADER, VINEXT_CACHEABILITY_PROBE_QUERY_PARAM } from "./headers.js";
2
- import { cloneRequestWithHeaders, cloneRequestWithUrl } from "./request-pipeline.js";
2
+ import { cloneRequestWithHeaders, cloneRequestWithUrl, stripRequestUrlFragment } from "./request-pipeline.js";
3
3
  import { runWithExecutionContext } from "../shims/request-context.js";
4
4
  import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
5
5
  import { validateCdnRequest } from "./cache-control.js";
@@ -52,7 +52,8 @@ async function handleSingleStageRequest(request, env, platformCtx) {
52
52
  return finalize ? finalize(response, ctx) : response;
53
53
  }
54
54
  var pages_router_entry_default = { fetch(request, env, ctx) {
55
- const handle = () => handleSingleStageRequest(request, env, ctx);
55
+ const strippedRequest = stripRequestUrlFragment(request);
56
+ const handle = () => handleSingleStageRequest(strippedRequest, env, ctx);
56
57
  return ctx && typeof ctx.waitUntil === "function" ? runWithExecutionContext(ctx, handle) : handle();
57
58
  } };
58
59
  //#endregion
@@ -102,11 +102,11 @@ declare function sendCompressed(req: IncomingMessage, res: ServerResponse, body:
102
102
  * Without a cache, falls back to async filesystem probing (still non-blocking,
103
103
  * unlike the old sync existsSync/statSync approach).
104
104
  *
105
- * `extraHeaders` go on every response for the file. `representationHeaders` go
105
+ * `stagedHeaders` go on every response for the file. `representationHeaders` go
106
106
  * only on responses that carry the file's bytes (200 and 206), never on a 304,
107
107
  * 412, 416 or 405.
108
108
  */
109
- declare function tryServeStatic(req: IncomingMessage, res: ServerResponse, clientDir: string, pathname: string, compress: boolean, cache?: StaticFileCache, extraHeaders?: Record<string, string | string[]>, statusCode?: number, representationHeaders?: Record<string, string>): Promise<boolean>;
109
+ declare function tryServeStatic(req: IncomingMessage, res: ServerResponse, clientDir: string, pathname: string, compress: boolean, cache?: StaticFileCache, stagedHeaders?: Record<string, string | string[]>, statusCode?: number, representationHeaders?: Record<string, string>): Promise<boolean>;
110
110
  /**
111
111
  * Convert a Node.js IncomingMessage to a Web Request object.
112
112
  *
@@ -8,7 +8,7 @@ import { getRepeatedSlashRedirect, isOpenRedirectShaped, sendRepeatedSlashRedire
8
8
  import { readStaticFileSignal } from "./static-file-signal.js";
9
9
  import { canonicalizeRequestPathname, filterInternalHeaders } from "./request-pipeline.js";
10
10
  import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix, isAssetPrefixBuildAsset } from "../utils/asset-prefix.js";
11
- import { StaticFileCache, contentTypeForPath, etagFromFilenameHash } from "./static-file-cache.js";
11
+ import { StaticFileCache, contentTypeForPath, etagFromFilenameHash, staticFileCacheControl } from "./static-file-cache.js";
12
12
  import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
13
13
  import { resolveRequestHost, resolveRequestProtocol, resolveTrustedForwardedHost, trustProxy, trustedHosts } from "./proxy-trust.js";
14
14
  import { normalizePath } from "./normalize-path.js";
@@ -19,7 +19,7 @@ import { parseHttpDate } from "./http-date.js";
19
19
  import { evaluateStaticPreconditions } from "./http-conditional.js";
20
20
  import { setPagesClientAssets } from "./pages-client-assets.js";
21
21
  import { signalFromNodeResponse } from "./node-response-signal.js";
22
- import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_RESPONSE_CACHE_STATE, INVALID_IMAGE_SOURCE_MESSAGE, isImageOptimizationPath, isImageSourceBodyStatus, isSafeImageContentType, parseImageParams, readImageOptimizationSignal } from "./image-optimization.js";
22
+ import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, IMAGE_RESPONSE_CACHE_STATE, INVALID_IMAGE_SOURCE_MESSAGE, MUTABLE_IMAGE_SOURCE_CACHE_CONTROL, isImageOptimizationPath, isImageSourceBodyStatus, isSafeImageContentType, parseImageParams, readImageOptimizationSignal } from "./image-optimization.js";
23
23
  import { installSocketErrorBackstop } from "./socket-error-backstop.js";
24
24
  import { collectInlineCssManifest } from "../build/inline-css.js";
25
25
  import { readTrustedRevalidationHostname } from "./revalidation-host.js";
@@ -284,6 +284,16 @@ function readHeaderCaseInsensitive(headersRecord, name) {
284
284
  const value = headersRecord[key];
285
285
  return Array.isArray(value) ? value.join(", ") : value;
286
286
  }
287
+ /** Spell a header's name as `name`, so spreading the record replaces that key. */
288
+ function withHeaderName(headersRecord, name) {
289
+ const lowerName = name.toLowerCase();
290
+ const key = Object.keys(headersRecord).find((entry) => entry !== name && entry.toLowerCase() === lowerName);
291
+ if (key === void 0) return headersRecord;
292
+ const { [key]: value, ...rest } = headersRecord;
293
+ const existing = rest[name];
294
+ rest[name] = existing === void 0 ? value : [existing, value].flat();
295
+ return rest;
296
+ }
287
297
  /** Remove one field name from a Vary header, dropping the header if it empties. */
288
298
  function omitVaryToken(headers, token) {
289
299
  const varyKey = Object.keys(headers).find((key) => key.toLowerCase() === "vary");
@@ -464,6 +474,18 @@ function staticCacheLookupPath(pathname) {
464
474
  if (lookupPath.startsWith("/.vite/") || lookupPath === "/.vite") return null;
465
475
  return lookupPath;
466
476
  }
477
+ /**
478
+ * Give a Node image passthrough Next.js's image Cache-Control instead of the
479
+ * public-file default: a hashed build asset keeps its immutable default, and
480
+ * any other source is revalidated after the default `images.minimumCacheTTL`.
481
+ */
482
+ function withImageSourceCacheControl(headers, sourcePath) {
483
+ if (sourcePath.includes(`/_next/static/`)) return headers;
484
+ return {
485
+ ...headers,
486
+ "Cache-Control": MUTABLE_IMAGE_SOURCE_CACHE_CONTROL
487
+ };
488
+ }
467
489
  /** Pathnames the Pages Router serves from routes rather than the client directory. */
468
490
  function isPagesFilesystemExcludedPath(pathname, phase) {
469
491
  return pathname === "/" || pathname === "/api" || pathname.startsWith("/api/") || phase === "direct" && pathname.startsWith(`/_next/static/`);
@@ -479,12 +501,13 @@ function isPagesFilesystemExcludedPath(pathname, phase) {
479
501
  * Without a cache, falls back to async filesystem probing (still non-blocking,
480
502
  * unlike the old sync existsSync/statSync approach).
481
503
  *
482
- * `extraHeaders` go on every response for the file. `representationHeaders` go
504
+ * `stagedHeaders` go on every response for the file. `representationHeaders` go
483
505
  * only on responses that carry the file's bytes (200 and 206), never on a 304,
484
506
  * 412, 416 or 405.
485
507
  */
486
- async function tryServeStatic(req, res, clientDir, pathname, compress, cache, extraHeaders, statusCode, representationHeaders) {
508
+ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, stagedHeaders, statusCode, representationHeaders) {
487
509
  if (pathname === "/") return false;
510
+ const extraHeaders = stagedHeaders && withHeaderName(stagedHeaders, "Cache-Control");
488
511
  const responseStatus = statusCode ?? 200;
489
512
  const omitBody = isNoBodyResponseStatus(responseStatus);
490
513
  const requestRange = req.method === "GET" || req.method === "HEAD" ? req.headers.range : void 0;
@@ -610,7 +633,7 @@ async function tryServeStatic(req, res, clientDir, pathname, compress, cache, ex
610
633
  const ext = path.extname(resolved.path);
611
634
  const ct = contentTypeForPath(resolved.path);
612
635
  const isHashed = pathname.includes(`/${ASSET_PREFIX_URL_DIR}/`);
613
- const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "public, max-age=3600";
636
+ const cacheControl = staticFileCacheControl(isHashed);
614
637
  const etag = isHashed && etagFromFilenameHash(resolved.path, ext) || `W/"${resolved.size}-${Math.floor(resolved.mtimeMs / 1e3)}"`;
615
638
  const baseHeaders = {
616
639
  "Content-Type": ct,
@@ -798,6 +821,15 @@ async function statIfFile(filePath) {
798
821
  }
799
822
  }
800
823
  /**
824
+ * Node's parser keeps a `#fragment` sent on the request line in `req.url`.
825
+ * Next.js rebuilds request URLs from pathname + search, so neither routing,
826
+ * middleware nor handlers observe one; drop it before anything reads the URL.
827
+ */
828
+ function stripNodeRequestUrlFragment(req) {
829
+ const hashIndex = req.url?.indexOf("#") ?? -1;
830
+ if (hashIndex !== -1) req.url = req.url?.slice(0, hashIndex);
831
+ }
832
+ /**
801
833
  * Convert a Node.js IncomingMessage to a Web Request object.
802
834
  *
803
835
  * When `urlOverride` is provided, it is used as the path + query string
@@ -1182,7 +1214,7 @@ async function startAppRouterServer(options) {
1182
1214
  "X-Content-Type-Options": "nosniff",
1183
1215
  "Content-Disposition": imageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
1184
1216
  };
1185
- const serveSource = (sourcePath) => tryServeStatic(req, res, clientDir, sourcePath, false, staticCache, imageSecurityHeaders, void 0, IMAGE_REPRESENTATION_HEADERS);
1217
+ const serveSource = (sourcePath) => tryServeStatic(req, res, clientDir, sourcePath, false, staticCache, withImageSourceCacheControl(imageSecurityHeaders, sourcePath), void 0, IMAGE_REPRESENTATION_HEADERS);
1186
1218
  const sourceUrl = new URL(params.imageUrl, request.url);
1187
1219
  let sourcePathname = null;
1188
1220
  try {
@@ -1299,6 +1331,7 @@ async function startAppRouterServer(options) {
1299
1331
  }
1300
1332
  };
1301
1333
  const handleRequest = async (req, res) => {
1334
+ stripNodeRequestUrlFragment(req);
1302
1335
  try {
1303
1336
  await ensureInstrumentation();
1304
1337
  } catch (error) {
@@ -1319,7 +1352,7 @@ async function startAppRouterServer(options) {
1319
1352
  },
1320
1353
  getStatus: () => res.statusCode,
1321
1354
  headers,
1322
- isRsc: target.split("?", 1)[0].endsWith(".rsc") || headers.get("RSC") === "1",
1355
+ isRsc: headers.get("RSC") === "1",
1323
1356
  method: req.method ?? "GET",
1324
1357
  target
1325
1358
  });
@@ -1434,6 +1467,7 @@ async function createPagesRouterRequestHandler(options) {
1434
1467
  });
1435
1468
  const staticCache = await StaticFileCache.create(clientDir);
1436
1469
  const handleRequest = async (req, res) => {
1470
+ stripNodeRequestUrlFragment(req);
1437
1471
  try {
1438
1472
  await ensureInstrumentation();
1439
1473
  } catch (error) {
@@ -1646,7 +1680,11 @@ async function createPagesRouterRequestHandler(options) {
1646
1680
  ...options,
1647
1681
  originalUrl: originalRenderUrl
1648
1682
  }, stagedHeaders?.has("Cache-Control") ? new Headers({ "Cache-Control": stagedHeaders.get("Cache-Control") }) : void 0) : null,
1649
- handleApi: typeof handleApi === "function" ? (request, apiUrl) => handleApi(request, apiUrl, createNodeExecutionContext(), resolveTrustedNodeRevalidateOrigin(req, host, port), "node") : null,
1683
+ handleApi: typeof handleApi === "function" ? (request, apiUrl, _ctx, stagedHeaders) => {
1684
+ stagedHeaders.delete("Content-Length");
1685
+ return handleApi(request, apiUrl, createNodeExecutionContext(), resolveTrustedNodeRevalidateOrigin(req, host, port), "node", stagedHeaders);
1686
+ } : null,
1687
+ handleApiAppliesStagedHeaders: true,
1650
1688
  serveFilesystemRoute: async (requestPathname, stagedHeaders, phase, resolvedUrl, _request, resolvedPathnameHasBasePath) => {
1651
1689
  if (resolvedPathnameHasBasePath && isImageOptimizationPath(requestPathname)) {
1652
1690
  for (const [name, value] of Object.entries(stagedHeaders)) res.setHeader(name, value);
@@ -1667,7 +1705,7 @@ async function createPagesRouterRequestHandler(options) {
1667
1705
  "X-Content-Type-Options": "nosniff",
1668
1706
  "Content-Disposition": pagesImageConfig?.contentDispositionType === "attachment" ? "attachment" : "inline"
1669
1707
  };
1670
- const serveSource = (sourcePath) => tryServeStatic(req, res, clientDir, sourcePath, false, staticCache, imageSecurityHeaders, void 0, IMAGE_REPRESENTATION_HEADERS);
1708
+ const serveSource = (sourcePath) => tryServeStatic(req, res, clientDir, sourcePath, false, staticCache, withImageSourceCacheControl(imageSecurityHeaders, sourcePath), void 0, IMAGE_REPRESENTATION_HEADERS);
1671
1709
  const sourceUrl = new URL(params.imageUrl, webRequest.url);
1672
1710
  let sourcePathname = null;
1673
1711
  try {
@@ -0,0 +1,9 @@
1
+ //#region src/server/request-error-log.d.ts
2
+ /**
3
+ * Logs an error vinext also passes to instrumentation's `onRequestError`, as
4
+ * `next start` logs it. `VINEXT_QUIET=1` turns these logs off, like Next.js'
5
+ * `quiet` server option, so an `onRequestError` that redacts errors before
6
+ * recording them is the only place they reach.
7
+ */
8
+ export declare function logRequestError(...args: unknown[]): void;
9
+ //#endregion
@@ -0,0 +1,13 @@
1
+ //#region src/server/request-error-log.ts
2
+ /**
3
+ * Logs an error vinext also passes to instrumentation's `onRequestError`, as
4
+ * `next start` logs it. `VINEXT_QUIET=1` turns these logs off, like Next.js'
5
+ * `quiet` server option, so an `onRequestError` that redacts errors before
6
+ * recording them is the only place they reach.
7
+ */
8
+ function logRequestError(...args) {
9
+ if (process.env.VINEXT_QUIET === "1") return;
10
+ console.error(...args);
11
+ }
12
+ //#endregion
13
+ export { logRequestError };
@@ -73,7 +73,6 @@ type ResolvePublicFileRouteOptions = {
73
73
  middlewareContext: StaticFileSignalContext & {
74
74
  requestHeaders?: Headers | null;
75
75
  };
76
- pathname: string;
77
76
  publicFiles: ReadonlySet<string>;
78
77
  request: Request;
79
78
  };
@@ -82,7 +81,7 @@ type ResolvePublicFileRouteOptions = {
82
81
  *
83
82
  * Public files are checked after middleware and before afterFiles/fallback
84
83
  * rewrites. The generated App Router entry provides the public-file set; this
85
- * helper owns the RSC exclusion, existence-first method enforcement, and
84
+ * helper owns existence-first method enforcement and
86
85
  * static-file signaling. Missing mutation targets continue through routing.
87
86
  */
88
87
  export declare function resolvePublicFileRoute(options: ResolvePublicFileRouteOptions): Response | null;
@@ -91,8 +90,8 @@ export declare function normalizeTrailingSlashPathname(pathname: string, trailin
91
90
  * Check if the pathname needs a trailing slash redirect, and return the
92
91
  * redirect Response if so.
93
92
  *
94
- * Follows Next.js behavior:
95
- * - `/api` routes are never redirected
93
+ * Follows Next.js behavior, whose internal trailing-slash redirects cover
94
+ * every path, `/api` included:
96
95
  * - The root path `/` is never redirected
97
96
  * - If `trailingSlash` is true, redirect `/about` → `/about/`
98
97
  * - If `trailingSlash` is true, redirect file-looking `/file.ext/` → `/file.ext`
@@ -181,6 +180,12 @@ export declare function attachRequestCfMetadata(target: Request, source: Request
181
180
  * a RequestInit with best-effort metadata.
182
181
  */
183
182
  export declare function cloneRequestWithHeaders(request: Request, headers: Headers): Request;
183
+ export declare function haveSameHeaders(first: Headers, second: Headers): boolean;
184
+ /**
185
+ * `cloneRequestWithHeaders`, except that a native request whose headers
186
+ * already match is returned as is, so its body stays where it is.
187
+ */
188
+ export declare function withRequestHeaders(request: Request, headers: Headers): Request;
184
189
  /**
185
190
  * Clone a Request while overriding the URL, preserving headers and metadata
186
191
  * when possible.
@@ -194,5 +199,11 @@ export declare function cloneRequestWithHeaders(request: Request, headers: Heade
194
199
  * exists.
195
200
  */
196
201
  export declare function cloneRequestWithUrl(request: Request, url: string): Request;
202
+ /**
203
+ * Drop a `#fragment` the host kept from the request line. Next.js rebuilds
204
+ * request URLs from pathname + search, so neither middleware nor handlers
205
+ * ever observe one, and pathname-keyed cache entries must not either.
206
+ */
207
+ export declare function stripRequestUrlFragment(request: Request): Request;
197
208
  //#endregion
198
209
  export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, createStaticFileSignal, getRepeatedSlashRedirect, hasBasePath, isOpenRedirectShaped, sendRepeatedSlashRedirect, stripBasePath };
@@ -84,7 +84,8 @@ function guardProtocolRelativeUrl(rawPathname, search = "") {
84
84
  if (isOpenRedirectShaped(rawPathname)) return notFoundResponse();
85
85
  return null;
86
86
  }
87
- const FILE_LIKE_PATHNAME_RE = /\.[^/]+\/?$/;
87
+ const SLASHED_FILE_PATHNAME_RE = /^\/(?:[^/]+\/)*[^/]+\.\w+\/$/;
88
+ const UNSLASHED_NON_FILE_PATHNAME_RE = /^\/(?:[^/]+\/)*[^/.]+$/;
88
89
  function isWellKnownPathname(pathname) {
89
90
  return pathname === "/.well-known" || pathname.startsWith("/.well-known/");
90
91
  }
@@ -93,37 +94,32 @@ function isWellKnownPathname(pathname) {
93
94
  *
94
95
  * Public files are checked after middleware and before afterFiles/fallback
95
96
  * rewrites. The generated App Router entry provides the public-file set; this
96
- * helper owns the RSC exclusion, existence-first method enforcement, and
97
+ * helper owns existence-first method enforcement and
97
98
  * static-file signaling. Missing mutation targets continue through routing.
98
99
  */
99
100
  function resolvePublicFileRoute(options) {
100
- if (options.pathname.endsWith(".rsc")) return null;
101
101
  if (!options.publicFiles.has(options.cleanPathname)) return null;
102
102
  if (options.request.method !== "GET" && options.request.method !== "HEAD") return methodNotAllowedResponse("GET, HEAD", { headers: options.middlewareContext.headers ?? void 0 });
103
103
  const { requestHeaders } = options.middlewareContext;
104
104
  return createStaticFileSignal(options.cleanPathname, options.middlewareContext, requestHeaders ? buildRequestHeadersFromMiddlewareResponse(options.request.headers, requestHeaders) : null);
105
105
  }
106
106
  function normalizeTrailingSlashPathname(pathname, trailingSlash) {
107
- if (pathname === "/" || pathname === "/api" || pathname.startsWith("/api/")) return null;
108
- const hasTrailing = pathname.endsWith("/");
107
+ if (pathname === "/") return null;
109
108
  if (trailingSlash) {
110
109
  if (isWellKnownPathname(pathname)) return null;
111
- if (FILE_LIKE_PATHNAME_RE.test(pathname)) {
112
- const normalized = removeTrailingSlash(pathname);
113
- return normalized === pathname ? null : normalized;
114
- }
115
- if (!hasTrailing && !pathname.endsWith(".rsc")) return `${pathname}/`;
110
+ if (SLASHED_FILE_PATHNAME_RE.test(pathname)) return pathname.slice(0, -1);
111
+ if (UNSLASHED_NON_FILE_PATHNAME_RE.test(pathname)) return `${pathname}/`;
116
112
  return null;
117
113
  }
118
- if (hasTrailing) return removeTrailingSlash(pathname);
114
+ if (pathname.endsWith("/")) return removeTrailingSlash(pathname);
119
115
  return null;
120
116
  }
121
117
  /**
122
118
  * Check if the pathname needs a trailing slash redirect, and return the
123
119
  * redirect Response if so.
124
120
  *
125
- * Follows Next.js behavior:
126
- * - `/api` routes are never redirected
121
+ * Follows Next.js behavior, whose internal trailing-slash redirects cover
122
+ * every path, `/api` included:
127
123
  * - The root path `/` is never redirected
128
124
  * - If `trailingSlash` is true, redirect `/about` → `/about/`
129
125
  * - If `trailingSlash` is true, redirect file-looking `/file.ext/` → `/file.ext`
@@ -137,7 +133,7 @@ function normalizeTrailingSlashPathname(pathname, trailingSlash) {
137
133
  * @returns A 308 redirect Response, or null if no redirect is needed
138
134
  */
139
135
  function normalizeTrailingSlash(pathname, basePath, trailingSlash, search) {
140
- if (pathname === "/" || pathname === "/api" || pathname.startsWith("/api/")) return null;
136
+ if (pathname === "/") return null;
141
137
  if (isOpenRedirectShaped(pathname)) return notFoundResponse();
142
138
  const normalizedPathname = normalizeTrailingSlashPathname(pathname, trailingSlash);
143
139
  if (normalizedPathname === null) return null;
@@ -407,6 +403,26 @@ function cloneRequestWithHeaders(request, headers) {
407
403
  }
408
404
  return attachRequestCfMetadata(cloned, request);
409
405
  }
406
+ function haveSameHeaders(first, second) {
407
+ const firstEntries = [...first];
408
+ const secondEntries = [...second];
409
+ return firstEntries.length === secondEntries.length && firstEntries.every(([name, value], index) => name === secondEntries[index]?.[0] && value === secondEntries[index]?.[1]);
410
+ }
411
+ function isNativeRequest(request) {
412
+ try {
413
+ Reflect.get(Request.prototype, "url", request);
414
+ return true;
415
+ } catch {
416
+ return false;
417
+ }
418
+ }
419
+ /**
420
+ * `cloneRequestWithHeaders`, except that a native request whose headers
421
+ * already match is returned as is, so its body stays where it is.
422
+ */
423
+ function withRequestHeaders(request, headers) {
424
+ return isNativeRequest(request) && haveSameHeaders(headers, request.headers) ? request : cloneRequestWithHeaders(request, headers);
425
+ }
410
426
  /**
411
427
  * Clone a Request while overriding the URL, preserving headers and metadata
412
428
  * when possible.
@@ -443,5 +459,17 @@ function cloneRequestWithUrl(request, url) {
443
459
  }
444
460
  return attachRequestCfMetadata(cloned, request);
445
461
  }
462
+ /**
463
+ * Drop a `#fragment` the host kept from the request line. Next.js rebuilds
464
+ * request URLs from pathname + search, so neither middleware nor handlers
465
+ * ever observe one, and pathname-keyed cache entries must not either.
466
+ */
467
+ function stripRequestUrlFragment(request) {
468
+ const hashIndex = request.url.indexOf("#");
469
+ if (hashIndex === -1) return request;
470
+ const signal = request.signal;
471
+ const stripped = cloneRequestWithUrl(request, request.url.slice(0, hashIndex));
472
+ return attachRequestCfMetadata(new Request(stripped, { signal }), request);
473
+ }
446
474
  //#endregion
447
- export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, attachRequestCfMetadata, canonicalizeRequestPathname, canonicalizeRequestUrlPathname, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, dropEmptyMiddlewareSetCookie, filterInternalHeaders, getRepeatedSlashRedirect, guardProtocolRelativeUrl, hasBasePath, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, sendRepeatedSlashRedirect, stripBasePath, validateCsrfOrigin, validateServerActionPayload };
475
+ export { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, attachRequestCfMetadata, canonicalizeRequestPathname, canonicalizeRequestUrlPathname, cloneRequestWithHeaders, cloneRequestWithUrl, createStaticFileSignal, dropEmptyMiddlewareSetCookie, filterInternalHeaders, getRepeatedSlashRedirect, guardProtocolRelativeUrl, hasBasePath, haveSameHeaders, isOpenRedirectShaped, isOriginAllowed, normalizeTrailingSlash, normalizeTrailingSlashPathname, processMiddlewareHeaders, resolvePublicFileRoute, sendRepeatedSlashRedirect, stripBasePath, stripRequestUrlFragment, validateCsrfOrigin, validateServerActionPayload, withRequestHeaders };
@@ -88,9 +88,11 @@ function extractRscCompletionMetadata(buffer) {
88
88
  }
89
89
  function appendRscCompletionMetadata(source, getMetadata) {
90
90
  const reader = source.getReader();
91
+ let cancelled = false;
91
92
  return new ReadableStream({
92
93
  async pull(controller) {
93
94
  const next = await reader.read();
95
+ if (cancelled) return;
94
96
  if (!next.done) {
95
97
  controller.enqueue(escapeFlightChunk(next.value));
96
98
  return;
@@ -100,6 +102,7 @@ function appendRscCompletionMetadata(source, getMetadata) {
100
102
  controller.close();
101
103
  },
102
104
  cancel(reason) {
105
+ cancelled = true;
103
106
  return reader.cancel(reason);
104
107
  }
105
108
  });
@@ -0,0 +1,23 @@
1
+ import { NextI18nConfig } from "../config/next-config.js";
2
+ //#region src/server/shared-cache-identity.d.ts
3
+ /** The core cache identity the configured adapter keys shared dispatches by, if any. */
4
+ export declare function adapterSharedCacheIdentity(): "host-free" | "query-free" | null;
5
+ /** Whether the configured adapter keys shared dispatches by a core cache identity. */
6
+ export declare function adapterUsesSharedCacheIdentity(): boolean;
7
+ /**
8
+ * Whether a Pages page's response is one for every host, as Next.js serves a
9
+ * getStaticProps page and an automatically static page. A page without data
10
+ * functions is rendered per request when its getInitialProps or a custom
11
+ * _app's runs, and may read the host, so it keeps the host in its key.
12
+ */
13
+ export declare function pagesPageSharesAcrossHosts(route: {
14
+ dataKind?: string;
15
+ runsInitialProps?: boolean;
16
+ } | null | undefined): boolean;
17
+ /**
18
+ * The origin a shared Pages page identity names. A static Pages render reads
19
+ * the host only to select a configured i18n domain, so the identity keeps that
20
+ * domain, as vinext's Pages ISR key does, and every other host shares one entry.
21
+ */
22
+ export declare function pagesCacheIdentityOrigin(requestUrl: string, i18nConfig: NextI18nConfig | null | undefined): string;
23
+ //#endregion
@@ -0,0 +1,36 @@
1
+ import { detectDomainLocale, normalizeDomainHostname } from "../utils/domain-locale.js";
2
+ import { getCdnCacheAdapter } from "../shims/cdn-cache.js";
3
+ import { VINEXT_CACHE_IDENTITY_ORIGIN } from "./multi-stage.js";
4
+ //#region src/server/shared-cache-identity.ts
5
+ /** The core cache identity the configured adapter keys shared dispatches by, if any. */
6
+ function adapterSharedCacheIdentity() {
7
+ const adapter = getCdnCacheAdapter();
8
+ if (adapter.requiresCompletedResponseAdmission !== true) return null;
9
+ return adapter.responseStageCacheIdentity ?? null;
10
+ }
11
+ /** Whether the configured adapter keys shared dispatches by a core cache identity. */
12
+ function adapterUsesSharedCacheIdentity() {
13
+ return adapterSharedCacheIdentity() !== null;
14
+ }
15
+ /**
16
+ * Whether a Pages page's response is one for every host, as Next.js serves a
17
+ * getStaticProps page and an automatically static page. A page without data
18
+ * functions is rendered per request when its getInitialProps or a custom
19
+ * _app's runs, and may read the host, so it keeps the host in its key.
20
+ */
21
+ function pagesPageSharesAcrossHosts(route) {
22
+ if (route?.dataKind === "static") return true;
23
+ return route?.dataKind === "none" && route.runsInitialProps !== true;
24
+ }
25
+ /**
26
+ * The origin a shared Pages page identity names. A static Pages render reads
27
+ * the host only to select a configured i18n domain, so the identity keeps that
28
+ * domain, as vinext's Pages ISR key does, and every other host shares one entry.
29
+ */
30
+ function pagesCacheIdentityOrigin(requestUrl, i18nConfig) {
31
+ const domainLocale = detectDomainLocale(i18nConfig?.domains, new URL(requestUrl).hostname);
32
+ if (!domainLocale) return VINEXT_CACHE_IDENTITY_ORIGIN;
33
+ return `${domainLocale.http ? "http" : "https"}://${normalizeDomainHostname(domainLocale.domain)}`;
34
+ }
35
+ //#endregion
36
+ export { adapterSharedCacheIdentity, adapterUsesSharedCacheIdentity, pagesCacheIdentityOrigin, pagesPageSharesAcrossHosts };