vinext 0.1.8 → 0.2.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 (285) hide show
  1. package/README.md +51 -30
  2. package/dist/build/css-url-assets.d.ts +3 -1
  3. package/dist/build/css-url-assets.js +18 -1
  4. package/dist/build/inject-pregenerated-paths.d.ts +7 -0
  5. package/dist/build/inject-pregenerated-paths.js +21 -0
  6. package/dist/build/layout-classification.js +1 -1
  7. package/dist/build/nitro-route-rules.js +1 -1
  8. package/dist/build/pages-client-assets-module.d.ts +11 -0
  9. package/dist/build/pages-client-assets-module.js +27 -0
  10. package/dist/build/prerender-server-entry.d.ts +1 -0
  11. package/dist/build/prerender-server-entry.js +49 -0
  12. package/dist/build/prerender-server-pool.d.ts +44 -0
  13. package/dist/build/prerender-server-pool.js +194 -0
  14. package/dist/build/prerender.d.ts +2 -1
  15. package/dist/build/prerender.js +98 -27
  16. package/dist/build/report.d.ts +13 -2
  17. package/dist/build/report.js +99 -2
  18. package/dist/build/run-prerender.d.ts +7 -0
  19. package/dist/build/run-prerender.js +12 -2
  20. package/dist/build/standalone.js +2 -0
  21. package/dist/cache/cache-adapters-virtual.js +3 -3
  22. package/dist/check.d.ts +4 -6
  23. package/dist/check.js +48 -11
  24. package/dist/cli-args.d.ts +1 -2
  25. package/dist/cli-args.js +1 -1
  26. package/dist/cli-dev-config.d.ts +12 -0
  27. package/dist/cli-dev-config.js +23 -0
  28. package/dist/cli.js +112 -96
  29. package/dist/{server → client}/dev-error-overlay-store.d.ts +1 -1
  30. package/dist/{server → client}/dev-error-overlay-store.js +1 -1
  31. package/dist/{server → client}/dev-error-overlay.d.ts +1 -1
  32. package/dist/{server → client}/dev-error-overlay.js +2 -2
  33. package/dist/client/navigation-runtime.d.ts +2 -0
  34. package/dist/client/navigation-runtime.js +3 -1
  35. package/dist/client/vinext-next-data.d.ts +4 -1
  36. package/dist/client/window-next.d.ts +2 -1
  37. package/dist/cloudflare/index.d.ts +2 -2
  38. package/dist/cloudflare/index.js +2 -2
  39. package/dist/config/config-matchers.js +45 -19
  40. package/dist/config/next-config.d.ts +41 -9
  41. package/dist/config/next-config.js +60 -3
  42. package/dist/config/prerender.d.ts +34 -0
  43. package/dist/config/prerender.js +55 -0
  44. package/dist/entries/app-browser-entry.js +5 -1
  45. package/dist/entries/app-rsc-entry.d.ts +5 -3
  46. package/dist/entries/app-rsc-entry.js +44 -10
  47. package/dist/entries/app-rsc-manifest.js +2 -0
  48. package/dist/entries/pages-client-entry.d.ts +3 -0
  49. package/dist/entries/pages-client-entry.js +28 -3
  50. package/dist/entries/pages-server-entry.js +23 -6
  51. package/dist/image/image-adapters-virtual.d.ts +59 -0
  52. package/dist/image/image-adapters-virtual.js +59 -0
  53. package/dist/index.d.ts +33 -0
  54. package/dist/index.js +482 -120
  55. package/dist/init-cloudflare.d.ts +43 -0
  56. package/dist/init-cloudflare.js +839 -0
  57. package/dist/init-platform.d.ts +40 -0
  58. package/dist/init-platform.js +195 -0
  59. package/dist/init.d.ts +16 -38
  60. package/dist/init.js +209 -99
  61. package/dist/node_modules/.pnpm/am-i-vibing@0.5.0/node_modules/am-i-vibing/dist/detector-1yx2Hoe0.js +294 -0
  62. package/dist/node_modules/.pnpm/process-ancestry@0.1.0/node_modules/process-ancestry/dist/index.js +94 -0
  63. package/dist/{cloudflare → packages/cloudflare}/src/cache/cdn-adapter.runtime.js +1 -1
  64. package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.d.ts +2 -2
  65. package/dist/{cloudflare → packages/cloudflare}/src/cache/kv-data-adapter.runtime.js +9 -2
  66. package/dist/packages/cloudflare/src/deploy-config.js +150 -0
  67. package/dist/packages/cloudflare/src/deploy-help.js +55 -0
  68. package/dist/packages/cloudflare/src/deploy.js +272 -0
  69. package/dist/{cloudflare → packages/cloudflare/src}/tpr.d.ts +4 -41
  70. package/dist/{cloudflare → packages/cloudflare/src}/tpr.js +44 -20
  71. package/dist/plugins/ast-scope.d.ts +16 -0
  72. package/dist/plugins/ast-scope.js +62 -0
  73. package/dist/plugins/ast-utils.d.ts +27 -1
  74. package/dist/plugins/ast-utils.js +32 -1
  75. package/dist/plugins/css-module-imports.d.ts +14 -0
  76. package/dist/plugins/css-module-imports.js +59 -0
  77. package/dist/plugins/extensionless-dynamic-import.js +2 -2
  78. package/dist/plugins/fonts.js +1 -1
  79. package/dist/plugins/ignore-dynamic-requests.d.ts +11 -0
  80. package/dist/plugins/ignore-dynamic-requests.js +530 -0
  81. package/dist/plugins/og-assets.js +2 -1
  82. package/dist/plugins/optimize-imports.js +1 -1
  83. package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
  84. package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
  85. package/dist/plugins/sass.d.ts +17 -1
  86. package/dist/plugins/sass.js +74 -1
  87. package/dist/plugins/styled-jsx.d.ts +16 -0
  88. package/dist/plugins/styled-jsx.js +149 -0
  89. package/dist/plugins/typeof-window.d.ts +1 -1
  90. package/dist/plugins/typeof-window.js +28 -56
  91. package/dist/routing/app-route-graph.d.ts +23 -2
  92. package/dist/routing/app-route-graph.js +138 -38
  93. package/dist/routing/file-matcher.d.ts +11 -1
  94. package/dist/routing/file-matcher.js +18 -3
  95. package/dist/routing/pages-router.js +2 -2
  96. package/dist/server/api-handler.js +9 -14
  97. package/dist/server/app-browser-action-result.d.ts +4 -1
  98. package/dist/server/app-browser-action-result.js +8 -1
  99. package/dist/server/app-browser-entry.js +198 -57
  100. package/dist/server/app-browser-interception-context.d.ts +1 -0
  101. package/dist/server/app-browser-interception-context.js +4 -2
  102. package/dist/server/app-browser-navigation-controller.d.ts +2 -0
  103. package/dist/server/app-browser-navigation-controller.js +60 -31
  104. package/dist/server/app-browser-server-action-client.d.ts +1 -1
  105. package/dist/server/app-browser-server-action-client.js +8 -7
  106. package/dist/server/app-browser-state.d.ts +12 -1
  107. package/dist/server/app-browser-state.js +25 -8
  108. package/dist/server/app-browser-visible-commit.d.ts +6 -1
  109. package/dist/server/app-browser-visible-commit.js +42 -24
  110. package/dist/server/app-elements-wire.d.ts +9 -2
  111. package/dist/server/app-elements-wire.js +8 -1
  112. package/dist/server/app-elements.d.ts +2 -2
  113. package/dist/server/app-elements.js +4 -3
  114. package/dist/server/app-fallback-renderer.d.ts +2 -1
  115. package/dist/server/app-fallback-renderer.js +10 -6
  116. package/dist/server/app-hydration-cache-publication.d.ts +11 -0
  117. package/dist/server/app-hydration-cache-publication.js +43 -0
  118. package/dist/server/app-middleware.d.ts +4 -3
  119. package/dist/server/app-middleware.js +8 -3
  120. package/dist/server/app-optimistic-routing.js +11 -4
  121. package/dist/server/app-page-boundary.js +2 -1
  122. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  123. package/dist/server/app-page-cache-finalizer.js +5 -4
  124. package/dist/server/app-page-cache-render.d.ts +1 -0
  125. package/dist/server/app-page-cache-render.js +8 -4
  126. package/dist/server/app-page-cache.d.ts +1 -0
  127. package/dist/server/app-page-cache.js +27 -7
  128. package/dist/server/app-page-dispatch.d.ts +1 -0
  129. package/dist/server/app-page-dispatch.js +26 -8
  130. package/dist/server/app-page-element-builder.d.ts +2 -1
  131. package/dist/server/app-page-element-builder.js +59 -4
  132. package/dist/server/app-page-execution.js +2 -1
  133. package/dist/server/app-page-probe.js +5 -0
  134. package/dist/server/app-page-render-identity.d.ts +2 -0
  135. package/dist/server/app-page-render-identity.js +3 -2
  136. package/dist/server/app-page-render.d.ts +2 -0
  137. package/dist/server/app-page-render.js +85 -16
  138. package/dist/server/app-page-request.d.ts +14 -0
  139. package/dist/server/app-page-request.js +69 -4
  140. package/dist/server/app-page-response.d.ts +7 -0
  141. package/dist/server/app-page-response.js +16 -4
  142. package/dist/server/app-page-route-wiring.d.ts +8 -1
  143. package/dist/server/app-page-route-wiring.js +32 -18
  144. package/dist/server/app-page-segment-state.d.ts +2 -1
  145. package/dist/server/app-page-segment-state.js +3 -1
  146. package/dist/server/app-page-stream.d.ts +7 -1
  147. package/dist/server/app-page-stream.js +3 -1
  148. package/dist/server/app-route-handler-execution.js +5 -1
  149. package/dist/server/app-route-handler-response.js +1 -0
  150. package/dist/server/app-route-handler-runtime.js +1 -1
  151. package/dist/server/app-route-tree-prefetch.d.ts +43 -0
  152. package/dist/server/app-route-tree-prefetch.js +187 -0
  153. package/dist/server/app-router-entry.js +9 -2
  154. package/dist/server/app-rsc-cache-busting.d.ts +2 -1
  155. package/dist/server/app-rsc-cache-busting.js +9 -4
  156. package/dist/server/app-rsc-handler.d.ts +7 -0
  157. package/dist/server/app-rsc-handler.js +148 -39
  158. package/dist/server/app-rsc-render-mode.d.ts +3 -2
  159. package/dist/server/app-rsc-render-mode.js +4 -1
  160. package/dist/server/app-rsc-request-normalization.d.ts +6 -6
  161. package/dist/server/app-rsc-request-normalization.js +10 -8
  162. package/dist/server/app-segment-config.d.ts +11 -0
  163. package/dist/server/app-segment-config.js +62 -6
  164. package/dist/server/app-server-action-execution.d.ts +1 -0
  165. package/dist/server/app-server-action-execution.js +61 -30
  166. package/dist/server/app-ssr-entry.d.ts +3 -0
  167. package/dist/server/app-ssr-entry.js +13 -5
  168. package/dist/server/app-ssr-stream.d.ts +7 -3
  169. package/dist/server/app-ssr-stream.js +10 -6
  170. package/dist/server/app-visited-response-cache.d.ts +6 -0
  171. package/dist/server/app-visited-response-cache.js +3 -1
  172. package/dist/server/cache-control.d.ts +3 -1
  173. package/dist/server/cache-control.js +13 -1
  174. package/dist/server/client-trace-metadata.js +26 -0
  175. package/dist/server/default-global-not-found-module.d.ts +14 -0
  176. package/dist/server/default-global-not-found-module.js +14 -0
  177. package/dist/server/dev-route-files.js +4 -0
  178. package/dist/server/dev-server.d.ts +11 -1
  179. package/dist/server/dev-server.js +94 -35
  180. package/dist/server/dev-stack-sourcemap.d.ts +1 -1
  181. package/dist/server/dev-stack-sourcemap.js +1 -1
  182. package/dist/server/fetch-handler.d.ts +2 -0
  183. package/dist/server/fetch-handler.js +18 -0
  184. package/dist/server/headers.d.ts +7 -15
  185. package/dist/server/headers.js +11 -18
  186. package/dist/server/image-optimization.d.ts +51 -1
  187. package/dist/server/image-optimization.js +52 -2
  188. package/dist/server/implicit-tags.js +1 -1
  189. package/dist/server/isr-cache.d.ts +3 -2
  190. package/dist/server/isr-cache.js +9 -5
  191. package/dist/server/metadata-routes.d.ts +3 -1
  192. package/dist/server/metadata-routes.js +12 -2
  193. package/dist/server/middleware-runtime.js +6 -1
  194. package/dist/server/navigation-planner.d.ts +1 -0
  195. package/dist/server/navigation-planner.js +14 -3
  196. package/dist/server/pages-api-route.js +2 -2
  197. package/dist/server/pages-asset-tags.d.ts +4 -6
  198. package/dist/server/pages-asset-tags.js +12 -12
  199. package/dist/server/pages-client-assets.d.ts +12 -0
  200. package/dist/server/pages-client-assets.js +10 -0
  201. package/dist/server/pages-data-route.d.ts +4 -2
  202. package/dist/server/pages-data-route.js +18 -4
  203. package/dist/server/pages-dev-module-url.d.ts +2 -1
  204. package/dist/server/pages-dev-module-url.js +6 -3
  205. package/dist/server/pages-node-compat.d.ts +19 -1
  206. package/dist/server/pages-node-compat.js +81 -4
  207. package/dist/server/pages-page-data.d.ts +33 -1
  208. package/dist/server/pages-page-data.js +62 -33
  209. package/dist/server/pages-page-handler.d.ts +2 -1
  210. package/dist/server/pages-page-handler.js +38 -19
  211. package/dist/server/pages-page-response.d.ts +8 -0
  212. package/dist/server/pages-page-response.js +7 -3
  213. package/dist/server/pages-request-pipeline.d.ts +9 -5
  214. package/dist/server/pages-request-pipeline.js +55 -7
  215. package/dist/server/pages-router-entry.d.ts +30 -0
  216. package/dist/server/pages-router-entry.js +108 -0
  217. package/dist/server/prerender-manifest.d.ts +3 -1
  218. package/dist/server/prerender-route-params.js +1 -1
  219. package/dist/server/prod-server.d.ts +5 -3
  220. package/dist/server/prod-server.js +68 -39
  221. package/dist/server/request-pipeline.js +2 -1
  222. package/dist/server/seed-cache.js +4 -4
  223. package/dist/shims/app-router-scroll-state.d.ts +1 -0
  224. package/dist/shims/app-router-scroll-state.js +1 -0
  225. package/dist/shims/app-router-scroll.js +2 -1
  226. package/dist/shims/cache-handler.js +8 -1
  227. package/dist/shims/cache.js +22 -15
  228. package/dist/shims/cdn-cache.js +1 -1
  229. package/dist/shims/dynamic-preload-chunks.js +2 -1
  230. package/dist/shims/fetch-cache.d.ts +3 -1
  231. package/dist/shims/fetch-cache.js +77 -52
  232. package/dist/shims/form.d.ts +4 -2
  233. package/dist/shims/form.js +37 -43
  234. package/dist/shims/headers.d.ts +7 -1
  235. package/dist/shims/headers.js +17 -3
  236. package/dist/shims/image.js +75 -14
  237. package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
  238. package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
  239. package/dist/shims/internal/app-route-detection.d.ts +2 -17
  240. package/dist/shims/internal/app-route-detection.js +4 -17
  241. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +23 -0
  242. package/dist/shims/internal/hybrid-client-route-owner-direct.js +51 -0
  243. package/dist/shims/internal/hybrid-client-route-owner.d.ts +3 -15
  244. package/dist/shims/internal/hybrid-client-route-owner.js +40 -58
  245. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +10 -5
  246. package/dist/shims/internal/pages-data-fetch-dedup.js +84 -14
  247. package/dist/shims/internal/pages-data-target.d.ts +18 -12
  248. package/dist/shims/internal/pages-data-target.js +97 -13
  249. package/dist/shims/internal/pages-router-components.d.ts +7 -0
  250. package/dist/shims/internal/pages-router-components.js +13 -0
  251. package/dist/shims/layout-segment-context.d.ts +4 -1
  252. package/dist/shims/layout-segment-context.js +18 -4
  253. package/dist/shims/link.d.ts +1 -1
  254. package/dist/shims/link.js +224 -58
  255. package/dist/shims/navigation.d.ts +19 -3
  256. package/dist/shims/navigation.js +245 -47
  257. package/dist/shims/request-context.js +18 -0
  258. package/dist/shims/root-params.d.ts +15 -1
  259. package/dist/shims/root-params.js +21 -1
  260. package/dist/shims/router.d.ts +5 -7
  261. package/dist/shims/router.js +387 -102
  262. package/dist/shims/server.js +3 -2
  263. package/dist/shims/slot.js +3 -6
  264. package/dist/shims/unified-request-context.js +1 -0
  265. package/dist/typegen.js +1 -1
  266. package/dist/utils/client-runtime-metadata.d.ts +2 -18
  267. package/dist/utils/client-runtime-metadata.js +31 -22
  268. package/dist/utils/dev-stack-sourcemap-endpoint.d.ts +4 -0
  269. package/dist/{server → utils}/dev-stack-sourcemap-endpoint.js +1 -1
  270. package/dist/utils/domain-locale.d.ts +6 -3
  271. package/dist/{server → utils}/middleware-request-headers.d.ts +1 -1
  272. package/dist/{server → utils}/middleware-request-headers.js +3 -3
  273. package/dist/utils/project.d.ts +48 -2
  274. package/dist/utils/project.js +225 -4
  275. package/dist/utils/protocol-headers.d.ts +23 -0
  276. package/dist/utils/protocol-headers.js +23 -0
  277. package/dist/utils/react-version.d.ts +4 -0
  278. package/dist/utils/react-version.js +44 -0
  279. package/dist/utils/vite-version.d.ts +2 -0
  280. package/dist/utils/vite-version.js +11 -1
  281. package/package.json +47 -2
  282. package/dist/deploy.d.ts +0 -197
  283. package/dist/deploy.js +0 -1040
  284. package/dist/server/dev-stack-sourcemap-endpoint.d.ts +0 -4
  285. /package/dist/{cloudflare → packages/cloudflare}/src/utils/cache-control-metadata.js +0 -0
