vinext 1.0.0-beta.1 → 1.0.0-beta.3

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 (234) hide show
  1. package/README.md +10 -10
  2. package/dist/build/client-build-config.js +8 -1
  3. package/dist/build/report.d.ts +8 -1
  4. package/dist/build/report.js +12 -2
  5. package/dist/check.js +19 -2
  6. package/dist/cli.js +3 -2
  7. package/dist/config/config-matchers.d.ts +13 -37
  8. package/dist/config/config-matchers.js +35 -122
  9. package/dist/config/next-config.d.ts +15 -5
  10. package/dist/config/next-config.js +7 -1
  11. package/dist/config/request-context.d.ts +14 -0
  12. package/dist/config/request-context.js +26 -0
  13. package/dist/entries/app-browser-entry.d.ts +4 -10
  14. package/dist/entries/app-browser-entry.js +20 -4
  15. package/dist/entries/app-rsc-entry.js +30 -9
  16. package/dist/entries/app-rsc-manifest.js +36 -0
  17. package/dist/entries/pages-client-entry.js +0 -1
  18. package/dist/entries/pages-server-entry.js +13 -5
  19. package/dist/index.js +194 -101
  20. package/dist/init-cloudflare.d.ts +3 -1
  21. package/dist/init-cloudflare.js +59 -5
  22. package/dist/init.d.ts +6 -4
  23. package/dist/init.js +20 -22
  24. package/dist/plugins/extensionless-dynamic-import.js +23 -18
  25. package/dist/plugins/ignore-dynamic-requests.js +3 -1
  26. package/dist/plugins/import-meta-url.js +17 -6
  27. package/dist/plugins/og-assets.js +1 -1
  28. package/dist/plugins/require-context.js +20 -15
  29. package/dist/plugins/transform-cache.d.ts +19 -0
  30. package/dist/plugins/transform-cache.js +36 -0
  31. package/dist/routing/app-route-graph.d.ts +27 -11
  32. package/dist/routing/app-route-graph.js +158 -22
  33. package/dist/routing/app-router.js +12 -6
  34. package/dist/routing/file-matcher.d.ts +11 -22
  35. package/dist/routing/file-matcher.js +21 -33
  36. package/dist/routing/pages-router.js +23 -29
  37. package/dist/routing/route-matching.d.ts +14 -1
  38. package/dist/routing/route-matching.js +13 -1
  39. package/dist/routing/route-pattern.d.ts +2 -1
  40. package/dist/routing/route-pattern.js +7 -4
  41. package/dist/routing/route-trie.d.ts +5 -1
  42. package/dist/routing/route-trie.js +5 -2
  43. package/dist/server/api-handler.d.ts +2 -0
  44. package/dist/server/api-handler.js +3 -3
  45. package/dist/server/app-browser-entry.js +110 -37
  46. package/dist/server/app-browser-history-controller.d.ts +1 -1
  47. package/dist/server/app-browser-history-controller.js +3 -3
  48. package/dist/server/app-browser-navigation-controller.d.ts +23 -21
  49. package/dist/server/app-browser-navigation-controller.js +2 -2
  50. package/dist/server/app-browser-state.js +1 -1
  51. package/dist/server/app-browser-visible-commit.js +1 -1
  52. package/dist/server/app-fallback-renderer.d.ts +3 -0
  53. package/dist/server/app-fallback-renderer.js +4 -2
  54. package/dist/server/app-middleware.js +2 -1
  55. package/dist/server/app-page-boundary-render.d.ts +12 -1
  56. package/dist/server/app-page-boundary-render.js +84 -2
  57. package/dist/server/app-page-cache-finalizer.d.ts +1 -1
  58. package/dist/server/app-page-cache-finalizer.js +1 -1
  59. package/dist/server/app-page-cache.d.ts +2 -2
  60. package/dist/server/app-page-cache.js +16 -2
  61. package/dist/server/app-page-dispatch.d.ts +19 -2
  62. package/dist/server/app-page-dispatch.js +45 -23
  63. package/dist/server/app-page-element-builder.d.ts +9 -2
  64. package/dist/server/app-page-element-builder.js +144 -33
  65. package/dist/server/app-page-head.d.ts +56 -4
  66. package/dist/server/app-page-head.js +216 -85
  67. package/dist/server/app-page-http-access-fallback-metadata.d.ts +29 -0
  68. package/dist/server/app-page-http-access-fallback-metadata.js +114 -0
  69. package/dist/server/app-page-probe.d.ts +4 -0
  70. package/dist/server/app-page-probe.js +6 -2
  71. package/dist/server/app-page-render.d.ts +2 -2
  72. package/dist/server/app-page-render.js +1 -1
  73. package/dist/server/app-page-request.d.ts +15 -0
  74. package/dist/server/app-page-request.js +134 -14
  75. package/dist/server/app-page-response.js +1 -1
  76. package/dist/server/app-page-route-wiring.d.ts +16 -0
  77. package/dist/server/app-page-route-wiring.js +254 -52
  78. package/dist/server/app-pages-bridge.d.ts +1 -1
  79. package/dist/server/app-pages-bridge.js +2 -1
  80. package/dist/server/app-post-middleware-context.d.ts +1 -1
  81. package/dist/server/app-post-middleware-context.js +1 -1
  82. package/dist/server/app-route-handler-cache.js +4 -0
  83. package/dist/server/app-route-handler-dispatch.js +40 -20
  84. package/dist/server/app-route-handler-execution.d.ts +6 -1
  85. package/dist/server/app-route-handler-execution.js +42 -16
  86. package/dist/server/app-route-handler-policy.d.ts +2 -0
  87. package/dist/server/app-route-handler-policy.js +3 -3
  88. package/dist/server/app-route-handler-response.js +1 -1
  89. package/dist/server/app-route-module-loader.d.ts +9 -1
  90. package/dist/server/app-route-module-loader.js +4 -0
  91. package/dist/server/app-router-entry.js +6 -3
  92. package/dist/server/app-rsc-cache-busting.d.ts +1 -1
  93. package/dist/server/app-rsc-errors.d.ts +1 -1
  94. package/dist/server/app-rsc-errors.js +22 -2
  95. package/dist/server/app-rsc-handler.d.ts +10 -5
  96. package/dist/server/app-rsc-handler.js +73 -33
  97. package/dist/server/app-rsc-request-normalization.d.ts +3 -2
  98. package/dist/server/app-rsc-request-normalization.js +8 -2
  99. package/dist/server/app-rsc-response-finalizer.d.ts +2 -2
  100. package/dist/server/app-rsc-response-finalizer.js +5 -11
  101. package/dist/server/app-rsc-route-matching.d.ts +29 -0
  102. package/dist/server/app-rsc-route-matching.js +93 -11
  103. package/dist/server/app-segment-config.js +13 -3
  104. package/dist/server/app-server-action-execution.d.ts +3 -1
  105. package/dist/server/app-server-action-execution.js +9 -7
  106. package/dist/server/app-ssr-entry.js +6 -6
  107. package/dist/server/app-ssr-stream.d.ts +1 -7
  108. package/dist/server/app-ssr-stream.js +2 -10
  109. package/dist/server/cache-control.d.ts +2 -2
  110. package/dist/server/cache-control.js +2 -1
  111. package/dist/server/config-headers.d.ts +24 -0
  112. package/dist/server/config-headers.js +52 -0
  113. package/dist/server/dev-initial-server-error.d.ts +1 -1
  114. package/dist/server/dev-server.d.ts +3 -1
  115. package/dist/server/dev-server.js +170 -321
  116. package/dist/server/headers.d.ts +2 -2
  117. package/dist/server/headers.js +4 -3
  118. package/dist/server/isr-cache.d.ts +11 -34
  119. package/dist/server/isr-cache.js +33 -43
  120. package/dist/server/isr-decision.d.ts +2 -2
  121. package/dist/server/middleware-matcher-pattern.d.ts +22 -0
  122. package/dist/server/middleware-matcher-pattern.js +219 -0
  123. package/dist/server/middleware-matcher.d.ts +2 -7
  124. package/dist/server/middleware-matcher.js +13 -60
  125. package/dist/server/middleware-path-to-regexp.d.ts +14 -0
  126. package/dist/server/middleware-path-to-regexp.js +228 -0
  127. package/dist/server/middleware-runtime.js +4 -3
  128. package/dist/server/middleware.d.ts +1 -1
  129. package/dist/server/middleware.js +2 -1
  130. package/dist/server/pages-api-route.d.ts +2 -0
  131. package/dist/server/pages-api-route.js +4 -1
  132. package/dist/server/pages-data-route.d.ts +11 -1
  133. package/dist/server/pages-data-route.js +16 -1
  134. package/dist/server/pages-dev-hydration.js +0 -1
  135. package/dist/server/pages-get-initial-props.d.ts +16 -3
  136. package/dist/server/pages-get-initial-props.js +17 -10
  137. package/dist/server/pages-i18n.js +64 -16
  138. package/dist/server/pages-node-compat.d.ts +2 -0
  139. package/dist/server/pages-node-compat.js +7 -3
  140. package/dist/server/pages-page-data.d.ts +64 -10
  141. package/dist/server/pages-page-data.js +349 -80
  142. package/dist/server/pages-page-handler.d.ts +9 -3
  143. package/dist/server/pages-page-handler.js +131 -36
  144. package/dist/server/pages-page-response.d.ts +5 -3
  145. package/dist/server/pages-page-response.js +24 -27
  146. package/dist/server/pages-readiness.d.ts +3 -3
  147. package/dist/server/pages-request-pipeline.d.ts +8 -0
  148. package/dist/server/pages-request-pipeline.js +30 -12
  149. package/dist/server/pages-revalidate.d.ts +1 -1
  150. package/dist/server/pages-revalidate.js +54 -8
  151. package/dist/server/pages-router-entry.d.ts +1 -0
  152. package/dist/server/pages-router-entry.js +16 -4
  153. package/dist/server/prerender-route-params.js +2 -2
  154. package/dist/server/prod-server.d.ts +3 -5
  155. package/dist/server/prod-server.js +72 -35
  156. package/dist/server/request-pipeline.d.ts +15 -29
  157. package/dist/server/request-pipeline.js +24 -59
  158. package/dist/server/revalidation-host.d.ts +11 -0
  159. package/dist/server/revalidation-host.js +19 -0
  160. package/dist/server/rsc-stream-hints.js +122 -18
  161. package/dist/server/worker-revalidation-context.d.ts +13 -0
  162. package/dist/server/worker-revalidation-context.js +29 -0
  163. package/dist/shims/app.d.ts +1 -1
  164. package/dist/shims/cache-handler.d.ts +1 -1
  165. package/dist/shims/cache-handler.js +10 -7
  166. package/dist/shims/cache-request-state.d.ts +27 -1
  167. package/dist/shims/cache-request-state.js +60 -1
  168. package/dist/shims/cache-runtime.d.ts +18 -1
  169. package/dist/shims/cache-runtime.js +26 -8
  170. package/dist/shims/cache.d.ts +5 -5
  171. package/dist/shims/cache.js +27 -11
  172. package/dist/shims/document.d.ts +42 -83
  173. package/dist/shims/document.js +62 -53
  174. package/dist/shims/dynamic.d.ts +5 -25
  175. package/dist/shims/dynamic.js +29 -8
  176. package/dist/shims/error.d.ts +1 -1
  177. package/dist/shims/error.js +2 -2
  178. package/dist/shims/fetch-cache.js +13 -4
  179. package/dist/shims/font-google-base.d.ts +11 -4
  180. package/dist/shims/font-google-base.js +17 -8
  181. package/dist/shims/font-local.d.ts +10 -3
  182. package/dist/shims/font-local.js +41 -10
  183. package/dist/shims/head.d.ts +13 -2
  184. package/dist/shims/head.js +3 -3
  185. package/dist/shims/headers.d.ts +37 -43
  186. package/dist/shims/headers.js +183 -74
  187. package/dist/shims/image.d.ts +27 -37
  188. package/dist/shims/image.js +21 -14
  189. package/dist/shims/internal/cookie-serialize.d.ts +12 -9
  190. package/dist/shims/internal/cookie-serialize.js +10 -7
  191. package/dist/shims/internal/hybrid-client-route-owner.js +3 -1
  192. package/dist/shims/internal/interpolate-as.d.ts +15 -1
  193. package/dist/shims/internal/interpolate-as.js +27 -2
  194. package/dist/shims/internal/utils.d.ts +3 -3
  195. package/dist/shims/legacy-image.d.ts +3 -37
  196. package/dist/shims/legacy-image.js +6 -16
  197. package/dist/shims/link.d.ts +15 -22
  198. package/dist/shims/link.js +34 -13
  199. package/dist/shims/metadata.d.ts +7 -17
  200. package/dist/shims/metadata.js +74 -24
  201. package/dist/shims/navigation-context-state.d.ts +1 -1
  202. package/dist/shims/navigation.d.ts +7 -3
  203. package/dist/shims/navigation.js +25 -14
  204. package/dist/shims/navigation.react-server.js +1 -1
  205. package/dist/shims/next-shims-augmentations.d.ts +1 -0
  206. package/dist/shims/next-shims-public.d.ts +1 -0
  207. package/dist/shims/public-shim-map.json.js +103 -0
  208. package/dist/shims/readonly-url-search-params.d.ts +3 -3
  209. package/dist/shims/readonly-url-search-params.js +3 -3
  210. package/dist/shims/request-context.d.ts +4 -1
  211. package/dist/shims/request-state-types.d.ts +1 -1
  212. package/dist/shims/router.d.ts +55 -21
  213. package/dist/shims/router.js +180 -44
  214. package/dist/shims/script.d.ts +6 -10
  215. package/dist/shims/script.js +7 -4
  216. package/dist/shims/server.d.ts +50 -26
  217. package/dist/shims/server.js +193 -55
  218. package/dist/shims/unified-request-context.d.ts +22 -3
  219. package/dist/shims/unified-request-context.js +84 -1
  220. package/dist/shims/url-safety.d.ts +1 -1
  221. package/dist/shims/url-safety.js +2 -2
  222. package/dist/typegen.d.ts +8 -2
  223. package/dist/typegen.js +76 -15
  224. package/dist/utils/cache-control-metadata.d.ts +2 -1
  225. package/dist/utils/cache-control-metadata.js +5 -1
  226. package/dist/utils/domain-locale.d.ts +2 -2
  227. package/dist/utils/external-url.d.ts +5 -0
  228. package/dist/utils/external-url.js +7 -0
  229. package/dist/utils/html-limited-bots.js +1 -1
  230. package/dist/utils/protocol-headers.d.ts +7 -1
  231. package/dist/utils/protocol-headers.js +7 -1
  232. package/dist/utils/regex-safety.d.ts +8 -0
  233. package/dist/utils/regex-safety.js +737 -0
  234. package/package.json +13 -2
