vinext 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/README.md +13 -10
  2. package/dist/build/client-build-config.d.ts +64 -3
  3. package/dist/build/client-build-config.js +131 -4
  4. package/dist/build/client-reference-groups.d.ts +163 -0
  5. package/dist/build/client-reference-groups.js +534 -0
  6. package/dist/build/module-dependency-cache.d.ts +31 -0
  7. package/dist/build/module-dependency-cache.js +51 -1
  8. package/dist/build/next-client-runtime-manifests.d.ts +10 -1
  9. package/dist/build/next-client-runtime-manifests.js +19 -4
  10. package/dist/build/nitro-public-files.d.ts +24 -0
  11. package/dist/build/nitro-public-files.js +60 -0
  12. package/dist/build/output-root-externals.d.ts +21 -0
  13. package/dist/build/output-root-externals.js +40 -0
  14. package/dist/build/pages-client-assets-module.js +1 -1
  15. package/dist/build/prerender-paths.js +6 -3
  16. package/dist/build/prerender.js +1 -1
  17. package/dist/build/server-actions-encryption-key.d.ts +23 -0
  18. package/dist/build/server-actions-encryption-key.js +101 -0
  19. package/dist/build/ssr-manifest.d.ts +3 -0
  20. package/dist/build/ssr-manifest.js +10 -1
  21. package/dist/check.js +5 -6
  22. package/dist/cli-dev-config.js +3 -3
  23. package/dist/cli.js +1 -1
  24. package/dist/client/client-rewrite-params.d.ts +9 -0
  25. package/dist/client/client-rewrite-params.js +20 -0
  26. package/dist/client/dev-error-overlay.js +2 -1
  27. package/dist/client/navigation-runtime.d.ts +25 -2
  28. package/dist/client/navigation-runtime.js +42 -11
  29. package/dist/client/vinext-next-data.d.ts +0 -1
  30. package/dist/config/config-matchers.d.ts +15 -40
  31. package/dist/config/config-matchers.js +195 -262
  32. package/dist/config/config-source.d.ts +34 -0
  33. package/dist/config/config-source.js +141 -0
  34. package/dist/config/header-params.d.ts +29 -0
  35. package/dist/config/header-params.js +106 -0
  36. package/dist/config/next-config.d.ts +7 -5
  37. package/dist/config/next-config.js +120 -7
  38. package/dist/entries/app-browser-entry.d.ts +14 -1
  39. package/dist/entries/app-browser-entry.js +26 -36
  40. package/dist/entries/app-rsc-entry.d.ts +2 -0
  41. package/dist/entries/app-rsc-entry.js +92 -57
  42. package/dist/entries/app-rsc-manifest.d.ts +10 -0
  43. package/dist/entries/app-rsc-manifest.js +20 -1
  44. package/dist/entries/app-ssr-entry.d.ts +4 -1
  45. package/dist/entries/app-ssr-entry.js +9 -2
  46. package/dist/entries/pages-client-entry.d.ts +1 -0
  47. package/dist/entries/pages-client-entry.js +6 -6
  48. package/dist/entries/pages-server-entry.js +17 -14
  49. package/dist/index.d.ts +11 -0
  50. package/dist/index.js +350 -175
  51. package/dist/init.d.ts +1 -1
  52. package/dist/init.js +103 -6
  53. package/dist/plugins/ast-utils.d.ts +53 -2
  54. package/dist/plugins/ast-utils.js +90 -2
  55. package/dist/plugins/cloudflare-dev-module-urls.d.ts +41 -0
  56. package/dist/plugins/cloudflare-dev-module-urls.js +271 -0
  57. package/dist/plugins/commonjs-esm-facade.js +2 -2
  58. package/dist/plugins/css-module-imports.js +13 -20
  59. package/dist/plugins/dynamic-preload-metadata.js +2 -3
  60. package/dist/plugins/extensionless-dynamic-import.js +2 -3
  61. package/dist/plugins/fonts.d.ts +1 -1
  62. package/dist/plugins/fonts.js +3 -3
  63. package/dist/plugins/ignore-dynamic-requests.js +2 -3
  64. package/dist/plugins/import-meta-url.js +3 -4
  65. package/dist/plugins/instrumentation-client.js +3 -2
  66. package/dist/plugins/middleware-export-validation.js +2 -3
  67. package/dist/plugins/og-harfbuzz.js +2 -3
  68. package/dist/plugins/optimize-imports.d.ts +25 -2
  69. package/dist/plugins/optimize-imports.js +109 -24
  70. package/dist/plugins/pages-node-externals.js +2 -3
  71. package/dist/plugins/remove-console.js +2 -18
  72. package/dist/plugins/require-condition-resolution.js +3 -3
  73. package/dist/plugins/require-context.js +2 -3
  74. package/dist/plugins/rsc-client-reference-loaders.d.ts +45 -1
  75. package/dist/plugins/rsc-client-reference-loaders.js +336 -18
  76. package/dist/plugins/strip-server-exports.js +3 -4
  77. package/dist/plugins/styled-jsx.js +2 -3
  78. package/dist/plugins/use-cache-callable.d.ts +26 -2
  79. package/dist/plugins/use-cache-callable.js +101 -36
  80. package/dist/plugins/worker-image-imports.d.ts +1 -0
  81. package/dist/plugins/worker-image-imports.js +31 -34
  82. package/dist/plugins/worker-use-server.js +38 -14
  83. package/dist/routing/app-route-graph.d.ts +1 -1
  84. package/dist/routing/browser-route-manifest.d.ts +43 -0
  85. package/dist/routing/browser-route-manifest.js +195 -0
  86. package/dist/routing/hashed-route-patterns.d.ts +4 -0
  87. package/dist/routing/hashed-route-patterns.js +22 -0
  88. package/dist/routing/optimistic-route-trie.d.ts +27 -0
  89. package/dist/routing/optimistic-route-trie.js +102 -0
  90. package/dist/routing/route-validation.d.ts +6 -1
  91. package/dist/routing/route-validation.js +26 -10
  92. package/dist/server/api-handler.js +1 -1
  93. package/dist/server/app-action-forwarding.d.ts +8 -0
  94. package/dist/server/app-action-forwarding.js +17 -3
  95. package/dist/server/app-browser-entry.js +149 -62
  96. package/dist/server/app-browser-error.d.ts +3 -1
  97. package/dist/server/app-browser-error.js +7 -2
  98. package/dist/server/app-browser-interception-context.d.ts +2 -2
  99. package/dist/server/app-browser-interception-context.js +1 -1
  100. package/dist/server/app-browser-mpa-navigation.d.ts +1 -0
  101. package/dist/server/app-browser-mpa-navigation.js +6 -5
  102. package/dist/server/app-browser-navigation-controller.d.ts +17 -6
  103. package/dist/server/app-browser-navigation-controller.js +88 -26
  104. package/dist/server/app-browser-prefetch-response.js +2 -2
  105. package/dist/server/app-browser-state.d.ts +2 -2
  106. package/dist/server/app-browser-state.js +1 -1
  107. package/dist/server/app-browser-supplemental-refresh.js +1 -1
  108. package/dist/server/app-browser-visible-commit.d.ts +4 -4
  109. package/dist/server/app-client-reference-preloader.d.ts +23 -0
  110. package/dist/server/app-client-reference-preloader.js +30 -7
  111. package/dist/server/app-fallback-renderer.js +2 -1
  112. package/dist/server/app-middleware.d.ts +6 -0
  113. package/dist/server/app-middleware.js +8 -10
  114. package/dist/server/app-optimistic-routing.d.ts +8 -10
  115. package/dist/server/app-optimistic-routing.js +4 -95
  116. package/dist/server/app-page-boundary-render.js +8 -1
  117. package/dist/server/app-page-cache-render.js +1 -0
  118. package/dist/server/app-page-dispatch.js +3 -1
  119. package/dist/server/app-page-render.js +4 -2
  120. package/dist/server/app-page-rsc-render-status.d.ts +1 -0
  121. package/dist/server/app-page-rsc-render-status.js +1 -0
  122. package/dist/server/app-page-search-params-observation.d.ts +1 -4
  123. package/dist/server/app-page-search-params-observation.js +8 -10
  124. package/dist/server/app-page-stream.d.ts +7 -0
  125. package/dist/server/app-page-stream.js +1 -0
  126. package/dist/server/app-pages-bridge.d.ts +2 -1
  127. package/dist/server/app-pages-bridge.js +12 -8
  128. package/dist/server/app-prerender-endpoints.js +1 -1
  129. package/dist/server/app-prerender-static-params.js +3 -2
  130. package/dist/server/app-render-abort-error.d.ts +19 -0
  131. package/dist/server/app-render-abort-error.js +31 -1
  132. package/dist/server/app-render-dependency.js +42 -2
  133. package/dist/server/app-request-stage-independent-entry.js +7 -7
  134. package/dist/server/app-response-stage-entry.js +5 -5
  135. package/dist/server/app-route-handler-dispatch.js +3 -1
  136. package/dist/server/app-route-handler-execution.d.ts +2 -0
  137. package/dist/server/app-route-handler-execution.js +9 -2
  138. package/dist/server/app-route-handler-middleware-context.d.ts +2 -1
  139. package/dist/server/app-route-handler-middleware-context.js +3 -3
  140. package/dist/server/app-route-handler-response.d.ts +2 -1
  141. package/dist/server/app-route-handler-response.js +2 -2
  142. package/dist/server/app-route-handler-runtime.d.ts +2 -0
  143. package/dist/server/app-route-handler-runtime.js +21 -4
  144. package/dist/server/app-route-module-loader.js +7 -6
  145. package/dist/server/app-route-tree.d.ts +20 -0
  146. package/dist/server/app-route-tree.js +18 -0
  147. package/dist/server/app-router-entry.js +7 -7
  148. package/dist/server/app-rsc-cache-busting.d.ts +16 -0
  149. package/dist/server/app-rsc-cache-busting.js +29 -12
  150. package/dist/server/app-rsc-combined-handler.js +8 -1
  151. package/dist/server/app-rsc-errors.d.ts +7 -0
  152. package/dist/server/app-rsc-errors.js +9 -2
  153. package/dist/server/app-rsc-handler.d.ts +4 -1
  154. package/dist/server/app-rsc-handler.js +151 -135
  155. package/dist/server/app-rsc-request-normalization.js +3 -3
  156. package/dist/server/app-rsc-response-finalizer.d.ts +5 -0
  157. package/dist/server/app-rsc-response-finalizer.js +4 -1
  158. package/dist/server/app-rsc-response-stage.js +5 -3
  159. package/dist/server/app-rsc-route-matching.d.ts +1 -0
  160. package/dist/server/app-rsc-route-matching.js +1 -1
  161. package/dist/server/app-server-action-execution.d.ts +23 -6
  162. package/dist/server/app-server-action-execution.js +51 -57
  163. package/dist/server/app-ssr-entry.d.ts +6 -0
  164. package/dist/server/app-ssr-entry.js +21 -11
  165. package/dist/server/app-ssr-stream.d.ts +7 -0
  166. package/dist/server/app-ssr-stream.js +13 -1
  167. package/dist/server/app-visited-response-cache.js +2 -2
  168. package/dist/server/config-headers.js +13 -4
  169. package/dist/server/defer-until-stream-consumed.d.ts +2 -1
  170. package/dist/server/defer-until-stream-consumed.js +3 -1
  171. package/dist/server/dev-server.js +1 -1
  172. package/dist/server/image-optimization.js +1 -0
  173. package/dist/server/isolate-shared-promise.d.ts +10 -0
  174. package/dist/server/isolate-shared-promise.js +33 -0
  175. package/dist/server/isr-cache.js +3 -2
  176. package/dist/server/metadata-route-response.js +2 -2
  177. package/dist/server/middleware-matcher-pattern.d.ts +0 -1
  178. package/dist/server/middleware-matcher-pattern.js +11 -140
  179. package/dist/server/middleware-matcher.js +5 -6
  180. package/dist/server/middleware-response-headers.d.ts +31 -0
  181. package/dist/server/middleware-response-headers.js +57 -1
  182. package/dist/server/middleware-runtime.js +30 -17
  183. package/dist/server/navigation-planner.d.ts +2 -2
  184. package/dist/server/navigation-planner.js +1 -1
  185. package/dist/server/nitro-public-files-plugin.d.ts +38 -0
  186. package/dist/server/nitro-public-files-plugin.js +106 -0
  187. package/dist/server/nitro-public-files.d.ts +21 -0
  188. package/dist/server/nitro-public-files.js +39 -0
  189. package/dist/server/open-redirect.d.ts +11 -4
  190. package/dist/server/open-redirect.js +11 -4
  191. package/dist/server/pages-api-route.js +2 -2
  192. package/dist/server/pages-asset-tags.d.ts +5 -0
  193. package/dist/server/pages-asset-tags.js +9 -2
  194. package/dist/server/pages-client-assets.d.ts +4 -1
  195. package/dist/server/pages-data-route.js +2 -1
  196. package/dist/server/pages-i18n.d.ts +18 -0
  197. package/dist/server/pages-i18n.js +18 -2
  198. package/dist/server/pages-node-compat.d.ts +5 -3
  199. package/dist/server/pages-node-compat.js +35 -16
  200. package/dist/server/pages-page-data.js +1 -1
  201. package/dist/server/pages-page-handler.js +1 -1
  202. package/dist/server/pages-page-response.js +1 -1
  203. package/dist/server/pages-request-pipeline.d.ts +6 -1
  204. package/dist/server/pages-request-pipeline.js +35 -39
  205. package/dist/server/pages-request-stage-entry.js +20 -10
  206. package/dist/server/pages-response-stage-entry.js +1 -1
  207. package/dist/server/pages-revalidate.js +3 -2
  208. package/dist/server/pages-router-entry.js +2 -2
  209. package/dist/server/prod-server.d.ts +2 -2
  210. package/dist/server/prod-server.js +74 -36
  211. package/dist/server/proxy-trust.d.ts +6 -0
  212. package/dist/server/proxy-trust.js +12 -6
  213. package/dist/server/request-pipeline.d.ts +5 -0
  214. package/dist/server/request-pipeline.js +12 -1
  215. package/dist/server/rsc-stream-hints.d.ts +1 -1
  216. package/dist/server/rsc-stream-hints.js +21 -3
  217. package/dist/server/server-reference-loader.js +10 -1
  218. package/dist/server/static-file-cache.js +15 -3
  219. package/dist/server/worker-image-optimization.js +19 -6
  220. package/dist/server/worker-utils.js +1 -1
  221. package/dist/shims/cache-handler.js +3 -2
  222. package/dist/shims/cache-request-state.d.ts +40 -3
  223. package/dist/shims/cache-request-state.js +70 -5
  224. package/dist/shims/cache-runtime.js +47 -19
  225. package/dist/shims/cache.d.ts +2 -2
  226. package/dist/shims/cache.js +17 -8
  227. package/dist/shims/cdn-purge-routes.d.ts +24 -0
  228. package/dist/shims/cdn-purge-routes.js +77 -0
  229. package/dist/shims/dynamic.js +17 -4
  230. package/dist/shims/form.js +8 -3
  231. package/dist/shims/head.js +1 -1
  232. package/dist/shims/headers.js +2 -2
  233. package/dist/shims/image-props.d.ts +93 -0
  234. package/dist/shims/image-props.js +323 -0
  235. package/dist/shims/image.d.ts +4 -18
  236. package/dist/shims/image.js +4 -319
  237. package/dist/shims/internal/headers-state.d.ts +7 -0
  238. package/dist/shims/internal/headers-state.js +14 -2
  239. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +4 -1
  240. package/dist/shims/internal/hybrid-client-route-owner-direct.js +32 -15
  241. package/dist/shims/internal/hybrid-client-route-owner.js +9 -8
  242. package/dist/shims/link-prefetch.js +5 -4
  243. package/dist/shims/link.js +7 -5
  244. package/dist/shims/navigation.d.ts +1 -1
  245. package/dist/shims/navigation.js +21 -10
  246. package/dist/shims/og.js +35 -10
  247. package/dist/shims/request-context.d.ts +13 -0
  248. package/dist/shims/router.js +28 -52
  249. package/dist/shims/server.d.ts +42 -8
  250. package/dist/shims/server.js +99 -15
  251. package/dist/shims/thenable-params.d.ts +6 -1
  252. package/dist/shims/thenable-params.js +11 -2
  253. package/dist/shims/unified-request-context.d.ts +5 -0
  254. package/dist/shims/unified-request-context.js +2 -0
  255. package/dist/shims/url-utils.d.ts +7 -0
  256. package/dist/shims/url-utils.js +12 -3
  257. package/dist/utils/asset-prefix.d.ts +7 -0
  258. package/dist/utils/asset-prefix.js +10 -1
  259. package/dist/utils/client-build-manifest.js +12 -5
  260. package/dist/utils/client-runtime-metadata.d.ts +1 -0
  261. package/dist/utils/client-runtime-metadata.js +15 -2
  262. package/dist/utils/domain-locale.js +1 -1
  263. package/dist/utils/lazy-chunks.d.ts +4 -0
  264. package/dist/utils/manifest-paths.d.ts +14 -0
  265. package/dist/utils/manifest-paths.js +22 -1
  266. package/dist/utils/path-to-regexp.d.ts +21 -0
  267. package/dist/{server/middleware-path-to-regexp.js → utils/path-to-regexp.js} +14 -11
  268. package/dist/utils/plugin-react-version.d.ts +15 -0
  269. package/dist/utils/plugin-react-version.js +64 -0
  270. package/dist/utils/plugin-rsc-version.d.ts +2 -0
  271. package/dist/utils/plugin-rsc-version.js +28 -2
  272. package/dist/utils/public-routes.d.ts +2 -0
  273. package/dist/utils/public-routes.js +18 -7
  274. package/dist/utils/react-version.d.ts +7 -0
  275. package/dist/utils/react-version.js +39 -16
  276. package/package.json +6 -6
  277. package/dist/build/nitro-route-rules.d.ts +0 -47
  278. package/dist/build/nitro-route-rules.js +0 -79
  279. package/dist/plugins/cache-flight-codec.d.ts +0 -19
  280. package/dist/plugins/cache-flight-codec.js +0 -68
  281. package/dist/server/middleware-path-to-regexp.d.ts +0 -13
  282. package/dist/utils/regex-safety.d.ts +0 -17
  283. package/dist/utils/regex-safety.js +0 -789