@@ -8,6 +8,7 @@ import { isValidElement } from "react";
8
8
  const APP_INTERCEPTION_SEPARATOR = "\0";
9
9
  const APP_ARTIFACT_COMPATIBILITY_KEY = "__artifactCompatibility";
10
10
  const APP_CACHE_ENTRY_REUSE_PROOF_KEY = "__cacheEntryReuseProof";
11
+ const APP_DYNAMIC_STALE_TIME_KEY = "__dynamicStaleTime";
11
12
  const APP_INTERCEPTION_KEY = "__interception";
12
13
  const APP_INTERCEPTION_CONTEXT_KEY = "__interceptionContext";
13
14
  const APP_LAYOUT_IDS_KEY = "__layoutIds";
@@ -177,6 +178,7 @@ function createAppElementsWireMetadataEntries(input) {
177
178
  [APP_INTERCEPTION_CONTEXT_KEY]: input.interceptionContext,
178
179
  [APP_LAYOUT_IDS_KEY]: layoutIds,
179
180
  [APP_ROOT_LAYOUT_KEY]: input.rootLayoutTreePath,
181
+ ...input.dynamicStaleTimeSeconds === void 0 ? {} : { [APP_DYNAMIC_STALE_TIME_KEY]: input.dynamicStaleTimeSeconds },
180
182
  ...input.sourcePage === null || input.sourcePage === void 0 ? {} : { [APP_SOURCE_PAGE_KEY]: input.sourcePage }
181
183
  };