@@ -4,14 +4,18 @@ import "./app-elements.js";
4
4
  import { createAppPageRenderIdentity } from "./app-page-render-identity.js";
5
5
  import { matchRoutePattern } from "../routing/route-pattern.js";
6
6
  import { makeThenableParams } from "../shims/thenable-params.js";
7
- import { resolveAppPageBranchParams } from "./app-page-params.js";
8
- import { resolveActiveParallelRouteHeadInputs, resolveAppPageHead } from "./app-page-head.js";
7
+ import { resolveAppPageBranchParams, resolveAppPageSegmentParams } from "./app-page-params.js";
8
+ import { resolveAppPageSpecialError } from "./app-page-execution.js";
9
+ import { prepareAppPageHead, resolveActiveParallelRouteHeadInputs } from "./app-page-head.js";
9
10
  import { createAppPageSearchParamsObserver, makeObservedAppPageSearchParamsThenable } from "./app-page-search-params-observation.js";
10
11
  import { buildAppPageElements, createAppPageSourcePage, createAppPageTreePath } from "./app-page-route-wiring.js";
12
+ import { resolveHttpAccessFallbackMetadata, resolveHttpAccessFallbackViewport } from "./app-page-http-access-fallback-metadata.js";
13
+ import "./app-rsc-route-matching.js";
14
+ import { resolveAppPageParentHttpAccessBoundary } from "./app-page-boundary.js";
15
+ import { sanitizeErrorForClient } from "./app-rsc-errors.js";
11
16
  import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