@@ -1,6 +1,7 @@
1
1
  import { HistoryUpdateMode } from "./app-browser-navigation-controller.js";
2
2
  //#region src/server/app-browser-mpa-navigation.d.ts
3
3
  export type AppBrowserMpaNavigationWindow = {
4
+ document?: Pick<Document, "visibilityState">;
4
5
  location: Pick<Location, "assign" | "replace">;
5
6
  requestAnimationFrame?: (callback: FrameRequestCallback) => unknown;
6
7
  setTimeout(callback: () => void, timeout: number): unknown;
@@ -14,21 +14,22 @@ var AppBrowserMpaNavigationScheduler = class {
14
14
  this.#pendingNavigation = null;
15
15
  }
16
16
  navigate(targetWindow, href, historyUpdateMode) {
17
- const pendingNavigation = this.#pendingNavigation;
18
- if (pendingNavigation?.href === href && pendingNavigation.historyUpdateMode === historyUpdateMode) return;
17
+ if (this.#pendingNavigation?.href === href) return;
19
18
  const token = this.#nextToken + 1;
20
19
  this.#nextToken = token;
21
20
  this.#pendingNavigation = {
22
21
  href,
23
- historyUpdateMode,
24
22
  token
25
23
  };
26
24
  const navigate = () => {
27
- const currentNavigation = this.#pendingNavigation;
28
- if (currentNavigation?.href !== href || currentNavigation.historyUpdateMode !== historyUpdateMode || currentNavigation.token !== token) return;
25
+ if (this.#pendingNavigation?.token !== token) return;
29
26
  if (historyUpdateMode === "replace") targetWindow.location.replace(href);
30
27
  else targetWindow.location.assign(href);
31
28
  };
29
+ if (targetWindow.document?.visibilityState === "hidden") {
30
+ navigate();
31
+ return;
32
+ }
32
33
  if (typeof targetWindow.requestAnimationFrame === "function") {
33
34
  targetWindow.requestAnimationFrame(() => {
34
35
  targetWindow.setTimeout(navigate, 0);
@@ -1,4 +1,4 @@
1
- import { RouteManifest } from "../routing/app-route-graph.js";
1
+ import { BrowserRouteManifest } from "../routing/browser-route-manifest.js";
2
2
  import { AppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
3
3
  import { NavigationRuntimeVisibleCommitMode } from "../client/navigation-runtime.js";
4
4
  import { AppElements } from "./app-elements-wire.js";
@@ -17,10 +17,14 @@ export type PendingBrowserRouterState = {
17
17
  };
18
18
  export type NavigationPayloadOutcome = "committed" | "no-commit" | "hard-navigate";
19
19
  type HardNavigationMode = "assign" | "replace";
20
- type BrowserNavigationCommitEffect = (options: {
21
- keepCurrentUrl: boolean;
22
- releaseSnapshot: boolean;
23
- }) => void;
20
+ type BrowserNavigationCommitEffect = {
21
+ writeHistory(options: {
22
+ keepCurrentUrl: boolean;
23
+ }): void;
24
+ publish(options: {
25
+ releaseSnapshot: boolean;
26
+ }): void;
27
+ };
24
28
  type BrowserNavigationCommitEffectFactory = (options: {
25
29
  activeRoutePaths: readonly string[];
26
30
  bfcacheIds: Readonly<Record<string, string>>;
@@ -43,8 +47,10 @@ type SameUrlServerActionLifecycleOptions = {
43
47
  type BrowserNavigationControllerDeps = {
44
48
  basePath?: string;
45
49
  commitClientNavigationState?: typeof commitClientNavigationState;
50
+ navigateDocument?: (href: string, mode: HardNavigationMode) => void;
46
51
  performHardNavigation?: (href: string, mode?: HardNavigationMode) => boolean;
47
- getRouteManifest?: () => RouteManifest | null;
52
+ getRouteManifest?: () => BrowserRouteManifest | null;
53
+ loadRouteManifest?: () => Promise<boolean> | null;
48
54
  syncHistoryStatePreviousNextUrl?: (previousNextUrl: string | null, bfcacheIds?: Readonly<Record<string, string>> | null) => void;
49
55
  };
50
56
  type BrowserNavigationPayloadOptions = {
@@ -80,6 +86,7 @@ type BrowserNavigationController = {
80
86
  waitForBrowserRouterStateReady(): Promise<void>;
81
87
  attachBrowserRouterState(setter: Dispatch<AppRouterState | Promise<AppRouterState>>, stateRef: BrowserRouterStateRef): () => void;
82
88
  beginPendingBrowserRouterState(): PendingBrowserRouterState;
89
+ abandonPendingBrowserRouterState(pending: PendingBrowserRouterState | null | undefined): void;
83
90
  finalizeNavigation(navId: number, pending: PendingBrowserRouterState | null | undefined): void;
84
91
  discardPendingNavigation(visibleState: AppRouterState | null): boolean;
85
92
  flushCommittingNavigationUrl(): void;
@@ -112,8 +119,12 @@ type BrowserNavigationController = {
112
119
  renderId: number;
113
120
  children?: ReactNode;
114
121
  }): ReactNode;
122
+ NavigationHistoryCommit(this: void, { renderId }: {
123
+ renderId: number;
124
+ }): null;
115
125
  };
116
126
  export declare function clearHardNavigationLoopGuard(): void;
127
+ export declare function navigateDocumentDirectly(href: string, mode: HardNavigationMode): void;
117
128
  export declare function createBasePathStrippedPathAndSearch(url: URL, basePath: string): string;
118
129
  export declare function createAppBrowserNavigationController(deps?: BrowserNavigationControllerDeps): BrowserNavigationController;
119
130
  //#endregion
@@ -1,4 +1,5 @@
1
1
  import { stripBasePath } from "../utils/base-path.js";
2
+ import { withBasePath } from "../shims/url-utils.js";
2
3
  import { clearAppNavigationFailureTarget, getAppNavigationFailureTarget } from "../client/app-nav-failure-handler.js";
3
4
  import { claimAppRouterScrollIntentForCommit, clearAppRouterScrollIntent, consumeAppRouterScrollIntent } from "../shims/app-router-scroll-state.js";
4
5
  import { resolveServerActionOperationLane, shouldScheduleRefreshForDiscardedServerAction } from "./app-browser-action-result.js";
@@ -37,7 +38,11 @@ function clearHardNavigationLoopGuard() {
37
38
  window.sessionStorage.removeItem(HARD_NAVIGATION_LOOP_GUARD_KEY);
38
39
  } catch {}
39
40
  }
40
- function performHardNavigationWithLoopGuard(href, mode = "assign") {
41
+ function navigateDocumentDirectly(href, mode) {
42
+ if (mode === "replace") window.location.replace(href);
43
+ else window.location.assign(href);
44
+ }
45
+ function performHardNavigationWithLoopGuard(href, mode = "assign", navigateDocument = navigateDocumentDirectly) {
41
46
  const targetHref = normalizeBrowserHref(href);
42
47
  const currentHref = normalizeBrowserHref(window.location.href);
43
48
  if (readHardNavigationLoopGuard() === targetHref && currentHref === targetHref) {
@@ -49,8 +54,7 @@ function performHardNavigationWithLoopGuard(href, mode = "assign") {
49
54
  console.error(`[vinext] Hard navigation to ${targetHref} requires a reload-loop guard, but sessionStorage is unavailable; leaving the current document in place.`);
50
55
  return false;
51
56
  }
52
- if (mode === "replace") window.location.replace(href);
53
- else window.location.assign(href);
57
+ navigateDocument(href, mode);
54
58
  return true;
55
59
  }
56
60
  function createBasePathStrippedPathAndSearch(url, basePath) {
@@ -69,8 +73,9 @@ function isSnapshotTargetHref(basePath, snapshot, targetHref) {
69
73
  function createAppBrowserNavigationController(deps = {}) {
70
74
  const basePath = deps.basePath ?? "";
71
75
  const commitClientNavigationStateImpl = deps.commitClientNavigationState ?? commitClientNavigationState;
72
- const performHardNavigation = deps.performHardNavigation ?? performHardNavigationWithLoopGuard;
76
+ const performHardNavigation = deps.performHardNavigation ?? ((href, mode) => performHardNavigationWithLoopGuard(href, mode, deps.navigateDocument));
73
77
  const getRouteManifest = deps.getRouteManifest ?? (() => null);
78
+ const loadRouteManifest = deps.loadRouteManifest ?? (() => null);
74
79
  const syncHistoryStatePreviousNextUrl = deps.syncHistoryStatePreviousNextUrl ?? (() => {});
75
80
  let nextNavigationRenderId = 0;
76
81
  let activeNavigationId = 0;
@@ -162,6 +167,11 @@ function createAppBrowserNavigationController(deps = {}) {
162
167
  pending.resolve(getBrowserRouterState());
163
168
  if (activePendingBrowserRouterState === pending) activePendingBrowserRouterState = null;
164
169
  }
170
+ function abandonPendingBrowserRouterState(pending) {
171
+ if (!pending || pending.settled) return;
172
+ pending.settled = true;
173
+ if (activePendingBrowserRouterState === pending) activePendingBrowserRouterState = null;
174
+ }
165
175
  function finalizeNavigation(navId, pending) {
166
176
  settlePendingBrowserRouterState(pending);
167
177
  if (isCurrentNavigation(navId)) {
@@ -209,11 +219,11 @@ function createAppBrowserNavigationController(deps = {}) {
209
219
  return true;
210
220
  }
211
221
  /**
212
- * Run the URL update of a navigation render React is committing right now.
213
- * It normally runs in NavigationCommitSignal's layout effect, after the
214
- * route's own layout effects. Next.js writes the URL in an insertion effect
215
- * instead, so a raw history write from a destination layout effect lands on
216
- * top of the destination entry. Called before such a write to keep that order.
222
+ * Publish the URL update of a navigation render React is committing right
223
+ * now. Its history entry is already written, but publishing normally runs in
224
+ * NavigationCommitSignal's layout effect, after the route's own layout
225
+ * effects. Called before a raw history write from such an effect, so the
226
+ * write is published on top of the destination's.
217
227
  */
218
228
  function flushCommittingNavigationUrl() {
219
229
  if (committingNavigationRenderId !== null) drainPrePaintEffects(committingNavigationRenderId);
@@ -224,9 +234,12 @@ function createAppBrowserNavigationController(deps = {}) {
224
234
  function isRetiredNavigationUrl(navId, targetHref) {
225
235
  return retiredNavigationUrl !== null && retiredNavigationUrl.navigationId === navId && retiredNavigationUrl.href === normalizeBrowserHref(targetHref);
226
236
  }
227
- function queuePrePaintNavigationEffect(renderId, effect) {
228
- if (!effect) return;
229
- pendingNavigationPrePaintEffects.set(renderId, effect);
237
+ function writeNavigationRenderHistory(renderId) {
238
+ const effect = pendingNavigationPrePaintEffects.get(renderId);
239
+ const writeHistory = effect?.writeHistory;
240
+ if (!effect || !writeHistory) return;
241
+ effect.writeHistory = null;
242
+ writeHistory();
230
243
  }
231
244
  /**
232
245
  * Run all queued pre-paint effects for renderIds up to and including the
@@ -243,8 +256,10 @@ function createAppBrowserNavigationController(deps = {}) {
243
256
  for (const [id, effect] of pendingNavigationPrePaintEffects) {
244
257
  if (id > upToRenderId) continue;
245
258
  pendingNavigationPrePaintEffects.delete(id);
246
- if (id === upToRenderId) effect();
247
- else releaseRenderSnapshot(id);
259
+ if (id === upToRenderId) {
260
+ effect.writeHistory?.();
261
+ effect.publish();
262
+ } else releaseRenderSnapshot(id);
248
263
  }
249
264
  }
250
265
  /**
@@ -261,7 +276,10 @@ function createAppBrowserNavigationController(deps = {}) {
261
276
  pendingCommit.resolve(didCommit);
262
277
  }
263
278
  }
264
- /** Runs when React starts committing a render, before any layout effect. */
279
+ /**
280
+ * Runs when React starts committing a render, before it changes the route
281
+ * tree's DOM, and writes the render's history entry.
282
+ */
265
283
  function beginNavigationRenderCommit(renderId) {
266
284
  committingNavigationRenderId = renderId;
267
285
  const committingCommit = pendingNavigationCommits.get(renderId);
@@ -269,6 +287,7 @@ function createAppBrowserNavigationController(deps = {}) {
269
287
  if (committingCommit && committingOperation?.navigationCommitKind === "detached" && committingOperation.navigationId === pendingUserNavigationId) pendingUserNavigationShellHref = normalizeBrowserHref(committingCommit.targetHref);
270
288
  else pendingUserNavigationCommitStarted = true;
271
289
  clearCommittedNavigationFailureTargets(renderId);
290
+ writeNavigationRenderHistory(renderId);
272
291
  }
273
292
  function commitNavigationRender(renderId) {
274
293
  committingNavigationRenderId = null;
@@ -288,7 +307,11 @@ function createAppBrowserNavigationController(deps = {}) {
288
307
  if (!hasBrowserRouterState()) return;
289
308
  const currentState = getBrowserRouterState();
290
309
  const renderId = allocateRenderId();
291
- const [navigationSnapshot] = await Promise.all([pendingNavigationSnapshot, nextElements]);
310
+ const [navigationSnapshot, , routeManifestLoaded] = await Promise.all([
311
+ pendingNavigationSnapshot,
312
+ nextElements,
313
+ loadRouteManifest()
314
+ ]);
292
315
  const pending = await createPendingNavigationCommit({
293
316
  currentState,
294
317
  nextElements,
@@ -300,6 +323,10 @@ function createAppBrowserNavigationController(deps = {}) {
300
323
  });
301
324
  if (hmrUpdateId !== latestHmrUpdateId || startedDuringUserNavigation) return;
302
325
  if (!hasBrowserRouterState()) return;
326
+ if (routeManifestLoaded === false) {
327
+ performHardNavigation(withBasePath(createSnapshotPathAndSearch(navigationSnapshot), basePath));
328
+ return;
329
+ }
303
330
  const approval = approveHmrVisibleCommit({
304
331
  currentState: getBrowserRouterState(),
305
332
  pending,
@@ -309,10 +336,19 @@ function createAppBrowserNavigationController(deps = {}) {
309
336
  if (approval.approvedCommit) dispatchSynchronousVisibleCommit(approval.approvedCommit);
310
337
  else if (approval.decision.disposition === "hard-navigate") performHardNavigation(createSnapshotPathAndSearch(navigationSnapshot));
311
338
  }
312
- function NavigationCommitSignal({ renderId, children }) {
339
+ /**
340
+ * Rendered before the route tree (see createAppRouteTree). Insertion effects
341
+ * run in the mutation phase, in tree order, after each component's own
342
+ * subtree mutations, so this one runs before React changes the route tree's
343
+ * DOM. An effect on NavigationCommitSignal itself would run after them.
344
+ */
345
+ function NavigationHistoryCommit({ renderId }) {
313
346
  useInsertionEffect(() => {
314
347
  beginNavigationRenderCommit(renderId);
315
348
  }, [renderId]);
349
+ return null;
350
+ }
351
+ function NavigationCommitSignal({ renderId, children }) {
316
352
  useLayoutEffect(() => {
317
353
  commitNavigationRender(renderId);
318
354
  return () => {
@@ -433,6 +469,13 @@ function createAppBrowserNavigationController(deps = {}) {
433
469
  return isSamePathSearchHashCommit(options.targetHref);
434
470
  }
435
471
  async function renderNavigationPayload(options) {
472
+ const routeManifestLoad = loadRouteManifest();
473
+ if (routeManifestLoad !== null && !await routeManifestLoad) {
474
+ settlePendingBrowserRouterState(options.pendingRouterState);
475
+ consumeAppRouterScrollIntent(options.scrollIntent ?? null);
476
+ if (isCurrentNavigation(options.navId)) performHardNavigation(options.targetHref, options.historyUpdateMode === "push" ? "assign" : "replace");
477
+ return "no-commit";
478
+ }
436
479
  if (options.navId === pendingUserNavigationId) pendingUserNavigationLane = options.operationLane;
437
480
  const renderId = allocateRenderId();
438
481
  const failureTarget = getAppNavigationFailureTarget(options.targetHref);
@@ -486,11 +529,14 @@ function createAppBrowserNavigationController(deps = {}) {
486
529
  return "no-commit";
487
530
  }
488
531
  if (approval.decision.disposition === "hard-navigate") {
489
- settlePendingBrowserRouterState(options.pendingRouterState);
490
532
  pendingNavigationFailureTargets.delete(renderId);
491
533
  pendingNavigationCommits.delete(renderId);
492
534
  consumeAppRouterScrollIntent(options.scrollIntent ?? null);
493
- if (performHardNavigation(options.targetHref)) return "hard-navigate";
535
+ if (performHardNavigation(options.targetHref, options.historyUpdateMode === "push" ? "assign" : "replace")) {
536
+ abandonPendingBrowserRouterState(options.pendingRouterState);
537
+ return "hard-navigate";
538
+ }
539
+ settlePendingBrowserRouterState(options.pendingRouterState);
494
540
  if (failureTarget) clearAppNavigationFailureTarget(failureTarget);
495
541
  return "no-commit";
496
542
  }
@@ -507,11 +553,13 @@ function createAppBrowserNavigationController(deps = {}) {
507
553
  previousNextUrl: approvedCommit.previousNextUrl,
508
554
  targetHistoryIndex: options.targetHistoryIndex
509
555
  });
510
- queuePrePaintNavigationEffect(renderId, () => {
511
- commitEffect({
512
- keepCurrentUrl: isRetiredNavigationUrl(options.navId, options.targetHref),
513
- releaseSnapshot: snapshotRenderIds.delete(renderId)
514
- });
556
+ pendingNavigationPrePaintEffects.set(renderId, {
557
+ writeHistory: () => {
558
+ commitEffect.writeHistory({ keepCurrentUrl: isRetiredNavigationUrl(options.navId, options.targetHref) });
559
+ },
560
+ publish: () => {
561
+ commitEffect.publish({ releaseSnapshot: snapshotRenderIds.delete(renderId) });
562
+ }
515
563
  });
516
564
  claimAppRouterScrollIntentForCommit(options.scrollIntent, renderId);
517
565
  if (!isRetiredNavigationUrl(options.navId, options.targetHref)) {
@@ -542,6 +590,15 @@ function createAppBrowserNavigationController(deps = {}) {
542
590
  const currentState = actionInitiationState ?? getBrowserRouterState();
543
591
  const startedNavigationId = lifecycleOptions?.startedNavigationId ?? activeNavigationId;
544
592
  const targetHref = lifecycleOptions?.targetHref ?? window.location.href;
593
+ const routeManifestLoad = loadRouteManifest();
594
+ if (routeManifestLoad !== null && !await routeManifestLoad) {
595
+ if (isCurrentNavigation(startedNavigationId)) {
596
+ performHardNavigation(targetHref);
597
+ return;
598
+ }
599
+ notifyDiscardedServerActionRevalidation(lifecycleOptions);
600
+ return resolveSameUrlActionReturnValue(returnValue);
601
+ }
545
602
  const { approvedCommit, decision, pending, trace: _navigationTrace } = await resolveAndClassifyNavigationCommit({
546
603
  activeNavigationId,
547
604
  currentState,
@@ -582,6 +639,9 @@ function createAppBrowserNavigationController(deps = {}) {
582
639
  syncHistoryStatePreviousNextUrl(approvedRevalidationCommit.previousNextUrl, approvedRevalidationCommit.action.bfcacheIds);
583
640
  } else notifyDiscardedServerActionRevalidation(lifecycleOptions);
584
641
  } else if (decision.disposition === "no-commit") notifyDiscardedServerActionRevalidation(lifecycleOptions);
642
+ return resolveSameUrlActionReturnValue(returnValue);
643
+ }
644
+ async function resolveSameUrlActionReturnValue(returnValue) {
585
645
  if (returnValue) {
586
646
  if (!returnValue.ok) throw await returnValue.data;
587
647
  return returnValue.data;
@@ -609,6 +669,7 @@ function createAppBrowserNavigationController(deps = {}) {
609
669
  waitForBrowserRouterStateReady,
610
670
  attachBrowserRouterState,
611
671
  beginPendingBrowserRouterState,
672
+ abandonPendingBrowserRouterState,
612
673
  finalizeNavigation,
613
674
  discardPendingNavigation,
614
675
  flushCommittingNavigationUrl,
@@ -620,8 +681,9 @@ function createAppBrowserNavigationController(deps = {}) {
620
681
  beginNavigationRenderCommit,
621
682
  commitNavigationRender,
622
683
  clearCommittedNavigationFailureTargets,
623
- NavigationCommitSignal
684
+ NavigationCommitSignal,
685
+ NavigationHistoryCommit
624
686
  };
625
687
  }
626
688
  //#endregion
627
- export { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch, createSnapshotPathAndSearch };
689
+ export { clearHardNavigationLoopGuard, createAppBrowserNavigationController, createBasePathStrippedPathAndSearch, createSnapshotPathAndSearch, navigateDocumentDirectly };
@@ -1,4 +1,4 @@
1
- import { stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
1
+ import { formatRscRequestPath, stripRscCacheBustingSearchParam } from "./app-rsc-cache-busting.js";
2
2
  import { peekPrefetchResponseForNavigation } from "../shims/navigation.js";
3
3
  //#region src/server/app-browser-prefetch-response.ts
4
4
  function peekSettledPrefetchResponseForNavigation(options) {
@@ -25,7 +25,7 @@ function isSameOriginBrowserRscUrl(url, origin) {
25
25
  function canonicalizeBrowserRscResponseUrl(responseUrl, origin) {
26
26
  try {
27
27
  const parsed = new URL(responseUrl, origin);
28
- if (parsed.origin === new URL(origin).origin) return `${parsed.pathname}${parsed.search}`;
28
+ if (parsed.origin === new URL(origin).origin) return formatRscRequestPath(parsed);
29
29
  } catch {}
30
30
  return responseUrl;
31
31
  }
@@ -1,4 +1,4 @@
1
- import { RouteManifest } from "../routing/app-route-graph.js";
1
+ import { BrowserRouteManifest } from "../routing/browser-route-manifest.js";
2
2
  import { CacheEntryReuseProof } from "./cache-proof.js";
3
3
  import { AppElements, AppElementsInterception, AppElementsSlotBinding, LayoutFlags } from "./app-elements-wire.js";
4
4
  import "./app-elements.js";
@@ -130,7 +130,7 @@ export declare function resolvePendingNavigationCommitDispositionDecision(option
130
130
  activeNavigationId: number;
131
131
  currentState: AppRouterState;
132
132
  pending: PendingNavigationCommit;
133
- routeManifest?: RouteManifest | null;
133
+ routeManifest?: BrowserRouteManifest | null;
134
134
  startedNavigationId: number;
135
135
  targetHref?: string;
136
136
  }): PendingNavigationCommitDispositionDecision;
@@ -1,7 +1,7 @@
1
- import { normalizePathnameForRouteMatch } from "../routing/utils.js";
2
1
  import { stripBasePath } from "../utils/base-path.js";
3
2
  import { VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_MOUNTED_SLOTS_HEADER } from "./app-rsc-vary.js";
4
3
  import { NEXT_ACTION_HEADER, RSC_ACTION_HEADER } from "./headers.js";
4
+ import { normalizePathnameForRouteMatch } from "../routing/utils.js";
5
5
  import { normalizePath } from "./normalize-path.js";
6
6
  import { AppElementsWire } from "./app-elements-wire.js";
7
7
  import { getMountedSlotIds, getMountedSlotIdsHeader } from "./app-elements.js";
@@ -1,5 +1,5 @@
1
- import { normalizePathnameForRouteMatch } from "../routing/utils.js";
2
1
  import { addBasePathToPathname, removeTrailingSlash, stripBasePath } from "../utils/base-path.js";
2
+ import { normalizePathnameForRouteMatch } from "../routing/utils.js";
3
3
  import { normalizePath } from "./normalize-path.js";
4
4
  import { APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_SLOT_BINDINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
5
5
  import "./app-elements.js";
@@ -1,4 +1,4 @@
1
- import { RouteManifest } from "../routing/app-route-graph.js";
1
+ import { BrowserRouteManifest } from "../routing/browser-route-manifest.js";
2
2
  import { AppElements } from "./app-elements-wire.js";
3
3
  import "./app-elements.js";
4
4
  import { NavigationTrace } from "./navigation-trace.js";
@@ -52,14 +52,14 @@ export declare function applyApprovedVisibleCommit(state: AppRouterState, commit
52
52
  export declare function approveHmrVisibleCommit(options: {
53
53
  currentState: AppRouterState;
54
54
  pending: PendingNavigationCommit;
55
- routeManifest?: RouteManifest | null;
55
+ routeManifest?: BrowserRouteManifest | null;
56
56
  targetHref: string;
57
57
  }): CommitApproval;
58
58
  export declare function approvePendingNavigationCommit(options: {
59
59
  activeNavigationId: number;
60
60
  currentState: AppRouterState;
61
61
  pending: PendingNavigationCommit;
62
- routeManifest?: RouteManifest | null;
62
+ routeManifest?: BrowserRouteManifest | null;
63
63
  startedNavigationId: number;
64
64
  targetHref: string;
65
65
  }): CommitApproval;
@@ -74,7 +74,7 @@ export declare function resolveAndClassifyNavigationCommit(options: {
74
74
  payloadOrigin: AppNavigationPayloadOrigin;
75
75
  previousNextUrl?: string | null;
76
76
  renderId: number;
77
- routeManifest?: RouteManifest | null;
77
+ routeManifest?: BrowserRouteManifest | null;
78
78
  startedNavigationId: number;
79
79
  targetHref: string;
80
80
  type: "navigate" | "replace" | "traverse";
@@ -9,5 +9,28 @@ type ClientReferencePreloaderOptions = {
9
9
  type ClientReferencePreloader = {
10
10
  preload: (referenceIds?: Iterable<string>) => Promise<void>;
11
11
  };
12
+ /**
13
+ * The client references each App Router route preloads before SSR, generated
14
+ * by plugins/rsc-client-reference-loaders.ts from the RSC build's module graph.
15
+ * Each list holds indices into `references`, or for routes into `files`.
16
+ */
17
+ export type RouteClientReferences = {
18
+ /** Client reference keys. */
19
+ references: readonly string[];
20
+ /** References any render may use, whatever its route. */
21
+ always: readonly number[];
22
+ /** The references each route file reaches. */
23
+ files: readonly (readonly number[])[];
24
+ /** Each route pattern's files. */
25
+ routes: Readonly<Record<string, readonly number[]>>;
26
+ /** The files of a render without a route, such as a route-miss 404. */
27
+ routeless: readonly number[];
28
+ };
29
+ /**
30
+ * The client references a render of `routePattern` preloads, or of no route
31
+ * when it is null. Undefined, meaning every reference, without a plan or a
32
+ * route to look up, or for a pattern the plan doesn't know.
33
+ */
34
+ export declare function resolveRouteClientReferences(plan: RouteClientReferences | null, routePattern: string | null | undefined): string[] | undefined;
12
35
  export declare function createClientReferencePreloader(options: ClientReferencePreloaderOptions): ClientReferencePreloader;
13
36
  //#endregion
@@ -1,27 +1,50 @@
1
+ import { shareIsolatePromise } from "./isolate-shared-promise.js";
1
2
  //#region src/server/app-client-reference-preloader.ts
2
3
  const resolvedPreload = Promise.resolve();
4
+ /**
5
+ * The client references a render of `routePattern` preloads, or of no route
6
+ * when it is null. Undefined, meaning every reference, without a plan or a
7
+ * route to look up, or for a pattern the plan doesn't know.
8
+ */
9
+ function resolveRouteClientReferences(plan, routePattern) {
10
+ if (!plan || routePattern === void 0) return void 0;
11
+ let files;
12
+ if (routePattern === null) files = plan.routeless;
13
+ else if (Object.hasOwn(plan.routes, routePattern)) files = plan.routes[routePattern];
14
+ else return;
15
+ const indices = new Set(plan.always);
16
+ for (const file of files) for (const index of plan.files[file]) indices.add(index);
17
+ return Array.from(indices, (index) => plan.references[index]);
18
+ }
3
19
  function createClientReferencePreloader(options) {
4
20
  let allReferencesPreloaded = false;
5
21
  let allReferencesPreloadPromise = null;
6
22
  const preloadedReferences = /* @__PURE__ */ new Set();
7
23
  const referencePreloadPromises = /* @__PURE__ */ new Map();
8
24
  function preloadReference(id, clientRequire) {
9
- if (preloadedReferences.has(id)) return resolvedPreload;
10
25
  const existing = referencePreloadPromises.get(id);
11
26
  if (existing) return existing;
12
- const preloadPromise = clientRequire(id).catch((error) => {
27
+ const loading = clientRequire(id);
28
+ const preloadPromise = shareIsolatePromise(loading.then((value) => {
29
+ loading.status = "fulfilled";
30
+ loading.value = value;
31
+ }, (error) => {
32
+ loading.status = "rejected";
33
+ loading.reason = error;
34
+ throw error;
35
+ }).catch((error) => {
13
36
  options.onPreloadError?.(id, error);
14
37
  }).then(() => {
15
38
  preloadedReferences.add(id);
16
39
  }).finally(() => {
17
40
  referencePreloadPromises.delete(id);
18
- });
41
+ }));
19
42
  referencePreloadPromises.set(id, preloadPromise);
20
43
  return preloadPromise;
21
44
  }
22
45
  function preloadReferenceSet(referenceIds, refs, clientRequire) {
23
46
  const pending = [];
24
- for (const id of referenceIds) if (Object.hasOwn(refs, id)) pending.push(preloadReference(id, clientRequire));
47
+ for (const id of referenceIds) if (Object.hasOwn(refs, id) && !preloadedReferences.has(id)) pending.push(preloadReference(id, clientRequire));
25
48
  if (pending.length === 0) return resolvedPreload;
26
49
  return Promise.all(pending).then(() => {});
27
50
  }
@@ -32,13 +55,13 @@ function createClientReferencePreloader(options) {
32
55
  if (referenceIds) return preloadReferenceSet(referenceIds, refs, clientRequire);
33
56
  if (allReferencesPreloaded) return resolvedPreload;
34
57
  if (allReferencesPreloadPromise) return allReferencesPreloadPromise;
35
- allReferencesPreloadPromise = preloadReferenceSet(Object.keys(refs), refs, clientRequire).then(() => {
58
+ allReferencesPreloadPromise = shareIsolatePromise(preloadReferenceSet(Object.keys(refs), refs, clientRequire).then(() => {
36
59
  allReferencesPreloaded = true;
37
60
  }).finally(() => {
38
61
  allReferencesPreloadPromise = null;
39
- });
62
+ }));
40
63
  return allReferencesPreloadPromise;
41
64
  } };
42
65
  }
43
66
  //#endregion
44
- export { createClientReferencePreloader };
67
+ export { createClientReferencePreloader, resolveRouteClientReferences };
@@ -1,4 +1,5 @@
1
1
  import { runOutsideRequestScopes } from "../shims/internal/als-registry.js";
2
+ import { shareIsolatePromise } from "./isolate-shared-promise.js";
2
3
  import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
3
4
  import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
4
5
  import { renderAppPageErrorBoundary, renderAppPageHttpAccessFallback } from "./app-page-boundary-render.js";
@@ -17,7 +18,7 @@ function createAppFallbackRenderer(options) {
17
18
  let globalNotFoundModulePromise = null;
18
19
  function resolveGlobalNotFoundModule() {
19
20
  if (!loadGlobalNotFoundModule) return null;
20
- if (globalNotFoundModulePromise === null) globalNotFoundModulePromise = runOutsideRequestScopes(() => Promise.resolve().then(loadGlobalNotFoundModule));
21
+ if (globalNotFoundModulePromise === null) globalNotFoundModulePromise = shareIsolatePromise(runOutsideRequestScopes(() => Promise.resolve().then(loadGlobalNotFoundModule)));
21
22
  return globalNotFoundModulePromise;
22
23
  }
23
24
  return {
@@ -50,6 +50,12 @@ export type ApplyAppMiddlewareResult = {
50
50
  search: string | null;
51
51
  } | {
52
52
  kind: "response";
53
+ /**
54
+ * True when `response` proxies a middleware external rewrite. It carries
55
+ * middleware's headers, and the caller still stages next.config headers
56
+ * beneath them.
57
+ */
58
+ externalRewrite?: boolean;
53
59
  /** Present on real middleware results; optional for older generated callers. */
54
60
  matched?: boolean;
55
61
  /** True when this pathname can match middleware for some request context. */
@@ -6,7 +6,7 @@ import { internalServerErrorResponse } from "./http-error-responses.js";
6
6
  import { cloneRequestWithHeaders, processMiddlewareHeaders } from "./request-pipeline.js";
7
7
  import { executeMiddleware } from "./middleware-runtime.js";
8
8
  import { applyMiddlewareRequestHeaders, setHeadersContext } from "../shims/headers.js";
9
- import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
9
+ import { mergeMiddlewareResponseHeaders, withExternalRewriteResponseHeaders } from "./middleware-response-headers.js";
10
10
  import { setNavigationContext } from "../shims/navigation-context-accessors.js";
11
11
  //#region src/server/app-middleware.ts
12
12
  const FLIGHT_HEADER_SET = new Set(FLIGHT_HEADERS);
@@ -92,19 +92,15 @@ async function proxyExternalMiddlewareRewrite(request, rewriteUrl, context) {
92
92
  const proxyResponse = await proxyExternalRequest(proxyRequest, rewriteUrl);
93
93
  const headers = new Headers(proxyResponse.headers);
94
94
  processMiddlewareHeaders(headers);
95
- if (!context.headers) return new Response(proxyResponse.body, {
96
- status: proxyResponse.status,
97
- statusText: proxyResponse.statusText,
98
- headers
99
- });
100
- const middlewareHeaders = new Headers(context.headers);
95
+ const stagedHeaders = new Headers();
96
+ const middlewareHeaders = new Headers(context.headers ?? void 0);
101
97
  processMiddlewareHeaders(middlewareHeaders);
102
- mergeMiddlewareResponseHeaders(headers, middlewareHeaders);
103
- return new Response(proxyResponse.body, {
98
+ mergeMiddlewareResponseHeaders(stagedHeaders, middlewareHeaders);
99
+ return withExternalRewriteResponseHeaders(new Response(proxyResponse.body, {
104
100
  status: proxyResponse.status,
105
101
  statusText: proxyResponse.statusText,
106
102
  headers
107
- });
103
+ }), stagedHeaders, middlewareHeaders.getSetCookie());
108
104
  }
109
105
  function validationResponseWithMiddlewareHeaders(response, context) {
110
106
  if (!context.headers) return response;
@@ -171,6 +167,7 @@ async function applyAppMiddleware(options) {
171
167
  const externalRequest = options.externalRewriteRequest ?? options.request;
172
168
  return {
173
169
  kind: "response",
170
+ externalRewrite: true,
174
171
  matched,
175
172
  pathnameEligible,
176
173
  response: await proxyExternalMiddlewareRewrite(externalRequest, forwarded.rewriteUrl, options.context)
@@ -248,6 +245,7 @@ async function applyAppMiddleware(options) {
248
245
  const externalRequest = options.externalRewriteRequest ?? options.request;
249
246
  return {
250
247
  kind: "response",
248
+ externalRewrite: true,
251
249
  matched,
252
250
  pathnameEligible,
253
251
  response: await proxyExternalMiddlewareRewrite(externalRequest, result.rewriteUrl, options.context)