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,8 +1,10 @@
1
1
  import { AppMiddlewareContext } from "./app-middleware.js";
2
2
  import { MiddlewareResponseMergeOptions } from "./middleware-response-headers.js";
3
3
  import { EdgeApiExecutionRuntime } from "./edge-api-runtime.js";
4
+ import { RuntimePagesDataKind } from "./pages-route-data-kind.js";
4
5
  //#region src/server/app-pages-bridge.d.ts
5
6
  export type PagesEntry = {
7
+ getRuntimePageDataKind?: (url: string, request: Request) => RuntimePagesDataKind;
6
8
  handleApiRoute?: (request: Request, url: string, ctx: unknown, trustedRevalidateOrigin: string | undefined, edgeRuntime: EdgeApiExecutionRuntime, initialResponseHeaders?: Headers) => Promise<Response> | Response;
7
9
  matchApiRoute?: (url: string, request: Request) => PagesRouteMatch | null;
8
10
  matchPageRoute?: (url: string, request: Request) => PagesRouteMatch | null;
@@ -55,6 +57,8 @@ type RenderPagesFallbackOptions = {
55
57
  pathname?: string;
56
58
  pagesDataRequest?: Request | null;
57
59
  request: Request;
60
+ /** The shared cache entry answers every host; a request-time render is not stored. */
61
+ sharedAcrossHosts?: boolean;
58
62
  url: URL;
59
63
  };
60
64
  /**
@@ -1,6 +1,6 @@
1
1
  import { cloneRequestWithHeaders, cloneRequestWithUrl } from "./request-pipeline.js";
2
2
  import { getRequestExecutionContext } from "../shims/request-context.js";
3
- import { beginRouteCacheability } from "../shims/cacheability-classification.js";
3
+ import { beginRouteCacheability, markRouteCacheabilityDynamic } from "../shims/cacheability-classification.js";
4
4
  import { mergeHeaders } from "./worker-utils.js";
5
5
  import { pagesRouteHasPriorityOverAppRoute } from "./hybrid-route-priority.js";
6
6
  //#region src/server/app-pages-bridge.ts
@@ -18,7 +18,7 @@ function applyPagesMiddlewareContext(response, middlewareContext) {
18
18
  * Fallback handler to route App Router requests to the Pages Router when no App Router route matches.
19
19
  */
20
20
  async function renderPagesFallback(options, dependencies) {
21
- const { allowRscDocumentFallback = false, appRouteMatch = null, isDataRequest = false, isRscRequest, initialResponseHeaders, matchKind, middlewareContext, pathname = options.url.pathname, pagesDataRequest = null, request, url } = options;
21
+ const { allowRscDocumentFallback = false, appRouteMatch = null, isDataRequest = false, isRscRequest, initialResponseHeaders, matchKind, middlewareContext, pathname = options.url.pathname, pagesDataRequest = null, request, sharedAcrossHosts = false, url } = options;
22
22
  const { loadPagesEntry, buildRequestHeaders, applyRouteHandlerMiddlewareContext, getDraftModeCookieHeader } = dependencies;
23
23
  if (isRscRequest && !allowRscDocumentFallback) return null;
24
24
  const pagesEntry = await loadPagesEntry();
@@ -61,7 +61,11 @@ async function renderPagesFallback(options, dependencies) {
61
61
  if (pageMatch !== null && matchKind === "static" && pageMatch.route.isDynamic) return null;
62
62
  if (pageMatch !== null && matchKind === "dynamic" && !pageMatch.route.isDynamic) return null;
63
63
  if (appRouteMatch !== null && (pageMatch === null || !pagesRouteHasPriorityOverAppRoute(pageMatch.route, appRouteMatch.route))) return null;
64
- if (pageMatch !== null) beginRouteCacheability("pages-page", pageMatch.route.pattern);
64
+ if (pageMatch !== null) {
65
+ beginRouteCacheability("pages-page", pageMatch.route.pattern);
66
+ const runtimeDataKind = sharedAcrossHosts ? pagesEntry.getRuntimePageDataKind?.(pagesUrl, matchRequest) : void 0;
67
+ if (runtimeDataKind === "server" || runtimeDataKind === "initial") markRouteCacheabilityDynamic("getInitialProps render shares a cache entry across hosts");
68
+ }
65
69
  const pagesRequest = claimPagesRequest();
66
70
  const renderArgs = [
67
71
  pagesDataRequest ? cloneRequestWithUrl(pagesRequest, pagesDataRequest.url) : pagesRequest,
@@ -17,16 +17,23 @@ export declare function isReactOwnedAppComponent(component: unknown): boolean;
17
17
  * errors this call throws or rejects with.
18
18
  */
19
19
  export declare function invokeAppComponent(component: ComponentType<Record<string, unknown>>, props: Readonly<Record<string, unknown>>, mapError?: (error: unknown) => unknown): ReactNode | Promise<ReactNode>;
20
+ /**
21
+ * Reports how a component's own render ended: `failure` holds what it threw
22
+ * or rejected with, after `mapError`. A suspension isn't an end, as React
23
+ * renders the component again.
24
+ */
25
+ export type AppComponentSettledCallback = (failure?: {
26
+ error: unknown;
27
+ }) => void;
20
28
  /**
21
29
  * `invokeAppComponent()`, with every error the component throws or rejects
22
30
  * with replaced by `mapError(error)`, including its CSS-wrapped inner one's.
31
+ * `onSettled` hears once how the component, or that inner one, ended.
23
32
  */
24
- export declare function invokeAppComponentMappingErrors(component: ComponentType<Record<string, unknown>>, props: Readonly<Record<string, unknown>>, mapError: (error: unknown) => unknown): ReactNode | Promise<ReactNode>;
25
- export declare function registerAppElementRenderDependencies(elements: Readonly<Record<string, unknown>>, dependenciesByElementId: ReadonlyMap<string, AppRenderDependency>): void;
26
- export declare function releaseAppElementRenderDependency(elements: Readonly<Record<string, unknown>>, elementId: string): void;
33
+ export declare function invokeAppComponentMappingErrors(component: ComponentType<Record<string, unknown>>, props: Readonly<Record<string, unknown>>, mapError: (error: unknown) => unknown, onSettled?: AppComponentSettledCallback): ReactNode | Promise<ReactNode>;
27
34
  export declare function createAppRenderDependency(): AppRenderDependency;
28
35
  export declare function createAppPageRenderDependency(): AppPageRenderDependency;
29
36
  export declare function isAppRenderSuspension(error: unknown): boolean;
30
37
  export declare function renderAfterAppDependencies(children: ReactNode, dependencies: readonly AppRenderDependency[]): ReactNode;
31
- export declare function renderAppComponentWithDependencyBarrier(component: ComponentType<Record<string, unknown>>, props: Readonly<Record<string, unknown>>, dependency: AppRenderDependency): ReactNode;
38
+ export declare function renderAppComponentWithDependencyBarrier(component: ComponentType<Record<string, unknown>>, props: Readonly<Record<string, unknown>>, dependency: AppRenderDependency, mapError?: (error: unknown) => unknown, onSettled?: AppComponentSettledCallback): ReactNode;
32
39
  //#endregion
@@ -21,29 +21,74 @@ function isReactOwnedAppComponent(component) {
21
21
  * errors this call throws or rejects with.
22
22
  */
23
23
  function invokeAppComponent(component, props, mapError) {
24
+ return invokeAppComponentObserved(component, props, mapError, void 0);
25
+ }
26
+ /**
27
+ * Like `invokeAppComponent()`. `onSettled` hears of a value returned
28
+ * synchronously; the caller reports a promise result or a thrown error.
29
+ */
30
+ function invokeAppComponentObserved(component, props, mapError, onSettled) {
24
31
  const candidate = component;
25
- if (candidate.$$typeof === REACT_MEMO && candidate.type) return invokeAppComponent(candidate.type, props, mapError);
26
- if (candidate.$$typeof === REACT_LAZY && candidate._init) return invokeAppComponent(candidate._init(candidate._payload), props, mapError);
27
- if (candidate.$$typeof === REACT_FORWARD_REF && candidate.render) return candidate.render(props, void 0);
28
- if (isReactOwnedAppComponent(candidate)) return createElement(candidate, props);
32
+ if (candidate.$$typeof === REACT_MEMO && candidate.type) return invokeAppComponentObserved(candidate.type, props, mapError, onSettled);
33
+ if (candidate.$$typeof === REACT_LAZY && candidate._init) return invokeAppComponentObserved(candidate._init(candidate._payload), props, mapError, onSettled);
34
+ if (candidate.$$typeof === REACT_FORWARD_REF && candidate.render) {
35
+ const result = candidate.render(props, void 0);
36
+ if (!isPromiseLike(result)) onSettled?.();
37
+ return result;
38
+ }
39
+ if (isReactOwnedAppComponent(candidate)) {
40
+ onSettled?.();
41
+ return createElement(candidate, props);
42
+ }
29
43
  const result = candidate(props);
30
- return isPromiseLike(result) ? result : invokeCssWrappedComponent(result, props, mapError);
44
+ return isPromiseLike(result) ? result : invokeCssWrappedComponent(result, props, mapError, onSettled);
31
45
  }
32
46
  /**
33
47
  * `invokeAppComponent()`, with every error the component throws or rejects
34
48
  * with replaced by `mapError(error)`, including its CSS-wrapped inner one's.
49
+ * `onSettled` hears once how the component, or that inner one, ended.
35
50
  */
36
- function invokeAppComponentMappingErrors(component, props, mapError) {
51
+ function invokeAppComponentMappingErrors(component, props, mapError, onSettled) {
52
+ const fail = (error) => {
53
+ if (isAppRenderSuspension(error)) return error;
54
+ const mapped = mapError(error);
55
+ onSettled?.({ error: mapped });
56
+ return mapped;
57
+ };
37
58
  try {
38
- const result = invokeAppComponent(component, props, mapError);
39
- return isPromiseLike(result) ? Promise.resolve(result).catch((error) => {
40
- throw mapError(error);
41
- }) : result;
59
+ const result = invokeAppComponentObserved(component, props, mapError, onSettled);
60
+ return isPromiseLike(result) ? trackAppComponentResult(result, fail, onSettled) : result;
42
61
  } catch (error) {
43
- throw mapError(error);
62
+ throw fail(error);
44
63
  }
45
64
  }
46
65
  /**
66
+ * Records how `result` settles on the promise itself, as React's thenables
67
+ * do, with `fail(error)` as a rejection's reason. Flight then reads that
68
+ * outcome rather than tracking the promise, so the result reaches it in the
69
+ * same tick as an unmapped one. A promise chained with `.then()` resolves a
70
+ * tick later, which costs a large page about a tenth more render work.
71
+ */
72
+ function trackAppComponentResult(result, fail, onSettled) {
73
+ const thenable = result;
74
+ if (thenable.status !== void 0) return Promise.resolve(result).then((value) => {
75
+ onSettled?.();
76
+ return value;
77
+ }, (error) => {
78
+ throw fail(error);
79
+ });
80
+ thenable.status = "pending";
81
+ thenable.then((value) => {
82
+ thenable.status = "fulfilled";
83
+ thenable.value = value;
84
+ onSettled?.();
85
+ }, (error) => {
86
+ thenable.status = "rejected";
87
+ thenable.reason = fail(error);
88
+ });
89
+ return thenable;
90
+ }
91
+ /**
47
92
  * Whether `elementProps` are what `createElement(type, props)` produces: the
48
93
  * same values, plus any `type.defaultProps` for keys that are `undefined`.
49
94
  * Defaulted values aren't read again, since a default can be a getter.
@@ -67,28 +112,33 @@ function isElementOfProps(elementProps, props, defaultProps) {
67
112
  * component from an element without props instead, as for an export without
68
113
  * CSS.
69
114
  */
70
- function invokeCssWrappedComponent(result, props, mapError) {
71
- if (!isValidElement(result) || result.type !== Fragment || result.key !== null) return result;
72
- const children = result.props.children;
73
- if (!Array.isArray(children) || children.length !== 2) return result;
74
- const [css, inner] = children;
75
- if (!isValidElement(inner) || typeof inner.type !== "function" || inner.key !== null) return result;
76
- const component = inner.type;
77
- if (!isElementOfProps(inner.props, props, component.defaultProps)) return result;
78
- const componentProps = inner.props;
115
+ function invokeCssWrappedComponent(result, props, mapError, onSettled) {
116
+ const wrapped = readCssWrappedComponent(result, props);
117
+ if (!wrapped) {
118
+ onSettled?.();
119
+ return result;
120
+ }
121
+ const { component, componentProps, css } = wrapped;
79
122
  function CssWrappedComponent() {
80
- return mapError ? invokeAppComponentMappingErrors(component, componentProps, mapError) : invokeAppComponent(component, componentProps);
123
+ return mapError ? invokeAppComponentMappingErrors(component, componentProps, mapError, onSettled) : invokeAppComponent(component, componentProps);
81
124
  }
82
125
  CssWrappedComponent.displayName = component.displayName ?? component.name;
83
126
  return createElement(Fragment, null, css, createElement(CssWrappedComponent));
84
127
  }
85
- const appElementRenderDependencies = /* @__PURE__ */ new WeakMap();
86
- function registerAppElementRenderDependencies(elements, dependenciesByElementId) {
87
- if (dependenciesByElementId.size === 0) return;
88
- appElementRenderDependencies.set(elements, dependenciesByElementId);
89
- }
90
- function releaseAppElementRenderDependency(elements, elementId) {
91
- appElementRenderDependencies.get(elements)?.get(elementId)?.release();
128
+ /** The parts of `result`, if it's a CSS-wrapped export's element for `props`. */
129
+ function readCssWrappedComponent(result, props) {
130
+ if (!isValidElement(result) || result.type !== Fragment || result.key !== null) return null;
131
+ const children = result.props.children;
132
+ if (!Array.isArray(children) || children.length !== 2) return null;
133
+ const [css, inner] = children;
134
+ if (!isValidElement(inner) || typeof inner.type !== "function" || inner.key !== null) return null;
135
+ const component = inner.type;
136
+ if (!isElementOfProps(inner.props, props, component.defaultProps)) return null;
137
+ return {
138
+ component,
139
+ componentProps: inner.props,
140
+ css
141
+ };
92
142
  }
93
143
  function createAppRenderDependency() {
94
144
  let released = false;
@@ -130,17 +180,15 @@ function renderAfterAppDependencies(children, dependencies) {
130
180
  }
131
181
  return /* @__PURE__ */ jsx(AwaitAppRenderDependencies, {});
132
182
  }
133
- function renderAppComponentWithDependencyBarrier(component, props, dependency) {
183
+ function renderAppComponentWithDependencyBarrier(component, props, dependency, mapError, onSettled) {
134
184
  function AppComponentDependencyBarrier() {
135
185
  try {
136
- const result = invokeAppComponent(component, props);
137
- if (isPromiseLike(result)) return Promise.resolve(result).then((resolvedResult) => {
138
- dependency.release();
139
- return resolvedResult;
140
- }, (error) => {
141
- dependency.release();
142
- throw error;
143
- });
186
+ const result = mapError ? invokeAppComponentMappingErrors(component, props, mapError, onSettled) : invokeAppComponent(component, props);
187
+ if (isPromiseLike(result)) {
188
+ const release = () => dependency.release();
189
+ result.then(release, release);
190
+ return result;
191
+ }
144
192
  dependency.release();
145
193
  return result;
146
194
  } catch (error) {
@@ -151,4 +199,4 @@ function renderAppComponentWithDependencyBarrier(component, props, dependency) {
151
199
  return createElement(AppComponentDependencyBarrier);
152
200
  }
153
201
  //#endregion
154
- export { createAppPageRenderDependency, createAppRenderDependency, invokeAppComponent, invokeAppComponentMappingErrors, isAppClientReference, isAppRenderSuspension, isReactOwnedAppComponent, registerAppElementRenderDependencies, releaseAppElementRenderDependency, renderAfterAppDependencies, renderAppComponentWithDependencyBarrier };
202
+ export { createAppPageRenderDependency, createAppRenderDependency, invokeAppComponent, invokeAppComponentMappingErrors, isAppClientReference, isAppRenderSuspension, isReactOwnedAppComponent, renderAfterAppDependencies, renderAppComponentWithDependencyBarrier };
@@ -44,7 +44,7 @@ async function dispatchAppRequestStage(request, ctx, dispatchResponseStage, opti
44
44
  headRequest,
45
45
  middlewareCookieOverlay: null,
46
46
  prerenderDiscovery: options.prerenderDiscovery,
47
- protocolVersion: 11,
47
+ protocolVersion: 13,
48
48
  requestOrigin: new URL(request.url).origin,
49
49
  scriptNonce: null,
50
50
  staticFileSignalToken,
@@ -32,7 +32,7 @@ function handleRequestStage(request, env, ctx, dispatchResponseStage) {
32
32
  callback: () => handleRequest(request, env, ctx, dispatchResponseStage, ctx?.assets).then((response) => applyCdnResponseIdentityHeaders(response, originalRequest)),
33
33
  getStatus: (response) => response?.status,
34
34
  headers: request.headers,
35
- isRsc: url.pathname.endsWith(".rsc") || request.headers.get("RSC") === "1",
35
+ isRsc: request.headers.get("RSC") === "1",
36
36
  method: request.method,
37
37
  target: url.pathname + url.search
38
38
  });
@@ -1,6 +1,6 @@
1
1
  import { isrCacheControl, resolveRouteExpireSeconds } from "./isr-cache.js";
2
- import { makeThenableParams } from "../shims/thenable-params.js";
3
2
  import { applyRouteHandlerMiddlewareContext, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, buildRouteHandlerCachedResponse } from "./app-route-handler-response.js";
3
+ import { makeThenableParams } from "../shims/thenable-params.js";
4
4
  import { markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
5
5
  import { resolveAppRouteHandlerSpecialError } from "./app-route-handler-policy.js";
6
6
  import { completeAppRouteHandlerResponse, runAppRouteHandler, traceAppRouteHandlerExecution } from "./app-route-handler-execution.js";
@@ -57,7 +57,7 @@ async function readAppRouteHandlerCacheResponse(options) {
57
57
  setHeadersAccessPhase: options.setHeadersAccessPhase
58
58
  }) };
59
59
  } catch (error) {
60
- if (resolveAppRouteHandlerSpecialError(error, options.requestUrl)) return { specialError: error };
60
+ if (resolveAppRouteHandlerSpecialError(error)) return { specialError: error };
61
61
  throw error;
62
62
  }
63
63
  });
@@ -1,21 +1,22 @@
1
1
  import { closeAfterResponse, createRequestContext, getRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
2
- import "../utils/protocol-headers.js";
2
+ import { PRERENDER_REVALIDATE_HEADER } from "../utils/protocol-headers.js";
3
3
  import { getRequestExecutionContext } from "../shims/request-context.js";
4
4
  import { runInWorkStoreScope } from "../shims/internal/work-store-scope.js";
5
5
  import { reportRequestError } from "./instrumentation.js";
6
6
  import { beginRouteCacheability, getRouteCacheabilityDynamicReason } from "../shims/cacheability-classification.js";
7
7
  import { applyCdnResponseBuildIdentityHeaders } from "./cache-control.js";
8
8
  import { isOnDemandRevalidateRequest } from "./revalidation-request.js";
9
+ import { coalesceOnDemandResponse } from "./isr-cache.js";
9
10
  import { markDynamicUsage } from "../shims/internal/headers-state.js";
10
11
  import { consumeDynamicUsage, getActiveDraftModeState, getAndClearPendingCookies, getDraftModeCookieHeader, isDraftModeRequest, setHeadersAccessPhase } from "../shims/headers.js";
11
12
  import { _drainPendingRevalidations } from "../shims/cache-request-state.js";
12
13
  import { ensureFetchPatch, getCollectedFetchTags, setCurrentFetchCacheMode, setCurrentFetchRevalidate, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault } from "../shims/fetch-cache.js";
13
14
  import { resolveAppRouteHandlerFetchCacheMode } from "./app-segment-config.js";
14
- import { setNavigationContext } from "../shims/navigation-context-state.js";
15
- import { makeThenableParams } from "../shims/thenable-params.js";
16
15
  import { traceResponseStart } from "./response-start-tracing.js";
17
16
  import { applyRouteHandlerMiddlewareContext, finalizeRouteHandlerResponse } from "./app-route-handler-response.js";
17
+ import { setNavigationContext } from "../shims/navigation-context-state.js";
18
18
  import "../shims/navigation.js";
19
+ import { makeThenableParams } from "../shims/thenable-params.js";
19
20
  import { buildPageCacheTags } from "./implicit-tags.js";
20
21
  import { isKnownDynamicAppRoute, isValidHTTPMethod } from "./app-route-handler-runtime.js";
21
22
  import { getAppRouteHandlerRevalidateSeconds, hasAppRouteHandlerDefaultExport, hasNonStaticAppRouteHandlerMethods, resolveAppRouteHandlerMethod, shouldReadAppRouteHandlerCache } from "./app-route-handler-policy.js";
@@ -94,7 +95,8 @@ async function dispatchAppRouteHandlerImpl(options) {
94
95
  headers: { Allow: allowHeaderForOptions }
95
96
  }));
96
97
  const resolvedHandlerFn = isAppRouteHandlerFunction(handlerFn) ? handlerFn : void 0;
97
- const shouldReadRouteCache = options.bypassSharedCache !== true && revalidateSeconds !== null && !getRouteCacheabilityDynamicReason() && shouldReadAppRouteHandlerCache({
98
+ const isOnDemandRevalidate = isOnDemandRevalidateRequest(options.request.headers.get(PRERENDER_REVALIDATE_HEADER));
99
+ const isStoredRoute = options.bypassSharedCache !== true && revalidateSeconds !== null && !getRouteCacheabilityDynamicReason() && shouldReadAppRouteHandlerCache({
98
100
  dynamicConfig: handler.dynamic,
99
101
  handlerFn: resolvedHandlerFn,
100
102
  isAutoHead,
@@ -104,12 +106,13 @@ async function dispatchAppRouteHandlerImpl(options) {
104
106
  method,
105
107
  revalidateSeconds
106
108
  });
107
- const revalidateReason = isOnDemandRevalidateRequest(options.request.headers.get("x-prerender-revalidate")) ? "on-demand" : shouldReadRouteCache && revalidateSeconds !== Infinity ? "stale" : void 0;
109
+ const shouldReadRouteCache = isStoredRoute && !isOnDemandRevalidate;
110
+ const revalidateReason = isOnDemandRevalidate ? "on-demand" : shouldReadRouteCache && revalidateSeconds !== Infinity ? "stale" : void 0;
108
111
  const fetchCacheMode = resolveAppRouteHandlerFetchCacheMode(handler);
109
112
  setCurrentFetchCacheMode(fetchCacheMode);
110
113
  setCurrentFetchRevalidate(configuredRevalidateSeconds);
111
114
  setCurrentForceDynamicFetchDefault(handler.dynamic === "force-dynamic");
112
- let isRevalidation = false;
115
+ let isRevalidation = isStoredRoute && isOnDemandRevalidate;
113
116
  if (shouldReadRouteCache && resolvedHandlerFn) {
114
117
  const cachedRouteResponse = await readAppRouteHandlerCacheResponse({
115
118
  basePath: options.basePath,
@@ -167,7 +170,7 @@ async function dispatchAppRouteHandlerImpl(options) {
167
170
  if (cachedRouteResponse) return applyCdnResponseBuildIdentityHeaders(cachedRouteResponse);
168
171
  }
169
172
  if (resolvedHandlerFn) {
170
- const response = await executeAppRouteHandler({
173
+ const handlerOptions = {
171
174
  isRevalidation,
172
175
  basePath: options.basePath,
173
176
  bypassSharedCache: options.bypassSharedCache,
@@ -210,8 +213,10 @@ async function dispatchAppRouteHandlerImpl(options) {
210
213
  revalidateReason,
211
214
  routePattern: route.pattern,
212
215
  setHeadersAccessPhase
213
- });
214
- return applyCdnResponseBuildIdentityHeaders(response);
216
+ };
217
+ const runHandler = async () => applyCdnResponseBuildIdentityHeaders(await executeAppRouteHandler(handlerOptions));
218
+ if (isOnDemandRevalidate && isStoredRoute) return coalesceOnDemandResponse(`${method}:${options.isrRouteKey(options.cleanPathname)}`, method, runHandler);
219
+ return runHandler();
215
220
  }
216
221
  return finalizeFrameworkResponse(new Response(null, { status: 405 }));
217
222
  }
@@ -1,6 +1,7 @@
1
1
  import { isFullyBufferedBody } from "./fully-buffered-response.js";
2
2
  import { patternToNextFormat } from "../routing/route-validation.js";
3
3
  import { frameworkTracer } from "./tracer.js";
4
+ import { logRequestError } from "./request-error-log.js";
4
5
  import { getRouteCacheabilityCaptureOptions, getRouteCacheabilityDynamicReason, isRouteCacheabilityEvaluation, markRouteCacheabilityExplicitResponsePolicy, markRouteCacheabilityResponseBodyComplete, recordRouteCacheability } from "../shims/cacheability-classification.js";
5
6
  import { NEVER_CACHE_CONTROL, applyCdnResponseHeaders, hasCdnResponsePolicy, hasExplicitNonCacheableResponsePolicy } from "./cache-control.js";
6
7
  import { buildAppRouteMissIsrCacheControl } from "./isr-decision.js";
@@ -117,7 +118,7 @@ async function runAppRouteHandler(options) {
117
118
  onDynamicAccess() {
118
119
  options.markDynamicUsage();
119
120
  },
120
- requestMode: options.dynamicConfig === "force-static" || options.dynamicConfig === "error" ? options.dynamicConfig : "auto",
121
+ requestMode: options.dynamicConfig === "force-dynamic" || options.dynamicConfig === "force-static" || options.dynamicConfig === "error" ? options.dynamicConfig : "auto",
121
122
  signal: options.requestSignal,
122
123
  staticGenerationErrorMessage(expression) {
123
124
  return getAppRouteStaticGenerationErrorMessage(options.routePattern, expression);
@@ -167,7 +168,7 @@ async function executeAppRouteHandlerImpl(options) {
167
168
  })
168
169
  };
169
170
  } catch (error) {
170
- if (resolveAppRouteHandlerSpecialError(error, options.request.url, { isAction: isPossibleAppRouteActionRequest(options.request) })) return {
171
+ if (resolveAppRouteHandlerSpecialError(error, { isAction: isPossibleAppRouteActionRequest(options.request) })) return {
171
172
  kind: "special",
172
173
  error
173
174
  };
@@ -284,7 +285,8 @@ async function executeAppRouteHandlerImpl(options) {
284
285
  console.error("[vinext] ISR route cache write error:", cacheErr);
285
286
  }
286
287
  })();
287
- options.executionContext?.waitUntil(routeWritePromise);
288
+ if (options.revalidateReason === "on-demand") await routeWritePromise;
289
+ else options.executionContext?.waitUntil(routeWritePromise);
288
290
  }
289
291
  let finalized = applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(finalizeRouteHandlerResponse(response, {
290
292
  pendingCookies,
@@ -321,7 +323,11 @@ async function executeAppRouteHandlerImpl(options) {
321
323
  const draftCookie = handlerDraftCookie ?? options.initialDraftModeCookie;
322
324
  const shouldApplyDraftPolicy = (options.getActiveDraftModeState?.() ?? options.isDraftMode === true) || draftCookie != null;
323
325
  if (handlerDraftCookie != null) markKnownDynamicAppRoute(options.routePattern);
324
- const specialError = resolveAppRouteHandlerSpecialError(error, options.request.url, { isAction: isPossibleAppRouteActionRequest(options.request) });
326
+ const specialError = resolveAppRouteHandlerSpecialError(error, { isAction: isPossibleAppRouteActionRequest(options.request) });
327
+ if (specialError && options.consumeDynamicUsage()) recordRouteCacheability({
328
+ cacheable: false,
329
+ dynamicUsage: true
330
+ });
325
331
  options.clearRequestContext();
326
332
  if (specialError) {
327
333
  if (specialError.kind === "redirect") return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(finalizeRouteHandlerResponse(new Response(null, {
@@ -334,7 +340,7 @@ async function executeAppRouteHandlerImpl(options) {
334
340
  }), options.middlewareContext, middlewareMergeOptions), shouldApplyDraftPolicy);
335
341
  return applyDraftModeCachePolicy(applyRouteHandlerMiddlewareContext(new Response(null, { status: specialError.statusCode }), options.middlewareContext, middlewareMergeOptions), shouldApplyDraftPolicy);
336
342
  }
337
- console.error("[vinext] Route handler error:", error);
343
+ logRequestError("[vinext] Route handler error:", error);
338
344
  await options.reportRequestError(error, {
339
345
  path: options.cleanPathname,
340
346
  method: options.request.method,
@@ -64,6 +64,6 @@ export declare function shouldApplyAppRouteHandlerRevalidateHeader(options: Omit
64
64
  */
65
65
  export declare function shouldCompleteAppRouteHandlerResponse(options: AppRouteHandlerResponseCacheOptions): boolean;
66
66
  export declare function shouldWriteAppRouteHandlerCache(options: AppRouteHandlerResponseCacheOptions): boolean;
67
- export declare function resolveAppRouteHandlerSpecialError(error: unknown, requestUrl: string, options?: AppRouteHandlerSpecialErrorOptions): AppRouteHandlerSpecialError | null;
67
+ export declare function resolveAppRouteHandlerSpecialError(error: unknown, options?: AppRouteHandlerSpecialErrorOptions): AppRouteHandlerSpecialError | null;
68
68
  //#endregion
69
69
  export { isPossibleAppRouteActionRequest };
@@ -1,5 +1,5 @@
1
- import { parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
2
1
  import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
2
+ import { parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
3
3
  import { buildRouteHandlerAllowHeader, collectRouteHandlerMethods } from "./app-route-handler-runtime.js";
4
4
  //#region src/server/app-route-handler-policy.ts
5
5
  function getAppRouteHandlerRevalidateSeconds(handler) {
@@ -53,13 +53,13 @@ function shouldCompleteAppRouteHandlerResponse(options) {
53
53
  function shouldWriteAppRouteHandlerCache(options) {
54
54
  return options.isProduction && options.revalidateSeconds !== null && options.revalidateSeconds > 0 && options.dynamicConfig !== "force-dynamic" && !options.isDraftMode && !options.dynamicUsedInHandler && (options.method === "GET" || options.isAutoHead);
55
55
  }
56
- function resolveAppRouteHandlerSpecialError(error, requestUrl, options) {
56
+ function resolveAppRouteHandlerSpecialError(error, options) {
57
57
  if (!(error && typeof error === "object" && "digest" in error)) return null;
58
58
  const digest = String(error.digest);
59
59
  const redirect = parseNextRedirectDigest(digest);
60
60
  if (redirect) return {
61
61
  kind: "redirect",
62
- location: new URL(redirect.url, requestUrl).toString(),
62
+ location: redirect.url,
63
63
  statusCode: options?.isAction ? 303 : redirect.status
64
64
  };
65
65
  const httpError = parseNextHttpErrorDigest(digest);
@@ -5,8 +5,8 @@ import { markRouteCacheabilityExplicitResponsePolicy, recordRouteCacheability }
5
5
  import { applyCdnResponseHeaders } from "./cache-control.js";
6
6
  import { buildAppRouteMissIsrCacheControl, decideIsr } from "./isr-decision.js";
7
7
  import { setCacheStateHeaders } from "./cache-headers.js";
8
- import { mergeMiddlewareResponseHeadersOntoResponse } from "./middleware-response-headers.js";
9
8
  import { markEdgeRouteHandlerLinkHeaders } from "./app-response-header-provenance.js";
9
+ import { mergeMiddlewareResponseHeadersOntoResponse } from "./middleware-response-headers.js";
10
10
  import { getSetCookieName } from "./cookie-utils.js";
11
11
  //#region src/server/app-route-handler-response.ts
12
12
  const APP_ROUTE_REWRITE_ERROR = "NextResponse.rewrite() was used in a app route handler, this is not currently supported. Please remove the invocation to continue.";
@@ -21,7 +21,7 @@ type NextUrlDynamicAccess = "nextUrl.search" | "nextUrl.searchParams" | "nextUrl
21
21
  type HostDerivedNextUrlDynamicAccess = "nextUrl.protocol" | "nextUrl.username" | "nextUrl.password" | "nextUrl.host" | "nextUrl.hostname" | "nextUrl.port" | DomainLocaleNextUrlDynamicAccess;
22
22
  type DomainLocaleNextUrlDynamicAccess = "nextUrl.locale" | "nextUrl.defaultLocale" | "nextUrl.domainLocale";
23
23
  type AppRouteDynamicRequestAccess = RequestDynamicAccess | NextUrlDynamicAccess;
24
- type AppRouteRequestMode = "auto" | "force-static" | "error";
24
+ type AppRouteRequestMode = "auto" | "force-dynamic" | "force-static" | "error";
25
25
  type TrackedAppRouteRequestOptions = {
26
26
  basePath?: string;
27
27
  i18n?: NextI18nConfig | null;
@@ -2,6 +2,7 @@ import { buildRequestHeadersFromMiddlewareResponse } from "../utils/middleware-r
2
2
  import { addBasePathToPathname } from "../utils/base-path.js";
3
3
  import { cloneRequestWithHeaders, cloneRequestWithUrl } from "./request-pipeline.js";
4
4
  import { NextRequest, RequestCookies, sealRequestCookies, sealRequestHeaders } from "../shims/server.js";
5
+ import { throwIfInsideCacheScope } from "../shims/internal/headers-state.js";
5
6
  import { BUILT_IN_REQUEST_PROPERTIES } from "./app-route-request-built-ins.js";
6
7
  //#region src/server/app-route-handler-runtime.ts
7
8
  const BUILT_IN_REQUEST_PROPERTY_MAP = new Map(BUILT_IN_REQUEST_PROPERTIES.map((property) => [property.key, property]));
@@ -76,8 +77,14 @@ function buildNextConfig(options) {
76
77
  * Undici's Request follows its input's signal through a WeakRef, and so does
77
78
  * every clone between the host signal and the handler's request. A handler
78
79
  * that only listens on `request.signal` (e.g. to stop a stream) would miss the
79
- * abort once GC collects any of them, so the request follows the host signal
80
- * directly and stays reachable for as long as that signal is.
80
+ * abort once GC collects any of them, so the request stays reachable for as
81
+ * long as the host signal is.
82
+ *
83
+ * The request must not follow the host signal itself, though. Undici registers
84
+ * every Request in a FinalizationRegistry whose held value strongly references
85
+ * the followed signal, so the registry would keep the host signal (the WeakMap
86
+ * key) and therefore the request alive forever. It follows a relay instead,
87
+ * which the host signal aborts through a strong listener.
81
88
  */
82
89
  const requestsByHostSignal = /* @__PURE__ */ new WeakMap();
83
90
  function retainWhileSignalLives(signal, request) {
@@ -85,6 +92,12 @@ function retainWhileSignalLives(signal, request) {
85
92
  if (requests) requests.push(request);
86
93
  else requestsByHostSignal.set(signal, [request]);
87
94
  }
95
+ function followHostSignal(signal) {
96
+ const relay = new AbortController();
97
+ if (signal.aborted) relay.abort(signal.reason);
98
+ else signal.addEventListener("abort", () => relay.abort(signal.reason), { once: true });
99
+ return relay.signal;
100
+ }
88
101
  function createForceStaticNextRequest(input, nextConfig, signal) {
89
102
  const read = (key) => {
90
103
  const descriptor = BUILT_IN_REQUEST_PROPERTY_MAP.get(key)?.descriptor;
@@ -138,7 +151,8 @@ function createTrackedAppRouteRequest(request, options = {}) {
138
151
  let didAccessDynamicRequest = false;
139
152
  const requestMode = options.requestMode ?? "auto";
140
153
  const nextConfig = buildNextConfig(options);
141
- const markDynamicAccess = (access) => {
154
+ const markDynamicAccess = (access, trackedByNext) => {
155
+ if (trackedByNext && requestMode !== "force-dynamic") throwIfInsideCacheScope(access);
142
156
  didAccessDynamicRequest = true;
143
157
  options.onDynamicAccess?.(access);
144
158
  };
@@ -172,7 +186,7 @@ function createTrackedAppRouteRequest(request, options = {}) {
172
186
  const wrapNextUrl = (nextUrl) => {
173
187
  return new Proxy(nextUrl, { get(target, prop) {
174
188
  if (isNextDynamicNextUrlProperty(prop) || isHostDerivedNextUrlProperty(prop)) {
175
- markDynamicAccess(`nextUrl.${String(prop)}`);
189
+ markDynamicAccess(`nextUrl.${String(prop)}`, isNextDynamicNextUrlProperty(prop));
176
190
  return bindMethodIfNeeded(Reflect.get(target, prop, target), target);
177
191
  }
178
192
  if (prop === "clone") return () => wrapNextUrl(target.clone());
@@ -228,9 +242,10 @@ function createTrackedAppRouteRequest(request, options = {}) {
228
242
  const sourceCfDescriptor = Reflect.getOwnPropertyDescriptor(requestWithOverrides, "cf");
229
243
  const sourceCfAccessor = sourceCfDescriptor?.get;
230
244
  const sourceCfMetadata = sourceCfAccessor ? void 0 : Reflect.get(requestWithOverrides, "cf", requestWithOverrides);
231
- const nextRequest = requestMode === "force-static" ? createForceStaticNextRequest(requestWithOverrides, nextConfig, options.signal) : requestWithOverrides instanceof NextRequest && sourceCfDescriptor?.configurable !== false && !options.signal ? requestWithOverrides : new NextRequest(requestWithOverrides, {
245
+ const signal = options.signal ? followHostSignal(options.signal) : void 0;
246
+ const nextRequest = requestMode === "force-static" ? createForceStaticNextRequest(requestWithOverrides, nextConfig, signal) : requestWithOverrides instanceof NextRequest && sourceCfDescriptor?.configurable !== false && !signal ? requestWithOverrides : new NextRequest(requestWithOverrides, {
232
247
  nextConfig: nextConfig ?? void 0,
233
- signal: options.signal
248
+ signal
234
249
  });
235
250
  if (options.signal) retainWhileSignalLives(options.signal, nextRequest);
236
251
  const rawCfMetadata = sourceCfAccessor ? void 0 : sourceCfMetadata === void 0 ? Reflect.get(nextRequest, "cf", nextRequest) : sourceCfMetadata;
@@ -239,7 +254,7 @@ function createTrackedAppRouteRequest(request, options = {}) {
239
254
  const accessCf = (read, forceStaticValue) => {
240
255
  if (requestMode === "force-static") return forceStaticValue;
241
256
  if (requestMode === "error") return throwStaticGenerationError("request.cf");
242
- markDynamicAccess("request.cf");
257
+ markDynamicAccess("request.cf", false);
243
258
  return read();
244
259
  };
245
260
  const controlledCfGetter = () => accessCf(sourceCfAccessor ? () => Reflect.apply(sourceCfAccessor, requestWithOverrides, []) : () => rawCfMetadata, void 0);
@@ -341,17 +356,19 @@ function createTrackedAppRouteRequest(request, options = {}) {
341
356
  return proxiedNextUrl;
342
357
  case "headers":
343
358
  case "cookies":
344
- case "ip":
345
- case "geo":
346
359
  case "url":
347
360
  case "body":
348
361
  case "blob":
349
- case "bytes":
350
362
  case "json":
351
363
  case "text":
352
364
  case "arrayBuffer":
353
365
  case "formData":
354
- markDynamicAccess(`request.${String(prop)}`);
366
+ markDynamicAccess(`request.${String(prop)}`, true);
367
+ return bindMethodIfNeeded(Reflect.get(target, prop, target), target);
368
+ case "ip":
369
+ case "geo":
370
+ case "bytes":
371
+ markDynamicAccess(`request.${String(prop)}`, false);
355
372
  return bindMethodIfNeeded(Reflect.get(target, prop, target), target);
356
373
  case "clone": return cloneTrackedRequest;
357
374
  default: return getTrackedRequestProperty(target, prop, receiver);
@@ -37,7 +37,7 @@ var app_router_entry_default = {
37
37
  callback: async () => applyCdnResponseIdentityHeaders(await handleRequest(request, env, ctx), request),
38
38
  getStatus: (response) => response?.status,
39
39
  headers: request.headers,
40
- isRsc: url.pathname.endsWith(".rsc") || request.headers.get("RSC") === "1",
40
+ isRsc: request.headers.get("RSC") === "1",
41
41
  method: request.method,
42
42
  target: url.pathname + url.search
43
43
  });