182
184
  const entriesWithInterception = input.interception ? {
@@ -319,6 +321,7 @@ function buildOutgoingAppPayload(input) {
319
321
  if (skippedLayoutIds.size > 0) payload[APP_SKIPPED_LAYOUT_IDS_KEY] = [...skippedLayoutIds];
320
322
  payload[APP_ARTIFACT_COMPATIBILITY_KEY] = input.artifactCompatibility ?? createArtifactCompatibilityEnvelope();
321
323
  if (input.cacheEntryReuseProof) payload[APP_CACHE_ENTRY_REUSE_PROOF_KEY] = input.cacheEntryReuseProof;
324
+ if (input.dynamicStaleTimeSeconds !== void 0) payload[APP_DYNAMIC_STALE_TIME_KEY] = input.dynamicStaleTimeSeconds;
322
325
  if (input.renderObservation) payload[APP_RENDER_OBSERVATION_KEY] = input.renderObservation;
323
326
  return payload;
324
327
  }
@@ -394,10 +397,13 @@ function readAppElementsMetadata(elements) {
394
397
  const interception = parseInterceptionMetadata(elements[APP_INTERCEPTION_KEY]);
395
398
  const artifactCompatibility = readArtifactCompatibilityMetadata(elements[APP_ARTIFACT_COMPATIBILITY_KEY]);
396
399
  const cacheEntryReuseProof = parseCacheEntryReuseProofMetadata(elements[APP_CACHE_ENTRY_REUSE_PROOF_KEY]);
400
+ const dynamicStaleTime = elements[APP_DYNAMIC_STALE_TIME_KEY];
401
+ const dynamicStaleTimeSeconds = typeof dynamicStaleTime === "number" && Number.isFinite(dynamicStaleTime) && dynamicStaleTime >= 0 ? dynamicStaleTime : void 0;
397
402
  const sourcePage = readSourcePageMetadata(elements[APP_SOURCE_PAGE_KEY]);
398
403
  return {
399
404
  artifactCompatibility,
400
405
  ...cacheEntryReuseProof ? { cacheEntryReuseProof } : {},
406
+ ...dynamicStaleTimeSeconds === void 0 ? {} : { dynamicStaleTimeSeconds },
401
407
  interception,
402
408
  interceptionContext: interceptionContext ?? null,
403
409
  layoutIds,
@@ -413,6 +419,7 @@ const AppElementsWire = {
413
419
  keys: {
414
420
  artifactCompatibility: APP_ARTIFACT_COMPATIBILITY_KEY,
415
421
  cacheEntryReuseProof: APP_CACHE_ENTRY_REUSE_PROOF_KEY,
422
+ dynamicStaleTime: APP_DYNAMIC_STALE_TIME_KEY,
416
423
  interception: APP_INTERCEPTION_KEY,
417
424
  interceptionContext: APP_INTERCEPTION_CONTEXT_KEY,
418
425
  layoutIds: APP_LAYOUT_IDS_KEY,
@@ -440,4 +447,4 @@ const AppElementsWire = {
440
447
  withLayoutFlags
441
448
  };
442
449
  //#endregion
443
- export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, withLayoutFlags };
450
+ export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, withLayoutFlags };
@@ -1,4 +1,4 @@
1
- import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementValue, AppElements, AppElementsInterception, AppElementsSlotBinding, AppElementsWire, AppOutgoingElements, AppWireElements, LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, withLayoutFlags } from "./app-elements-wire.js";
1
+ import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementValue, AppElements, AppElementsInterception, AppElementsSlotBinding, AppElementsWire, AppOutgoingElements, AppWireElements, LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, withLayoutFlags } from "./app-elements-wire.js";
2
2
 
3
3
  //#region src/server/app-elements.d.ts
4
4
  declare const APP_PREFETCH_LOADING_SHELL_MARKER_KEY = "__prefetchLoadingShell";
@@ -6,4 +6,4 @@ declare function getMountedSlotIds(elements: AppElements): string[];
6
6
  declare function getMountedSlotIdsHeader(elements: AppElements): string | null;
7
7
  declare function resolveVisitedResponseInterceptionContext(requestInterceptionContext: string | null, payloadInterceptionContext: string | null): string | null;
8
8
  //#endregion
9
- export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, type AppElementValue, type AppElements, type AppElementsInterception, type AppElementsSlotBinding, AppElementsWire, type AppOutgoingElements, type AppWireElements, type LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
9
+ export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, type AppElementValue, type AppElements, type AppElementsInterception, type AppElementsSlotBinding, AppElementsWire, type AppOutgoingElements, type AppWireElements, type LayoutFlags, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
@@ -1,11 +1,12 @@
1
- import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, withLayoutFlags } from "./app-elements-wire.js";
1
+ import { APP_ARTIFACT_COMPATIBILITY_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, withLayoutFlags } from "./app-elements-wire.js";
2
2
  import { normalizeMountedSlotsHeader } from "./app-mounted-slots-header.js";