12
17
  import { shouldServeStreamingMetadata } from "./streaming-metadata.js";
13
- import "./app-rsc-route-matching.js";
14
- import { createElement } from "react";
18
+ import { Suspense, createElement } from "react";
15
19
  //#region src/server/app-page-element-builder.ts
16
20
  function resolveInterceptLayoutParams(branchSegments, layoutSegments, params) {
17
21
  return resolveAppPageBranchParams(branchSegments, layoutSegments.length, params, layoutSegments);
@@ -41,7 +45,7 @@ function isReactOwnedPageComponent(component) {
41
45
  async function buildPageElements(options) {
42
46
  const { route, params, routePath, displayPathname = routePath, pageRequest, globalErrorModule, rootNotFoundModule, rootForbiddenModule, rootUnauthorizedModule, metadataRoutes } = options;
43
47
  const slotParamOverrides = resolveSlotParamOverrides(route, routePath);
44
- const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION, observeMetadataSearchParamsAccess = false, observePageSearchParamsAccess = false, serveStreamingMetadata } = pageRequest;
48
+ const { opts, searchParams, isRscRequest, mountedSlotsHeader, renderMode = APP_RSC_RENDER_MODE_NAVIGATION, observeMetadataSearchParamsAccess = false, observePageSearchParamsAccess = false, serveStreamingMetadata, isProduction = process.env.NODE_ENV === "production" } = pageRequest;
45
49
  const pageModule = route.page;
46
50
  const isSiblingIntercept = opts?.interceptSlotKey === "__vinext_page_intercept" && !!opts?.interceptPage;
47
51
  const effectivePageModule = isSiblingIntercept ? opts.interceptPage : pageModule;
@@ -76,38 +80,116 @@ async function buildPageElements(options) {
76
80
  [renderIdentity.routeId]: createElement("div", null, "Page has no default export")
77
81
  };
78
82
  }
79
- const { hasDynamicMetadata, metadata: resolvedMetadata, pageSearchParams, viewport: resolvedViewport } = await resolveAppPageHead({
80
- applyFileBasedMetadata: options.applyFileBasedMetadata,
81
- basePath: options.basePath ?? "",
82
- layoutModules: route.layouts,
83
+ const activeParallelRouteHeadInputs = resolveActiveParallelRouteHeadInputs({
84
+ interceptBranchSegments: opts?.interceptBranchSegments ?? null,
85
+ interceptLayouts: opts?.interceptLayouts ?? null,
86
+ interceptLayoutSegments: opts?.interceptLayoutSegments ?? null,
87
+ interceptNotFoundBranchSegments: opts?.interceptNotFoundBranchSegments ?? null,
88
+ interceptNotFound: opts?.interceptNotFound ?? null,
89
+ interceptNotFoundTreePosition: opts?.interceptNotFoundTreePosition ?? null,
90
+ interceptPage: opts?.interceptPage ?? null,
91
+ interceptParams: opts?.interceptParams ?? null,
92
+ interceptSlotKey: opts?.interceptSlotKey ?? null,
93
+ interceptSourcePageSegments: opts?.interceptSourcePageSegments ?? null,
83
94
  layoutTreePositions: route.layoutTreePositions,
84
- metadataRoutes,
85
- pageModule: isSiblingIntercept ? null : effectivePageModule ?? null,
86
- parallelRoutes: [...resolveActiveParallelRouteHeadInputs({
87
- interceptBranchSegments: opts?.interceptBranchSegments ?? null,
88
- interceptLayouts: opts?.interceptLayouts ?? null,
89
- interceptLayoutSegments: opts?.interceptLayoutSegments ?? null,
90
- interceptPage: opts?.interceptPage ?? null,
91
- interceptParams: opts?.interceptParams ?? null,
92
- interceptSlotKey: opts?.interceptSlotKey ?? null,
93
- layoutTreePositions: route.layoutTreePositions,
94
- params,
95
- routeSegments: route.routeSegments ?? [],
96
- slotParams: slotParamOverrides,
97
- slots: route.slots ?? null
98
- }), ...isSiblingIntercept ? [{
95
+ params,
96
+ routeSegments: route.routeSegments ?? [],
97
+ slotParams: slotParamOverrides,
98
+ slots: route.slots ?? null
99
+ });
100
+ const primaryParallelRouteHeadInput = isSiblingIntercept ? {
101
+ head: {
99
102
  layoutModules: opts?.interceptLayouts ?? [],
100
103
  layoutParams: (opts?.interceptLayoutSegments ?? []).map((segments) => resolveInterceptLayoutParams(opts?.interceptBranchSegments ?? segments, segments, effectiveParams)),
101
104
  pageModule: effectivePageModule ?? null,
102
105
  params: effectiveParams,
103
106
  routeSegments: opts?.interceptSourcePageSegments ?? route.routeSegments ?? []
104
- }] : []],
107
+ },
108
+ ...opts?.interceptNotFound ? {
109
+ notFoundModule: opts.interceptNotFound,
110
+ notFoundParams: resolveAppPageBranchParams(opts.interceptNotFoundBranchSegments ?? opts.interceptBranchSegments ?? route.routeSegments ?? [], opts.interceptNotFoundTreePosition ?? 0, effectiveParams)
111
+ } : {},
112
+ ownerTreePosition: route.routeSegments?.length ?? 0
113
+ } : null;
114
+ const parallelRoutes = [...primaryParallelRouteHeadInput ? [primaryParallelRouteHeadInput.head] : [], ...activeParallelRouteHeadInputs.map((input) => input.head)];
115
+ const metadataSearchParamsObserver = observeMetadataSearchParamsAccess ? createAppPageSearchParamsObserver() : void 0;
116
+ const preparedHead = prepareAppPageHead({
117
+ applyFileBasedMetadata: options.applyFileBasedMetadata,
118
+ basePath: options.basePath ?? "",
119
+ layoutModules: route.layouts,
120
+ layoutTreePositions: route.layoutTreePositions,
121
+ metadataRoutes,
122
+ pageModule: isSiblingIntercept ? null : effectivePageModule ?? null,
123
+ parallelRoutes,
105
124
  params: effectiveParams,
106
125
  routePath: route.pattern,
107
126
  routeSegments: route.routeSegments ?? null,
108
127
  searchParams,
109
- searchParamsObserver: observeMetadataSearchParamsAccess ? createAppPageSearchParamsObserver() : void 0
128
+ searchParamsObserver: metadataSearchParamsObserver
110
129
  });
130
+ const { hasDynamicMetadata, pageSearchParams } = preparedHead;
131
+ const streamGeneratedHead = serveStreamingMetadata ?? shouldServeStreamingMetadata(pageRequest.request.headers.get("user-agent") ?? "", options.htmlLimitedBots);
132
+ const metadataPlacement = hasDynamicMetadata && streamGeneratedHead ? "body" : "head";
133
+ const shouldDeferMetadata = metadataPlacement === "body";
134
+ const streamingMetadata = shouldDeferMetadata ? isProduction ? preparedHead.metadata.catch((error) => {
135
+ throw sanitizeErrorForClient(error, "production");
136
+ }) : preparedHead.metadata : null;
137
+ streamingMetadata?.catch(() => null);
138
+ const resolveNotFoundFallbackPlanOptions = () => {
139
+ const routeBoundaryModule = route.notFound;
140
+ const parentBoundary = resolveAppPageParentHttpAccessBoundary({
141
+ layoutIndex: route.layouts.length,
142
+ rootForbiddenModule,
143
+ rootNotFoundModule,
144
+ rootUnauthorizedModule,
145
+ routeForbiddenModules: route.forbiddens,
146
+ routeNotFoundModules: route.notFounds,
147
+ routeUnauthorizedModules: route.unauthorizeds,
148
+ statusCode: 404
149
+ });
150
+ const boundaryModule = routeBoundaryModule ?? parentBoundary.module;
151
+ const boundaryTreePosition = routeBoundaryModule ? route.notFoundTreePosition : parentBoundary.layoutIndex === null ? null : route.layoutTreePositions?.[parentBoundary.layoutIndex];
152
+ return {
153
+ boundaryModule,
154
+ boundaryParams: boundaryModule && boundaryTreePosition != null ? resolveAppPageSegmentParams(route.routeSegments ?? [], boundaryTreePosition, effectiveParams) : {},
155
+ layoutModules: route.layouts,
156
+ layoutTreePositions: route.layoutTreePositions,
157
+ parallelBranches: activeParallelRouteHeadInputs,
158
+ params: effectiveParams,
159
+ primaryParallelBranch: primaryParallelRouteHeadInput,
160
+ routeSegments: route.routeSegments ?? null
161
+ };
162
+ };
163
+ let viewportErrorOutlet = null;
164
+ let metadataErrorOutlet = null;
165
+ const resolveMetadataErrorTags = async (error) => {
166
+ if (resolveAppPageSpecialError(error)?.kind !== "http-access-fallback") return null;
167
+ return resolveHttpAccessFallbackMetadata({
168
+ applyFileBasedMetadata: options.applyFileBasedMetadata,
169
+ basePath: options.basePath ?? "",
170
+ ...resolveNotFoundFallbackPlanOptions(),
171
+ metadataRoutes,
172
+ routePath: route.pattern
173
+ }).catch(() => null);
174
+ };
175
+ const [resolvedMetadata, resolvedViewport] = await Promise.all([shouldDeferMetadata ? Promise.resolve(null) : preparedHead.metadata.catch((error) => {
176
+ metadataErrorOutlet = Promise.reject(isProduction ? sanitizeErrorForClient(error, "production") : error);
177
+ metadataErrorOutlet.catch(() => null);
178
+ return resolveMetadataErrorTags(error);
179
+ }), preparedHead.viewport.catch(async (error) => {
180
+ const specialError = resolveAppPageSpecialError(error);
181
+ viewportErrorOutlet = Promise.reject(isProduction ? sanitizeErrorForClient(error, "production") : error);
182
+ viewportErrorOutlet.catch(() => null);
183
+ return specialError?.kind === "http-access-fallback" ? resolveHttpAccessFallbackViewport(resolveNotFoundFallbackPlanOptions()).catch(() => ({})) : {};
184
+ })]);
185
+ const streamingMetadataTags = shouldDeferMetadata ? preparedHead.metadata.catch(resolveMetadataErrorTags) : null;
186
+ const streamingMetadataOutletInputs = [
187
+ streamingMetadata,
188
+ metadataErrorOutlet,
189
+ viewportErrorOutlet
190
+ ].filter((promise) => promise !== null).map((promise) => Promise.resolve(promise));
191
+ const streamingMetadataOutlet = streamingMetadataOutletInputs.length > 0 ? Promise.all(streamingMetadataOutletInputs).then(() => null) : null;
192
+ streamingMetadataOutlet?.catch(() => null);
111
193
  const pageProps = { params: makeThenableParams(effectiveParams) };
112
194
  const hasRequestSearchParams = Object.keys(pageSearchParams).length > 0;
113
195
  const createPageElement = (PageComponent, props) => {
@@ -127,13 +209,36 @@ async function buildPageElements(options) {
127
209
  const pageSearchParamsThenable = searchParams ? makeThenableParams(pageSearchParams) : void 0;
128
210
  const mountedSlotIds = mountedSlotsHeader ? new Set(mountedSlotsHeader.split(" ")) : null;
129
211
  const slotOverrides = buildSlotOverrides(route, params, routePath, opts);
130
- const metadataPlacement = hasDynamicMetadata && (serveStreamingMetadata ?? shouldServeStreamingMetadata(pageRequest.request.headers.get("user-agent") ?? "", options.htmlLimitedBots)) ? "body" : "head";
131
212
  let siblingInterceptElement = isSiblingIntercept && EffectivePageComponent ? createPageElement(EffectivePageComponent, pageProps) : null;
132
- if (isSiblingIntercept && siblingInterceptElement !== null && opts?.interceptLayouts?.length) for (let i = opts.interceptLayouts.length - 1; i >= 0; i--) {
133
- const LayoutComponent = opts.interceptLayouts[i]?.default;
134
- if (LayoutComponent) {
135
- const interceptLayoutSegments = opts.interceptLayoutSegments?.[i] ?? [];
136
- siblingInterceptElement = createElement(LayoutComponent, { params: makeThenableParams(resolveInterceptLayoutParams(opts.interceptBranchSegments ?? interceptLayoutSegments, interceptLayoutSegments, effectiveParams)) }, siblingInterceptElement);
213
+ if (isSiblingIntercept && siblingInterceptElement !== null) {
214
+ const layoutIndexesByTreePosition = /* @__PURE__ */ new Map();
215
+ for (const [index, layoutModule] of (opts?.interceptLayouts ?? []).entries()) {
216
+ if (!layoutModule?.default) continue;
217
+ const treePosition = opts?.interceptLayoutSegments?.[index]?.length ?? 0;
218
+ const indexes = layoutIndexesByTreePosition.get(treePosition) ?? [];
219
+ indexes.push(index);
220
+ layoutIndexesByTreePosition.set(treePosition, indexes);
221
+ }
222
+ const loadingIndexesByTreePosition = /* @__PURE__ */ new Map();
223
+ for (const [index, loadingModule] of (opts?.interceptLoadings ?? []).entries()) {
224
+ if (!loadingModule?.default) continue;
225
+ const treePosition = opts?.interceptLoadingTreePositions?.[index];
226
+ if (treePosition !== void 0) loadingIndexesByTreePosition.set(treePosition, index);
227
+ }
228
+ const treePositions = Array.from(/* @__PURE__ */ new Set([...layoutIndexesByTreePosition.keys(), ...loadingIndexesByTreePosition.keys()])).sort((left, right) => left - right);
229
+ for (let index = treePositions.length - 1; index >= 0; index--) {
230
+ const treePosition = treePositions[index];
231
+ const loadingIndex = loadingIndexesByTreePosition.get(treePosition);
232
+ const LoadingComponent = loadingIndex === void 0 ? null : opts?.interceptLoadings?.[loadingIndex]?.default;
233
+ if (LoadingComponent) siblingInterceptElement = createElement(Suspense, { fallback: createElement(LoadingComponent) }, siblingInterceptElement);
234
+ const layoutIndexes = layoutIndexesByTreePosition.get(treePosition) ?? [];
235
+ for (let layoutOffset = layoutIndexes.length - 1; layoutOffset >= 0; layoutOffset--) {
236
+ const layoutIndex = layoutIndexes[layoutOffset];
237
+ const LayoutComponent = opts?.interceptLayouts?.[layoutIndex]?.default;
238
+ if (!LayoutComponent) continue;
239
+ const interceptLayoutSegments = opts?.interceptLayoutSegments?.[layoutIndex] ?? [];
240
+ siblingInterceptElement = createElement(LayoutComponent, { params: makeThenableParams(resolveInterceptLayoutParams(opts?.interceptBranchSegments ?? interceptLayoutSegments, interceptLayoutSegments, effectiveParams)) }, siblingInterceptElement);
241
+ }
137
242
  }
138
243
  }
139
244
  return buildAppPageElements({
@@ -149,6 +254,10 @@ async function buildPageElements(options) {
149
254
  resolvedMetadata,
150
255
  resolvedMetadataPathname: routePath,
151
256
  resolvedViewport,
257
+ streamingMetadata,
258
+ streamingMetadataOutlet,
259
+ streamingMetadataOutletSuspended: streamGeneratedHead,
260
+ streamingMetadataTags,
152
261
  renderIdentity,
153
262
  routePath,
154
263
  sourcePageSegments,
@@ -182,6 +291,8 @@ function buildSlotOverrides(route, routeParams, routePath, opts) {
182
291
  branchSegments: opts.interceptBranchSegments ?? null,
183
292
  layoutModules: opts.interceptLayouts || null,
184
293
  layoutSegments: opts.interceptLayoutSegments ?? null,
294
+ loadingModules: opts.interceptLoadings || null,
295
+ loadingTreePositions: opts.interceptLoadingTreePositions ?? null,
185
296
  pageModule: opts.interceptPage,
186
297
  params: opts.interceptParams || routeParams,
187
298
  routeSegments: resolveInterceptedSlotSegments(opts.interceptSourcePageSegments, opts.interceptSlotKey)
@@ -293,4 +404,4 @@ function collectParamNameSet(params) {
293
404
  return set;
294
405
  }
295
406
  //#endregion
296
- export { buildPageElements, resolveAppPageNavigationParams, resolveInterceptedSlotSegments };
407
+ export { buildPageElements, resolveAppPageNavigationParams, resolveInterceptedSlotSegments, resolveSlotParamOverrides };
@@ -1,13 +1,21 @@
1
1
  import { MetadataFileRoute } from "./metadata-routes.js";
2
2
  import { AppPageParams } from "./app-page-boundary.js";
3
3
  import { ThenableParamsObserver } from "../shims/thenable-params.js";
4
- import { Metadata, Viewport } from "../shims/metadata.js";
4
+ import { Metadata, ResolvedViewport } from "../shims/metadata.js";
5
5
  import { applyFileBasedMetadata } from "./file-based-metadata.js";
6
6
 
7
7
  //#region src/server/app-page-head.d.ts
8
8
  type AppPageSearchParams = Record<string, string | string[]>;
9
9
  type AppPageHeadModule = Record<string, unknown>;
10
10
  type ApplyAppPageFileBasedMetadata = typeof applyFileBasedMetadata;
11
+ type OrderedAppPageMetadataSource<TModule extends AppPageHeadModule = AppPageHeadModule> = {
12
+ /** Preserve an empty result as the most specific file-metadata source. */includeWhenEmpty?: boolean;
13
+ module: TModule;
14
+ params: AppPageParams;
15
+ routeSegments: readonly string[];
16
+ searchParams?: AppPageSearchParams;
17
+ searchParamsObserver?: ThenableParamsObserver;
18
+ };
11
19
  type AppPageHeadParallelRoute<TModule extends AppPageHeadModule = AppPageHeadModule> = {
12
20
  layoutParams?: readonly AppPageParams[] | null;
13
21
  layoutModule?: TModule | null;
@@ -17,11 +25,19 @@ type AppPageHeadParallelRoute<TModule extends AppPageHeadModule = AppPageHeadMod
17
25
  params?: AppPageParams | null;
18
26
  routeSegments?: readonly string[] | null;
19
27
  };
28
+ type ActiveParallelRouteHeadInput<TModule extends AppPageHeadModule = AppPageHeadModule> = {
29
+ head: AppPageHeadParallelRoute<TModule>;
30
+ notFoundModule?: TModule | null;
31
+ notFoundParams?: AppPageParams | null;
32
+ ownerTreePosition: number;
33
+ };
20
34
  type AppPageHeadSlot<TModule extends AppPageHeadModule = AppPageHeadModule> = {
21
35
  configLayouts?: readonly (TModule | null | undefined)[] | null;
22
36
  configLayoutTreePositions?: readonly number[] | null;
23
37
  layout?: TModule | null;
24
38
  layoutIndex?: number;
39
+ notFound?: TModule | null;
40
+ notFoundTreePosition?: number | null;
25
41
  page?: TModule | null;
26
42
  routeSegments?: readonly string[] | null;
27
43
  };
@@ -30,8 +46,12 @@ type ResolveActiveParallelRouteHeadInputsOptions<TModule extends AppPageHeadModu
30
46
  interceptBranchSegments?: readonly string[] | null;
31
47
  interceptLayoutSegments?: readonly (readonly string[])[] | null;
32
48
  interceptPage?: TModule | null;
49
+ interceptNotFoundBranchSegments?: readonly string[] | null;
50
+ interceptNotFound?: TModule | null;
51
+ interceptNotFoundTreePosition?: number | null;
33
52
  interceptParams?: AppPageParams | null;
34
53
  interceptSlotKey?: string | null;
54
+ interceptSourcePageSegments?: readonly string[] | null;
35
55
  layoutTreePositions?: readonly number[] | null;
36
56
  params: AppPageParams;
37
57
  routeSegments: readonly string[];
@@ -59,19 +79,51 @@ type ResolveAppPageHeadOptions<TModule extends AppPageHeadModule = AppPageHeadMo
59
79
  searchParams?: URLSearchParams | null;
60
80
  searchParamsObserver?: ThenableParamsObserver;
61
81
  };
82
+ type AppPageMetadataOutputOptions = {
83
+ applyFileBasedMetadata?: ApplyAppPageFileBasedMetadata;
84
+ basePath?: string;
85
+ fallbackOnFileMetadataError?: boolean;
86
+ metadataRoutes: readonly MetadataFileRoute[];
87
+ params: AppPageParams;
88
+ routePath: string;
89
+ routeSegments?: readonly string[] | null;
90
+ };
91
+ type ResolveOrderedAppPageMetadataOptions<TModule extends AppPageHeadModule = AppPageHeadModule> = AppPageMetadataOutputOptions & {
92
+ sources: readonly OrderedAppPageMetadataSource<TModule>[];
93
+ };
62
94
  type ResolveAppPageHeadResult = {
63
95
  hasDynamicMetadata: boolean;
64
96
  hasSearchParams: boolean;
65
97
  metadata: Metadata | null;
66
98
  pageSearchParams: AppPageSearchParams;
67
- viewport: Viewport;
99
+ viewport: ResolvedViewport;
100
+ };
101
+ type PreparedAppPageHead = Omit<ResolveAppPageHeadResult, "metadata" | "viewport"> & {
102
+ metadata: Promise<Metadata | null>;
103
+ viewport: Promise<ResolvedViewport>;
68
104
  };
69
105
  type AppPageSearchParamsCollection = {
70
106
  hasSearchParams: boolean;
71
107
  pageSearchParams: AppPageSearchParams;
72
108
  };
73
- declare function resolveActiveParallelRouteHeadInputs<TModule extends AppPageHeadModule>(options: ResolveActiveParallelRouteHeadInputsOptions<TModule>): AppPageHeadParallelRoute<TModule>[];
109
+ declare function resolveActiveParallelRouteHeadInputs<TModule extends AppPageHeadModule>(options: ResolveActiveParallelRouteHeadInputsOptions<TModule>): ActiveParallelRouteHeadInput<TModule>[];
74
110
  declare function collectAppPageSearchParams(searchParams: URLSearchParams | null | undefined): AppPageSearchParamsCollection;
111
+ /**
112
+ * Resolve an explicit metadata-source sequence.
113
+ *
114
+ * Route-specific conventions own source selection and ordering. This resolver
115
+ * only supplies each source with its accumulated parent, merges the results,
116
+ * and applies file-based metadata at the end.
117
+ */
118
+ declare function resolveOrderedAppPageMetadata<TModule extends AppPageHeadModule>(options: ResolveOrderedAppPageMetadataOptions<TModule>): Promise<Metadata | null>;
75
119
  declare function resolveAppPageHead<TModule extends AppPageHeadModule>(options: ResolveAppPageHeadOptions<TModule>): Promise<ResolveAppPageHeadResult>;
120
+ /**
121
+ * Start metadata and viewport resolution without coupling their completion.
122
+ *
123
+ * Live document renders can place the metadata promise behind Suspense while
124
+ * still waiting for viewport tags before the shell is emitted. Blocking
125
+ * callers use {@link resolveAppPageHead} and observe the same result as before.
126
+ */
127
+ declare function prepareAppPageHead<TModule extends AppPageHeadModule>(options: ResolveAppPageHeadOptions<TModule>): PreparedAppPageHead;
76
128
  //#endregion
77
- export { AppPageSearchParams, ApplyAppPageFileBasedMetadata, collectAppPageSearchParams, resolveActiveParallelRouteHeadInputs, resolveAppPageHead };
129
+ export { ActiveParallelRouteHeadInput, AppPageHeadModule, AppPageHeadParallelRoute, AppPageSearchParams, ApplyAppPageFileBasedMetadata, OrderedAppPageMetadataSource, PreparedAppPageHead, ResolveAppPageHeadResult, ResolveOrderedAppPageMetadataOptions, collectAppPageSearchParams, prepareAppPageHead, resolveActiveParallelRouteHeadInputs, resolveAppPageHead, resolveOrderedAppPageMetadata };