3
3
  //#region src/server/app-elements.ts
4
4
  const APP_PREFETCH_LOADING_SHELL_MARKER_KEY = "__prefetchLoadingShell";
5
5
  function getMountedSlotIds(elements) {
6
6
  return Object.keys(elements).filter((key) => {
7
7
  const value = elements[key];
8
- return AppElementsWire.isSlotId(key) && value !== null && value !== void 0 && value !== UNMATCHED_SLOT;
8
+ const parsed = AppElementsWire.parseElementKey(key);
9
+ return parsed?.kind === "slot" && parsed.name !== "children" && value !== null && value !== void 0 && value !== UNMATCHED_SLOT;
9
10
  }).sort();
10
11
  }
11
12
  function getMountedSlotIdsHeader(elements) {
@@ -15,4 +16,4 @@ function resolveVisitedResponseInterceptionContext(requestInterceptionContext, p
15
16
  return payloadInterceptionContext ?? requestInterceptionContext;
16
17
  }
17
18
  //#endregion
18
- export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
19
+ export { APP_ARTIFACT_COMPATIBILITY_KEY, APP_CACHE_ENTRY_REUSE_PROOF_KEY, APP_DYNAMIC_STALE_TIME_KEY, APP_INTERCEPTION_CONTEXT_KEY, APP_INTERCEPTION_KEY, APP_LAYOUT_FLAGS_KEY, APP_LAYOUT_IDS_KEY, APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_RENDER_OBSERVATION_KEY, APP_ROOT_LAYOUT_KEY, APP_ROUTE_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_SLOT_BINDINGS_KEY, APP_SOURCE_PAGE_KEY, APP_STATIC_SIBLINGS_KEY, APP_UNMATCHED_SLOT_WIRE_VALUE, AppElementsWire, UNMATCHED_SLOT, buildOutgoingAppPayload, compareAppElementsSlotIds, getMountedSlotIds, getMountedSlotIdsHeader, isAppElementsRecord, normalizeAppElements, normalizeAppElementsSlotBindings, readAppElementsMetadata, resolveVisitedResponseInterceptionContext, withLayoutFlags };
@@ -33,7 +33,8 @@ type AppFallbackRendererOptions<TModule extends AppPageModule = AppPageModule> =
33
33
  createRscOnErrorHandler: (request: Request, pathname: string, routePath: string) => AppPageBoundaryOnError;
34
34
  fontProviders: AppFallbackRendererFontProviders;
35
35
  getNavigationContext: () => NavigationContext | null;
36
- globalErrorModule?: TModule | null;
36
+ globalErrorModule?: TModule | null; /** Whether experimental.globalNotFound is enabled for route-miss 404s. */
37
+ globalNotFoundEnabled?: boolean;
37
38
  /**
38
39
  * Loader for the user's `app/global-not-found.tsx` module. When provided,
39
40
  * route-miss 404s render this module as a standalone document (skipping the
@@ -1,5 +1,6 @@
1
1
  import { renderAppPageErrorBoundary, renderAppPageHttpAccessFallback } from "./app-page-boundary-render.js";
2
2
  import { DEFAULT_GLOBAL_ERROR_MODULE } from "./default-global-error-module.js";
3
+ import { DEFAULT_GLOBAL_NOT_FOUND_MODULE } from "./default-global-not-found-module.js";
3
4
  import { DEFAULT_NOT_FOUND_MODULE } from "./default-not-found-module.js";
4
5
  //#region src/server/app-fallback-renderer.ts
5
6
  const EMPTY_MW_CTX = {
@@ -7,7 +8,7 @@ const EMPTY_MW_CTX = {
7
8
  status: null
8
9
  };
9
10
  function createAppFallbackRenderer(options) {
10
- const { applyFileBasedMetadata, basePath = "", clearRequestContext, createRscOnErrorHandler: buildRscOnErrorHandler, fontProviders, getNavigationContext, globalErrorModule, loadGlobalNotFoundModule, makeThenableParams, metadataRoutes, resolveChildSegments, rootBoundaries, rscRenderer, sanitizer, ssrLoader, trailingSlash } = options;
11
+ const { applyFileBasedMetadata, basePath = "", clearRequestContext, createRscOnErrorHandler: buildRscOnErrorHandler, fontProviders, getNavigationContext, globalErrorModule, globalNotFoundEnabled = false, loadGlobalNotFoundModule, makeThenableParams, metadataRoutes, resolveChildSegments, rootBoundaries, rscRenderer, sanitizer, ssrLoader, trailingSlash } = options;
11
12
  const { rootForbiddenModule, rootLayouts, rootNotFoundModule, rootUnauthorizedModule } = rootBoundaries;
12
13
  const effectiveGlobalErrorModule = globalErrorModule ?? DEFAULT_GLOBAL_ERROR_MODULE;
13
14
  const effectiveRootNotFoundModule = rootNotFoundModule ?? DEFAULT_NOT_FOUND_MODULE;
@@ -19,7 +20,8 @@ function createAppFallbackRenderer(options) {
19
20
  }
20
21
  return {
21
22
  async renderHttpAccessFallback(route, statusCode, isRscRequest, request, opts, scriptNonce, middlewareContext, callContext) {
22
- if (statusCode === 404 && !!loadGlobalNotFoundModule && !route && !opts?.boundaryComponent) {
23
+ const useGlobalNotFound = statusCode === 404 && globalNotFoundEnabled && !route && !opts?.boundaryComponent;
24
+ if (useGlobalNotFound && loadGlobalNotFoundModule) {
23
25
  const globalNotFoundModule = await resolveGlobalNotFoundModule();
24
26
  const globalNotFoundComponent = globalNotFoundModule?.default ?? null;
25
27
  if (globalNotFoundComponent) return renderAppPageHttpAccessFallback({
@@ -57,6 +59,7 @@ function createAppFallbackRenderer(options) {
57
59
  statusCode
58
60
  });
59
61
  }
62
+ const routeMissRootNotFoundModule = useGlobalNotFound ? DEFAULT_GLOBAL_NOT_FOUND_MODULE : effectiveRootNotFoundModule;
60
63
  return renderAppPageHttpAccessFallback({
61
64
  applyFileBasedMetadata,
62
65
  basePath,
@@ -75,7 +78,7 @@ function createAppFallbackRenderer(options) {
75
78
  globalErrorModule: effectiveGlobalErrorModule,
76
79
  isEdgeRuntime: callContext?.isEdgeRuntime,
77
80
  isRscRequest,
78
- layoutModules: opts?.layouts ?? null,
81
+ layoutModules: useGlobalNotFound ? [] : opts?.layouts ?? null,
79
82
  loadSsrHandler: ssrLoader,
80
83
  makeThenableParams,
81
84
  matchedParams: opts?.matchedParams ?? route?.params ?? {},
@@ -84,12 +87,13 @@ function createAppFallbackRenderer(options) {
84
87
  requestUrl: request.url,
85
88
  resolveChildSegments,
86
89
  rootForbiddenModule,
87
- rootLayouts,
88
- rootNotFoundModule: effectiveRootNotFoundModule,
90
+ rootLayouts: useGlobalNotFound ? [] : rootLayouts,
91
+ rootNotFoundModule: routeMissRootNotFoundModule,
89
92
  rootUnauthorizedModule,
90
- route,
93
+ route: useGlobalNotFound ? null : route,
91
94
  renderToReadableStream: rscRenderer,
92
95
  scriptNonce,
96
+ skipLayoutWrapping: useGlobalNotFound,
93
97
  sourcePageSegments: callContext?.sourcePageSegments,
94
98
  statusCode
95
99
  });
@@ -0,0 +1,11 @@
1
+ //#region src/server/app-hydration-cache-publication.d.ts
2
+ type HydrationCachePublication = {
3
+ commit(): void;
4
+ complete(): void;
5
+ fail(): void;
6
+ invalidate(): void;
7
+ publish(publishCandidate: () => () => void): void;
8
+ };
9
+ declare function createHydrationCachePublication(): HydrationCachePublication;
10
+ //#endregion
11
+ export { HydrationCachePublication, createHydrationCachePublication };
@@ -0,0 +1,43 @@
1
+ //#region src/server/app-hydration-cache-publication.ts
2
+ function createHydrationCachePublication() {
3
+ let state = "pending";
4
+ let pendingPublication = null;
5
+ let invalidatePublishedCandidate = null;
6
+ const publishPendingCandidate = () => {
7
+ if (state !== "committed" && state !== "complete" || pendingPublication === null) return;
8
+ const publishCandidate = pendingPublication;
9
+ pendingPublication = null;
10
+ invalidatePublishedCandidate = publishCandidate();
11
+ };
12
+ return {
13
+ commit() {
14
+ if (state !== "pending") return;
15
+ state = "committed";
16
+ publishPendingCandidate();
17
+ },
18
+ complete() {
19
+ if (state === "committed") state = "complete";
20
+ },
21
+ fail() {
22
+ if (state === "complete" || state === "invalidated") return;
23
+ state = "invalidated";
24
+ pendingPublication = null;
25
+ invalidatePublishedCandidate?.();
26
+ invalidatePublishedCandidate = null;
27
+ },
28
+ invalidate() {
29
+ if (state === "invalidated") return;
30
+ state = "invalidated";
31
+ pendingPublication = null;
32
+ invalidatePublishedCandidate?.();
33
+ invalidatePublishedCandidate = null;
34
+ },
35
+ publish(publishCandidate) {
36
+ if (state === "invalidated") return;
37
+ pendingPublication = publishCandidate;
38
+ publishPendingCandidate();
39
+ }
40
+ };
41
+ }
42
+ //#endregion
43
+ export { createHydrationCachePublication };
@@ -12,11 +12,11 @@ type ApplyAppMiddlewareOptions = {
12
12
  basePath?: string;
13
13
  cleanPathname: string;
14
14
  context: AppMiddlewareContext;
15
+ hadBasePath?: boolean;
15
16
  i18nConfig?: NextI18nConfig | null;
16
17
  /**
17
- * Whether the inbound request was a `_next/data` fetch. Captured from the
18
- * raw incoming headers by the caller, because `x-nextjs-data` is in
19
- * INTERNAL_HEADERS and is stripped before this function runs.
18
+ * Whether the inbound request was recognized as a `_next/data` fetch from
19
+ * trusted URL normalization before internal headers were stripped.
20
20
  */
21
21
  isDataRequest?: boolean;
22
22
  filePath?: string;
@@ -34,6 +34,7 @@ type ApplyAppMiddlewareOptions = {
34
34
  type ApplyAppMiddlewareResult = {
35
35
  kind: "continue";
36
36
  cleanPathname: string;
37
+ rewritten: boolean;
37
38
  search: string | null;
38
39
  } | {
39
40
  kind: "response";
@@ -1,5 +1,6 @@
1
- import { FLIGHT_HEADERS, VINEXT_MW_CTX_HEADER } from "./headers.js";
2
- import { buildRequestHeadersFromMiddlewareResponse } from "./middleware-request-headers.js";
1
+ import { VINEXT_MW_CTX_HEADER } from "../utils/protocol-headers.js";
2
+ import { FLIGHT_HEADERS } from "./headers.js";
3
+ import { buildRequestHeadersFromMiddlewareResponse } from "../utils/middleware-request-headers.js";
3
4
  import { isExternalUrl, proxyExternalRequest } from "../config/config-matchers.js";
4
5
  import { internalServerErrorResponse } from "./http-error-responses.js";
5
6
  import { cloneRequestWithHeaders, processMiddlewareHeaders } from "./request-pipeline.js";
@@ -100,6 +101,7 @@ async function applyAppMiddleware(options) {
100
101
  const forwarded = applyForwardedMiddlewareContext(options.request, options.context);
101
102
  const middlewareRequest = requestWithoutFlightHeaders(options.request);
102
103
  let cleanPathname = options.cleanPathname;
104
+ let rewritten = false;
103
105
  let search = null;
104
106
  if (forwarded.rewriteUrl) try {
105
107
  if (isExternalMiddlewareRewrite(forwarded.rewriteUrl, middlewareRequest)) return {
@@ -108,6 +110,7 @@ async function applyAppMiddleware(options) {
108
110
  };
109
111
  const rewriteParsed = new URL(forwarded.rewriteUrl, middlewareRequest.url);
110
112
  cleanPathname = rewriteParsed.pathname;
113
+ rewritten = true;
111
114
  search = rewriteParsed.search;
112
115
  } catch (e) {
113
116
  console.error("[vinext] Failed to apply forwarded middleware rewrite:", e);
@@ -116,7 +119,7 @@ async function applyAppMiddleware(options) {
116
119
  if (!forwarded.applied) {
117
120
  const result = await executeMiddleware({
118
121
  basePath: options.basePath,
119
- hadBasePath: true,
122
+ hadBasePath: options.hadBasePath ?? true,
120
123
  filePath: options.filePath,
121
124
  i18nConfig: options.i18nConfig,
122
125
  isDataRequest: options.isDataRequest,
@@ -150,6 +153,7 @@ async function applyAppMiddleware(options) {
150
153
  };
151
154
  const rewriteParsed = new URL(result.rewriteUrl, middlewareRequest.url);
152
155
  cleanPathname = rewriteParsed.pathname;
156
+ rewritten = true;
153
157
  search = rewriteParsed.search;
154
158
  }
155
159
  }
@@ -161,6 +165,7 @@ async function applyAppMiddleware(options) {
161
165
  return {
162
166
  kind: "continue",
163
167
  cleanPathname,
168
+ rewritten,
164
169
  search
165
170
  };
166
171
  }
@@ -1,9 +1,9 @@
1
1
  import { buildParams, decodeMatchedParams, splitPathnameForRouteMatch } from "../routing/utils.js";
2
2
  import { stripBasePath } from "../utils/base-path.js";
3
- import { matchRoutePattern } from "../routing/route-pattern.js";
4
3
  import { isUnknownRecord } from "../utils/record.js";
5
4
  import { AppElementsWire } from "./app-elements-wire.js";
6
5
  import "./app-elements.js";
6
+ import { matchRoutePattern } from "../routing/route-pattern.js";
7
7
  import { stripRscCacheBustingSearchParam, stripRscSuffix } from "./app-rsc-cache-busting.js";
8
8
  import { Suspense, createElement, isValidElement } from "react";
9
9
  //#region src/server/app-optimistic-routing.ts
@@ -162,8 +162,15 @@ function elementHasSuspenseFallback(value, depth = 0) {
162
162
  if (!isUnknownRecord(props)) return false;
163
163
  return elementHasSuspenseFallback(Reflect.get(props, "children"), depth + 1);
164
164
  }
165
- function getPageElementIds(elements) {
166
- return Object.keys(elements).filter((key) => AppElementsWire.parseElementKey(key)?.kind === "page").sort();
165
+ function getPageElementIds(elements, route) {
166
+ const pageElementIds = /* @__PURE__ */ new Set();
167
+ if (route.pageId && Object.hasOwn(elements, route.pageId)) pageElementIds.add(route.pageId);
168
+ for (const slotId of route.slotIds) {
169
+ const parsed = AppElementsWire.parseElementKey(slotId);
170
+ if (parsed?.kind === "slot" && parsed.name === "children" && Object.hasOwn(elements, slotId)) pageElementIds.add(slotId);
171
+ }
172
+ for (const key of Object.keys(elements)) if (AppElementsWire.parseElementKey(key)?.kind === "page") pageElementIds.add(key);
173
+ return Array.from(pageElementIds).sort();
167
174
  }
168
175
  function OptimisticRouteSegment() {
169
176
  throw OPTIMISTIC_ROUTE_SEGMENT_SUSPENSE_TRIGGER;
@@ -182,7 +189,7 @@ function createOptimisticRouteTemplate(options) {
182
189
  if (!options.allowLoadingShell && !elementHasSuspenseFallback(routeElement)) return null;
183
190
  if (options.allowLoadingShell && options.elements["__prefetchLoadingShell"] !== "LoadingBoundary") return null;
184
191
  if (options.allowLoadingShell && (routeElement === void 0 || routeElement === null)) return null;
185
- const pageElementIds = getPageElementIds(options.elements);
192
+ const pageElementIds = getPageElementIds(options.elements, match.route);
186
193
  if (pageElementIds.length === 0) return null;
187
194
  return {
188
195
  elements: options.elements,
@@ -1,6 +1,6 @@
1
1
  import { runWithFetchDedupe } from "../shims/fetch-cache.js";
2
2
  import { resolveAppPageSegmentParams } from "./app-page-params.js";
3
- import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
3
+ import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
4
4
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
5
5
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
6
6
  //#region src/server/app-page-boundary.ts
@@ -109,6 +109,7 @@ async function renderAppPageBoundaryResponse(options) {
109
109
  applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);
110
110
  mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);
111
111
  applyRscCompatibilityIdHeader(headers);
112
+ applyRscDeploymentIdHeader(headers);
112
113
  return new Response(rscStream, {
113
114
  status: options.status,
114
115
  headers
@@ -50,6 +50,7 @@ type ScheduleAppPageRscCacheWriteOptions = {
50
50
  isrSet: AppPageCacheSetter;
51
51
  interceptionContext?: string | null;
52
52
  mountedSlotsHeader?: string | null;
53
+ omitPendingDynamicCacheState?: boolean;
53
54
  renderMode?: AppRscRenderMode;
54
55
  preserveClientResponseHeaders?: boolean;
55
56
  expireSeconds?: number;
@@ -63,7 +63,8 @@ function finalizeAppPageHtmlCacheResponse(response, options) {
63
63
  cacheTags: pageTags,
64
64
  state: observationState
65
65
  });
66
- const writes = [options.isrSet(htmlKey, buildAppPageCacheValue(cachedHtml, void 0, 200, htmlRenderObservation), cachePolicy.revalidateSeconds, pageTags, cachePolicy.expireSeconds)];
66
+ const linkHeader = response.headers.get("link");
67
+ const writes = [options.isrSet(htmlKey, buildAppPageCacheValue(cachedHtml, void 0, 200, htmlRenderObservation, linkHeader ? { link: linkHeader } : void 0), cachePolicy.revalidateSeconds, pageTags, cachePolicy.expireSeconds)];
67
68
  if (options.capturedRscDataPromise) writes.push(options.capturedRscDataPromise.then((rscData) => options.isrSet(rscKey, buildAppPageCacheValue("", rscData, 200, rscRenderObservation), cachePolicy.revalidateSeconds, pageTags, cachePolicy.expireSeconds)));
68
69
  await Promise.all(writes);
69
70
  options.isrDebug?.("HTML cache written", htmlKey);
@@ -82,7 +83,7 @@ function finalizeAppPageRscCacheResponse(response, options) {
82
83
  if (!scheduleAppPageRscCacheWrite(options)) return response;
83
84
  if (options.preserveClientResponseHeaders === true) return response;
84
85
  const clientHeaders = new Headers(response.headers);
85
- applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags());
86
+ applyPendingDynamicCdnHeaders(clientHeaders, options.getPageTags(), { omitCacheState: options.omitPendingDynamicCacheState === true });
86
87
  return new Response(response.body, {
87
88
  status: response.status,
88
89
  statusText: response.statusText,
@@ -91,8 +92,8 @@ function finalizeAppPageRscCacheResponse(response, options) {
91
92
  }
92
93
  function scheduleAppPageRscCacheWrite(options) {
93
94
  const capturedRscDataPromise = options.capturedRscDataPromise;
94
- if (!capturedRscDataPromise || options.dynamicUsedDuringBuild) return false;
95
- const rscKey = options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode, options.interceptionContext);
95
+ if (!capturedRscDataPromise || options.dynamicUsedDuringBuild || options.mountedSlotsHeader) return false;
96
+ const rscKey = options.isrRscKey(options.cleanPathname, null, options.renderMode, options.interceptionContext);
96
97
  const cachePromise = (async () => {
97
98
  try {
98
99
  const rscData = await capturedRscDataPromise;
@@ -38,6 +38,7 @@ type RenderAppPageCacheArtifactsResult = {
38
38
  cacheControl?: CacheControlMetadata;
39
39
  html: string;
40
40
  htmlRenderObservation: ReturnType<typeof createAppPageRenderObservation>;
41
+ linkHeader?: string;
41
42
  rscData?: ArrayBuffer;
42
43
  rscRenderObservation?: ReturnType<typeof createAppPageRenderObservation>;
43
44
  tags: string[];
@@ -2,9 +2,9 @@ import { consumeDynamicUsage, consumeInvalidDynamicUsageError } from "../shims/h
2
2
  import { _consumeRequestScopedCacheLife } from "../shims/cache-request-state.js";
3
3
  import { getCollectedFetchTags } from "../shims/fetch-cache.js";
4
4
  import { readStreamAsText } from "../utils/text-stream.js";
5
- import { teeAppPageRscStreamForCapture } from "./app-page-execution.js";
5
+ import { buildAppPageFontLinkHeader, teeAppPageRscStreamForCapture } from "./app-page-execution.js";
6
6
  import { consumeAppPageRenderObservationState, createAppPageHtmlOutputScope, createAppPageRenderObservation, createAppPageRscOutputScope } from "./app-page-render-observation.js";
7
- import { isAppSsrRenderResult } from "./app-page-stream.js";
7
+ import { buildAppPageLinkHeader, isAppSsrRenderResult } from "./app-page-stream.js";
8
8
  import { buildAppPageTags } from "./implicit-tags.js";
9
9
  //#region src/server/app-page-cache-render.ts
10
10
  /**
@@ -16,10 +16,11 @@ import { buildAppPageTags } from "./implicit-tags.js";
16
16
  async function renderAppPageCacheArtifacts(options) {
17
17
  const rscCapture = teeAppPageRscStreamForCapture(options.renderToReadableStream(options.element, { onError: options.onError }), options.captureRscData);
18
18
  const capturedRscDataRef = { value: null };
19
+ const fontPreloads = options.getFontPreloads();
19
20
  const htmlResult = await (await options.loadSsrHandler()).handleSsr(rscCapture.ssrStream, options.getNavigationContext(), {
20
21
  links: options.getFontLinks(),
21
22
  styles: options.getFontStyles(),
22
- preloads: options.getFontPreloads()
23
+ preloads: fontPreloads
23
24
  }, {
24
25
  basePath: options.basePath,
25
26
  clientTraceMetadata: options.clientTraceMetadata,
@@ -31,7 +32,9 @@ async function renderAppPageCacheArtifacts(options) {
31
32
  capturedRscDataRef
32
33
  } : {}
33
34
  });
34
- const html = await readStreamAsText(isAppSsrRenderResult(htmlResult) ? htmlResult.htmlStream : htmlResult);
35
+ const htmlStream = isAppSsrRenderResult(htmlResult) ? htmlResult.htmlStream : htmlResult;
36
+ const linkHeader = buildAppPageLinkHeader(isAppSsrRenderResult(htmlResult) ? htmlResult.linkHeader : void 0, buildAppPageFontLinkHeader(fontPreloads), options.reactMaxHeadersLength);
37
+ const html = await readStreamAsText(htmlStream);
35
38
  let rscData;
36
39
  if (options.captureRscData) {
37
40
  const capturedPromise = capturedRscDataRef.value;
@@ -60,6 +63,7 @@ async function renderAppPageCacheArtifacts(options) {
60
63
  params: options.navigationParams,
61
64
  state: observationState
62
65
  }),
66
+ ...linkHeader ? { linkHeader } : {},
63
67
  tags,
64
68
  cacheControl: typeof cacheLife?.revalidate === "number" ? {
65
69
  revalidate: cacheLife.revalidate,
@@ -25,6 +25,7 @@ type AppPageCacheRenderResult = {
25
25
  cacheControl?: CacheControlMetadata;
26
26
  html: string;
27
27
  htmlRenderObservation?: RenderObservation;
28
+ linkHeader?: string;
28
29
  rscData: ArrayBuffer;
29
30
  rscRenderObservation?: RenderObservation;
30
31
  tags: string[];
@@ -4,7 +4,7 @@ import { applyCdnResponseHeaders } from "./cache-control.js";
4
4
  import { decideIsr } from "./isr-decision.js";
5
5
  import { buildAppPageCacheValue } from "./isr-cache.js";
6
6
  import { encodeCacheTag } from "../utils/encode-cache-tag.js";
7
- import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
7
+ import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
8
8
  import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
9
9
  import { applyEdgeRuntimeHeader } from "./app-page-response.js";
10
10
  import { hasCompleteNegativeRequestApiProof } from "./cache-proof.js";
@@ -19,7 +19,7 @@ function recordAppPageCacheOutcome(recordCacheOutcome, input) {
19
19
  function buildAppPageCacheTags(pathname, extraTags) {
20
20
  const tags = [
21
21
  pathname,
22
- `_N_T_${pathname}`,
22
+ `_N_T_${pathname.length > 1 && pathname.endsWith("/") ? pathname.slice(0, -1) : pathname}`,
23
23
  "_N_T_/layout"
24
24
  ];
25
25
  const segments = pathname.split("/");
@@ -43,6 +43,8 @@ function buildAppPageCachedHeaders(options) {
43
43
  applyCdnResponseHeaders(headers, { cacheControl: options.cacheControl });
44
44
  setCacheStateHeaders(headers, options.cacheState);
45
45
  applyEdgeRuntimeHeader(headers, options.isEdgeRuntime);
46
+ if (options.linkHeader) if (Array.isArray(options.linkHeader)) for (const value of options.linkHeader) headers.append("Link", value);
47
+ else headers.set("Link", options.linkHeader);
46
48
  if (options.mountedSlotsHeader) headers.set(VINEXT_MOUNTED_SLOTS_HEADER, options.mountedSlotsHeader);
47
49
  mergeMiddlewareResponseHeaders(headers, options.middlewareHeaders ?? null);
48
50
  return headers;
@@ -53,6 +55,15 @@ function getCachedAppPageValue(entry) {
53
55
  function hasQueryInvariantAppPageProof(cachedValue) {
54
56
  return cachedValue.renderObservation !== void 0 && hasCompleteNegativeRequestApiProof(cachedValue.renderObservation, ["searchParams"]);
55
57
  }
58
+ function resolveRegeneratedAppPageCachePolicy(options) {
59
+ let revalidateSeconds = options.routeRevalidateSeconds;
60
+ const renderRevalidateSeconds = options.renderCacheControl?.revalidate;
61
+ if (renderRevalidateSeconds !== void 0) revalidateSeconds = revalidateSeconds > 0 ? Math.min(revalidateSeconds, renderRevalidateSeconds) : renderRevalidateSeconds;
62
+ return {
63
+ expireSeconds: options.renderCacheControl?.expire ?? options.expireSeconds,
64
+ revalidateSeconds
65
+ };
66
+ }
56
67
  function buildAppPageCachedResponse(cachedValue, options) {
57
68
  const status = options.middlewareStatus ?? (cachedValue.status || 200);
58
69
  const { cacheControl } = decideIsr({
@@ -73,6 +84,7 @@ function buildAppPageCachedResponse(cachedValue, options) {
73
84
  mountedSlotsHeader: options.mountedSlotsHeader
74
85
  });
75
86
  applyRscCompatibilityIdHeader(rscHeaders);
87
+ applyRscDeploymentIdHeader(rscHeaders);
76
88
  return new Response(cachedValue.rscData, {
77
89
  status,
78
90
  headers: rscHeaders
@@ -84,6 +96,7 @@ function buildAppPageCachedResponse(cachedValue, options) {
84
96
  cacheState: options.cacheState,
85
97
  contentType: "text/html; charset=utf-8",
86
98
  isEdgeRuntime: options.isEdgeRuntime,
99
+ linkHeader: cachedValue.headers?.link,
87
100
  middlewareHeaders: options.middlewareHeaders
88
101
  });
89
102
  return new Response(cachedValue.html, {
@@ -115,7 +128,11 @@ async function serveAppPageCachedHtml(options, transformValue) {
115
128
  return response;
116
129
  }
117
130
  async function readAppPageCacheResponse(options) {
118
- const isrKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode, options.interceptionContext) : options.isrHtmlKey(options.cleanPathname);
131
+ if (options.isRscRequest && options.mountedSlotsHeader) {
132
+ options.isrDebug?.("MISS (mounted slots RSC variant)", options.cleanPathname);
133
+ return null;
134
+ }
135
+ const isrKey = options.isRscRequest ? options.isrRscKey(options.cleanPathname, null, options.renderMode, options.interceptionContext) : options.isrHtmlKey(options.cleanPathname);
119
136
  const artifact = options.isRscRequest ? "rsc" : "html";
120
137
  try {
121
138
  const cached = await options.isrGet(isrKey);
@@ -174,10 +191,13 @@ async function readAppPageCacheResponse(options) {
174
191
  if (cached?.isStale && cachedValue) {
175
192
  options.scheduleBackgroundRegeneration(isrKey, async () => {
176
193
  const revalidatedPage = await options.renderFreshPageForCache();
177
- const revalidateSeconds = revalidatedPage.cacheControl?.revalidate ?? options.revalidateSeconds;
178
- const expireSeconds = revalidatedPage.cacheControl?.expire ?? options.expireSeconds;
179
- const writes = [options.isrSet(options.isRscRequest ? isrKey : options.isrRscKey(options.cleanPathname, options.mountedSlotsHeader, options.renderMode, options.interceptionContext), buildAppPageCacheValue("", revalidatedPage.rscData, 200, revalidatedPage.rscRenderObservation), revalidateSeconds, revalidatedPage.tags, expireSeconds)];
180
- if (!options.isRscRequest) writes.push(options.isrSet(isrKey, buildAppPageCacheValue(revalidatedPage.html, void 0, 200, revalidatedPage.htmlRenderObservation), revalidateSeconds, revalidatedPage.tags, expireSeconds));
194
+ const cachePolicy = resolveRegeneratedAppPageCachePolicy({
195
+ expireSeconds: options.expireSeconds,
196
+ renderCacheControl: revalidatedPage.cacheControl,
197
+ routeRevalidateSeconds: options.revalidateSeconds
198
+ });
199
+ const writes = [options.isrSet(options.isRscRequest ? isrKey : options.isrRscKey(options.cleanPathname, null, options.renderMode, options.interceptionContext), buildAppPageCacheValue("", revalidatedPage.rscData, 200, revalidatedPage.rscRenderObservation), cachePolicy.revalidateSeconds, revalidatedPage.tags, cachePolicy.expireSeconds)];
200
+ if (!options.isRscRequest) writes.push(options.isrSet(isrKey, buildAppPageCacheValue(revalidatedPage.html, void 0, 200, revalidatedPage.htmlRenderObservation, revalidatedPage.linkHeader ? { link: revalidatedPage.linkHeader } : void 0), cachePolicy.revalidateSeconds, revalidatedPage.tags, cachePolicy.expireSeconds));
181
201
  await Promise.all(writes);
182
202
  options.isrDebug?.("regen complete", options.cleanPathname);
183
203
  });
@@ -199,6 +199,7 @@ type DispatchAppPageOptions<TRoute extends AppPageDispatchRoute> = {
199
199
  }>;
200
200
  request: Request;
201
201
  revalidateSeconds: number | null;
202
+ renderedPathAndSearch?: string | null;
202
203
  resolveRouteFetchCacheMode?: (route: TRoute) => FetchCacheMode | null;
203
204
  resolveRouteDynamicConfig?: (route: TRoute) => string | null | undefined;
204
205
  rootForbiddenModule?: AppPageModule | null;