vinext 1.0.1 → 1.2.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 (334) hide show
  1. package/README.md +93 -10
  2. package/dist/build/app-page-static-eligibility.d.ts +15 -0
  3. package/dist/build/app-page-static-eligibility.js +82 -0
  4. package/dist/build/client-build-config.d.ts +10 -0
  5. package/dist/build/client-build-config.js +18 -2
  6. package/dist/build/pages-client-assets-module.d.ts +8 -0
  7. package/dist/build/pages-client-assets-module.js +21 -1
  8. package/dist/build/prerender-paths.js +8 -81
  9. package/dist/build/prerender.js +33 -8
  10. package/dist/build/run-prerender.js +1 -1
  11. package/dist/build/server-manifest.d.ts +7 -0
  12. package/dist/build/server-manifest.js +11 -1
  13. package/dist/build/ssr-manifest.d.ts +2 -0
  14. package/dist/build/ssr-manifest.js +6 -2
  15. package/dist/cache/cache-adapters-virtual.d.ts +7 -1
  16. package/dist/cache/cache-adapters-virtual.js +3 -3
  17. package/dist/check.js +7 -6
  18. package/dist/cli.js +2 -1
  19. package/dist/client/client-redirect-matcher.d.ts +14 -0
  20. package/dist/client/client-redirect-matcher.js +37 -0
  21. package/dist/client/client-redirects.d.ts +27 -0
  22. package/dist/client/client-redirects.js +28 -0
  23. package/dist/client/client-rewrites.d.ts +2 -1
  24. package/dist/client/client-rewrites.js +1 -1
  25. package/dist/client/navigation-runtime.d.ts +11 -0
  26. package/dist/client/navigation-runtime.js +1 -1
  27. package/dist/config/config-matchers.d.ts +26 -11
  28. package/dist/config/config-matchers.js +81 -82
  29. package/dist/config/destination-params.d.ts +47 -0
  30. package/dist/config/destination-params.js +116 -0
  31. package/dist/config/next-config.d.ts +14 -0
  32. package/dist/config/next-config.js +21 -3
  33. package/dist/entries/app-rsc-entry.d.ts +6 -0
  34. package/dist/entries/app-rsc-entry.js +84 -49
  35. package/dist/entries/pages-client-entry.js +3 -1
  36. package/dist/entries/pages-server-entry.js +13 -37
  37. package/dist/index.d.ts +7 -2
  38. package/dist/index.js +193 -73
  39. package/dist/init-cloudflare.d.ts +9 -0
  40. package/dist/init-cloudflare.js +107 -31
  41. package/dist/init-platform.d.ts +4 -0
  42. package/dist/init-platform.js +27 -2
  43. package/dist/init.d.ts +1 -0
  44. package/dist/init.js +67 -3
  45. package/dist/plugins/ast-scope.d.ts +7 -0
  46. package/dist/plugins/ast-scope.js +59 -3
  47. package/dist/plugins/cache-flight-codec.d.ts +19 -0
  48. package/dist/plugins/cache-flight-codec.js +68 -0
  49. package/dist/plugins/commonjs-esm-facade.d.ts +35 -0
  50. package/dist/plugins/commonjs-esm-facade.js +80 -0
  51. package/dist/plugins/dynamic-preload-metadata.d.ts +1 -1
  52. package/dist/plugins/dynamic-preload-metadata.js +9 -8
  53. package/dist/plugins/fonts.d.ts +8 -11
  54. package/dist/plugins/fonts.js +71 -34
  55. package/dist/plugins/ignore-dynamic-requests.d.ts +1 -1
  56. package/dist/plugins/ignore-dynamic-requests.js +3 -4
  57. package/dist/plugins/middleware-server-only.d.ts +5 -4
  58. package/dist/plugins/middleware-server-only.js +8 -5
  59. package/dist/plugins/pages-node-externals.js +1 -1
  60. package/dist/plugins/rsc-scan-glob-imports.d.ts +19 -0
  61. package/dist/plugins/rsc-scan-glob-imports.js +50 -0
  62. package/dist/plugins/strip-server-exports.js +262 -98
  63. package/dist/plugins/transform-result.d.ts +9 -5
  64. package/dist/plugins/transitive-externals.js +1 -1
  65. package/dist/plugins/typeof-window.d.ts +2 -2
  66. package/dist/plugins/use-cache-callable.js +8 -2
  67. package/dist/plugins/worker-server-only-imports.d.ts +20 -0
  68. package/dist/plugins/worker-server-only-imports.js +31 -0
  69. package/dist/plugins/worker-use-server.d.ts +25 -0
  70. package/dist/plugins/worker-use-server.js +129 -0
  71. package/dist/routing/file-matcher.d.ts +1 -0
  72. package/dist/routing/file-matcher.js +1 -1
  73. package/dist/server/api-handler.d.ts +1 -0
  74. package/dist/server/api-handler.js +19 -8
  75. package/dist/server/app-browser-action-result.d.ts +1 -1
  76. package/dist/server/app-browser-action-result.js +9 -2
  77. package/dist/server/app-browser-entry.js +11 -7
  78. package/dist/server/app-browser-history-controller.d.ts +2 -0
  79. package/dist/server/app-browser-history-controller.js +8 -0
  80. package/dist/server/app-browser-interception-context.js +26 -2
  81. package/dist/server/app-browser-navigation-controller.d.ts +7 -1
  82. package/dist/server/app-browser-navigation-controller.js +94 -11
  83. package/dist/server/app-browser-server-action-client.js +1 -1
  84. package/dist/server/app-fallback-renderer.d.ts +2 -0
  85. package/dist/server/app-fallback-renderer.js +1 -0
  86. package/dist/server/app-history-state.d.ts +3 -0
  87. package/dist/server/app-history-state.js +7 -0
  88. package/dist/server/app-middleware.d.ts +11 -0
  89. package/dist/server/app-middleware.js +19 -3
  90. package/dist/server/app-optimistic-routing.js +1 -1
  91. package/dist/server/app-page-boundary-render.d.ts +5 -0
  92. package/dist/server/app-page-boundary-render.js +6 -4
  93. package/dist/server/app-page-cache-finalizer.d.ts +11 -0
  94. package/dist/server/app-page-cache-finalizer.js +41 -7
  95. package/dist/server/app-page-cache-render.d.ts +18 -0
  96. package/dist/server/app-page-cache-render.js +63 -43
  97. package/dist/server/app-page-cache.d.ts +6 -1
  98. package/dist/server/app-page-cache.js +28 -8
  99. package/dist/server/app-page-dispatch.d.ts +12 -2
  100. package/dist/server/app-page-dispatch.js +51 -33
  101. package/dist/server/app-page-element-builder.d.ts +7 -0
  102. package/dist/server/app-page-element-builder.js +27 -42
  103. package/dist/server/app-page-execution.d.ts +15 -12
  104. package/dist/server/app-page-execution.js +30 -40
  105. package/dist/server/app-page-head.d.ts +5 -0
  106. package/dist/server/app-page-head.js +9 -3
  107. package/dist/server/app-page-ppr-runtime.js +1 -1
  108. package/dist/server/app-page-probe.d.ts +0 -109
  109. package/dist/server/app-page-probe.js +3 -136
  110. package/dist/server/app-page-render-identity.d.ts +0 -1
  111. package/dist/server/app-page-render-identity.js +1 -1
  112. package/dist/server/app-page-render-observation.js +3 -3
  113. package/dist/server/app-page-render.d.ts +13 -5
  114. package/dist/server/app-page-render.js +219 -119
  115. package/dist/server/app-page-request.d.ts +0 -1
  116. package/dist/server/app-page-request.js +54 -17
  117. package/dist/server/app-page-response.d.ts +4 -3
  118. package/dist/server/app-page-response.js +4 -3
  119. package/dist/server/app-page-route-wiring.d.ts +17 -5
  120. package/dist/server/app-page-route-wiring.js +57 -35
  121. package/dist/server/app-page-rsc-render-status.d.ts +48 -0
  122. package/dist/server/app-page-rsc-render-status.js +54 -0
  123. package/dist/server/app-page-stream.d.ts +15 -8
  124. package/dist/server/app-page-stream.js +6 -0
  125. package/dist/server/app-pages-bridge.d.ts +1 -1
  126. package/dist/server/app-pages-bridge.js +2 -3
  127. package/dist/server/app-prerender-endpoints.js +9 -6
  128. package/dist/server/app-request-stage-dispatch.js +7 -3
  129. package/dist/server/app-request-stage-independent-entry.js +29 -9
  130. package/dist/server/app-response-header-provenance.d.ts +2 -0
  131. package/dist/server/app-response-header-provenance.js +10 -4
  132. package/dist/server/app-response-stage-entry.js +10 -2
  133. package/dist/server/app-route-handler-cache.d.ts +1 -0
  134. package/dist/server/app-route-handler-cache.js +1 -0
  135. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  136. package/dist/server/app-route-handler-dispatch.js +6 -3
  137. package/dist/server/app-route-handler-execution.d.ts +1 -0
  138. package/dist/server/app-route-handler-execution.js +1 -0
  139. package/dist/server/app-route-handler-runtime.d.ts +4 -1
  140. package/dist/server/app-route-handler-runtime.js +45 -24
  141. package/dist/server/app-router-entry.js +27 -8
  142. package/dist/server/app-rsc-cache-busting.js +1 -1
  143. package/dist/server/app-rsc-errors.js +20 -16
  144. package/dist/server/app-rsc-handler.d.ts +11 -0
  145. package/dist/server/app-rsc-handler.js +291 -125
  146. package/dist/server/app-rsc-request-normalization.d.ts +3 -1
  147. package/dist/server/app-rsc-request-normalization.js +4 -2
  148. package/dist/server/app-rsc-response-stage.d.ts +1 -1
  149. package/dist/server/app-rsc-response-stage.js +10 -6
  150. package/dist/server/app-rsc-route-matching.d.ts +9 -1
  151. package/dist/server/app-rsc-route-matching.js +36 -19
  152. package/dist/server/app-segment-config.d.ts +2 -1
  153. package/dist/server/app-server-action-execution.d.ts +2 -1
  154. package/dist/server/app-server-action-execution.js +62 -23
  155. package/dist/server/app-ssr-entry.d.ts +3 -2
  156. package/dist/server/app-ssr-entry.js +8 -5
  157. package/dist/server/app-ssr-stream.d.ts +6 -1
  158. package/dist/server/app-ssr-stream.js +34 -15
  159. package/dist/server/app-worker-stages.d.ts +7 -2
  160. package/dist/server/app-worker-stages.js +4 -4
  161. package/dist/server/cacheability-request.js +11 -7
  162. package/dist/server/client-build-files.d.ts +16 -0
  163. package/dist/server/client-build-files.js +36 -0
  164. package/dist/server/client-reuse-manifest.js +1 -1
  165. package/dist/server/config-headers.js +2 -0
  166. package/dist/server/dev-server.js +50 -29
  167. package/dist/server/dev-stack-sourcemap.js +18 -23
  168. package/dist/server/document-initial-head.d.ts +0 -11
  169. package/dist/server/document-initial-head.js +1 -1
  170. package/dist/server/forwarded-middleware-context.d.ts +5 -0
  171. package/dist/server/forwarded-middleware-context.js +22 -0
  172. package/dist/server/headers.d.ts +18 -1
  173. package/dist/server/headers.js +19 -2
  174. package/dist/server/http-conditional.d.ts +11 -0
  175. package/dist/server/http-conditional.js +10 -1
  176. package/dist/server/http-error-responses.d.ts +1 -1
  177. package/dist/server/image-optimization.d.ts +54 -0
  178. package/dist/server/image-optimization.js +118 -9
  179. package/dist/server/isr-cache.d.ts +10 -0
  180. package/dist/server/isr-cache.js +43 -8
  181. package/dist/server/metadata-route-response.js +9 -8
  182. package/dist/server/middleware-matcher-pattern.js +8 -4
  183. package/dist/server/middleware-matcher.d.ts +2 -0
  184. package/dist/server/middleware-matcher.js +23 -2
  185. package/dist/server/middleware-response-headers.js +2 -0
  186. package/dist/server/middleware-runtime.d.ts +13 -0
  187. package/dist/server/middleware-runtime.js +33 -20
  188. package/dist/server/middleware.d.ts +1 -1
  189. package/dist/server/middleware.js +3 -1
  190. package/dist/server/multi-stage.d.ts +19 -0
  191. package/dist/server/navigation-planner.js +1 -1
  192. package/dist/server/node-response-signal.d.ts +16 -0
  193. package/dist/server/node-response-signal.js +26 -0
  194. package/dist/server/normalize-path.d.ts +0 -13
  195. package/dist/server/normalize-path.js +1 -34
  196. package/dist/server/open-redirect.d.ts +47 -0
  197. package/dist/server/open-redirect.js +74 -1
  198. package/dist/server/pages-api-route.d.ts +3 -2
  199. package/dist/server/pages-api-route.js +4 -3
  200. package/dist/server/pages-cache-tag.d.ts +12 -0
  201. package/dist/server/pages-cache-tag.js +19 -0
  202. package/dist/server/pages-client-assets.d.ts +2 -0
  203. package/dist/server/pages-data-route.d.ts +10 -0
  204. package/dist/server/pages-data-route.js +19 -2
  205. package/dist/server/pages-document-asset-props.d.ts +5 -1
  206. package/dist/server/pages-document-asset-props.js +13 -5
  207. package/dist/server/pages-document-splice.d.ts +19 -0
  208. package/dist/server/pages-document-splice.js +55 -0
  209. package/dist/server/pages-i18n.d.ts +12 -1
  210. package/dist/server/pages-i18n.js +18 -4
  211. package/dist/server/pages-node-compat.d.ts +16 -5
  212. package/dist/server/pages-node-compat.js +20 -12
  213. package/dist/server/pages-page-data.d.ts +32 -24
  214. package/dist/server/pages-page-data.js +50 -120
  215. package/dist/server/pages-page-handler.d.ts +0 -6
  216. package/dist/server/pages-page-handler.js +209 -130
  217. package/dist/server/pages-page-response.d.ts +12 -6
  218. package/dist/server/pages-page-response.js +41 -34
  219. package/dist/server/pages-request-pipeline.d.ts +10 -2
  220. package/dist/server/pages-request-pipeline.js +37 -18
  221. package/dist/server/pages-request-stage-entry.d.ts +6 -0
  222. package/dist/server/pages-request-stage-entry.js +79 -16
  223. package/dist/server/pages-response-stage-entry.js +4 -0
  224. package/dist/server/pages-revalidate.js +1 -1
  225. package/dist/server/pages-router-entry.js +4 -3
  226. package/dist/server/prerender-manifest.d.ts +3 -3
  227. package/dist/server/prerender-manifest.js +4 -3
  228. package/dist/server/prerender-work-unit-setup.js +4 -0
  229. package/dist/server/prod-server.d.ts +20 -7
  230. package/dist/server/prod-server.js +343 -129
  231. package/dist/server/proper-error.d.ts +4 -0
  232. package/dist/server/proper-error.js +31 -0
  233. package/dist/server/request-pipeline.d.ts +24 -9
  234. package/dist/server/request-pipeline.js +24 -9
  235. package/dist/server/response-compression.d.ts +43 -0
  236. package/dist/server/response-compression.js +111 -0
  237. package/dist/server/revalidation-request.d.ts +1 -0
  238. package/dist/server/revalidation-request.js +1 -1
  239. package/dist/server/rsc-stream-hints.js +31 -2
  240. package/dist/server/seed-cache.d.ts +1 -0
  241. package/dist/server/seed-cache.js +15 -11
  242. package/dist/server/server-reference-loader.d.ts +4 -0
  243. package/dist/server/server-reference-loader.js +29 -0
  244. package/dist/server/socket-error-backstop.d.ts +23 -1
  245. package/dist/server/socket-error-backstop.js +69 -17
  246. package/dist/server/static-file-signal.d.ts +15 -4
  247. package/dist/server/static-file-signal.js +46 -12
  248. package/dist/server/worker-image-optimization.d.ts +34 -0
  249. package/dist/server/worker-image-optimization.js +86 -0
  250. package/dist/server/worker-stages.d.ts +1 -1
  251. package/dist/server/worker-stages.js +2 -2
  252. package/dist/server/worker-utils.d.ts +8 -3
  253. package/dist/server/worker-utils.js +12 -7
  254. package/dist/shims/app-router-scroll.js +4 -1
  255. package/dist/shims/app-router-tree-context.d.ts +5 -0
  256. package/dist/shims/app-router-tree-context.js +27 -0
  257. package/dist/shims/cache-adapter-instantiate.d.ts +50 -0
  258. package/dist/shims/cache-adapter-instantiate.js +118 -0
  259. package/dist/shims/cache-callable-runtime.d.ts +6 -42
  260. package/dist/shims/cache-callable-runtime.js +65 -174
  261. package/dist/shims/cache-flight-arguments.d.ts +22 -0
  262. package/dist/shims/cache-flight-arguments.js +56 -0
  263. package/dist/shims/cache-handler.js +1 -9
  264. package/dist/shims/cache-request-state.d.ts +15 -0
  265. package/dist/shims/cache-request-state.js +31 -8
  266. package/dist/shims/cache-runtime.d.ts +12 -20
  267. package/dist/shims/cache-runtime.js +166 -225
  268. package/dist/shims/cache.d.ts +4 -4
  269. package/dist/shims/cache.js +44 -16
  270. package/dist/shims/cacheability-classification.d.ts +7 -0
  271. package/dist/shims/cdn-cache.d.ts +8 -0
  272. package/dist/shims/cdn-cache.js +17 -1
  273. package/dist/shims/disable-smooth-scroll.d.ts +3 -0
  274. package/dist/shims/disable-smooth-scroll.js +36 -0
  275. package/dist/shims/document-placeholders.d.ts +19 -0
  276. package/dist/shims/document-placeholders.js +45 -0
  277. package/dist/shims/document.js +21 -5
  278. package/dist/shims/dynamic-preload-chunks.d.ts +1 -0
  279. package/dist/shims/dynamic-preload-chunks.js +13 -9
  280. package/dist/shims/dynamic.d.ts +1 -1
  281. package/dist/shims/dynamic.js +60 -8
  282. package/dist/shims/error-boundary-navigation.d.ts +7 -0
  283. package/dist/shims/error-boundary-navigation.js +19 -1
  284. package/dist/shims/error-boundary.d.ts +10 -10
  285. package/dist/shims/error-boundary.js +26 -7
  286. package/dist/shims/fetch-cache-state.d.ts +66 -0
  287. package/dist/shims/fetch-cache-state.js +92 -0
  288. package/dist/shims/fetch-cache.d.ts +3 -61
  289. package/dist/shims/fetch-cache.js +161 -108
  290. package/dist/shims/form.js +1 -1
  291. package/dist/shims/head.d.ts +10 -6
  292. package/dist/shims/head.js +15 -13
  293. package/dist/shims/headers.d.ts +13 -0
  294. package/dist/shims/headers.js +47 -4
  295. package/dist/shims/image.js +2 -1
  296. package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -2
  297. package/dist/shims/internal/app-page-props-cache-key.js +24 -15
  298. package/dist/shims/internal/headers-state.d.ts +0 -1
  299. package/dist/shims/internal/work-store-scope.d.ts +5 -0
  300. package/dist/shims/internal/work-store-scope.js +24 -0
  301. package/dist/shims/metadata.js +3 -3
  302. package/dist/shims/navigation-errors.d.ts +6 -0
  303. package/dist/shims/navigation-errors.js +11 -1
  304. package/dist/shims/navigation.d.ts +7 -0
  305. package/dist/shims/navigation.js +45 -9
  306. package/dist/shims/request-context.d.ts +11 -0
  307. package/dist/shims/request-state-types.d.ts +2 -1
  308. package/dist/shims/router.js +12 -20
  309. package/dist/shims/server.d.ts +16 -0
  310. package/dist/shims/server.js +24 -4
  311. package/dist/shims/thenable-params.d.ts +4 -0
  312. package/dist/shims/thenable-params.js +25 -3
  313. package/dist/shims/unified-request-context.d.ts +1 -1
  314. package/dist/shims/unified-request-context.js +1 -0
  315. package/dist/shims/url-utils.d.ts +2 -0
  316. package/dist/shims/url-utils.js +3 -1
  317. package/dist/utils/client-runtime-metadata.js +1 -1
  318. package/dist/utils/hash.d.ts +7 -0
  319. package/dist/utils/hash.js +11 -1
  320. package/dist/utils/mdx-scan.d.ts +5 -0
  321. package/dist/utils/mdx-scan.js +8 -1
  322. package/dist/utils/package-name.d.ts +6 -0
  323. package/dist/utils/package-name.js +12 -1
  324. package/dist/utils/plugin-rsc-version.d.ts +4 -0
  325. package/dist/utils/plugin-rsc-version.js +15 -0
  326. package/dist/utils/prerender-output-paths.js +15 -4
  327. package/dist/utils/public-file-path.d.ts +10 -2
  328. package/dist/utils/public-file-path.js +13 -9
  329. package/dist/utils/public-routes.js +2 -2
  330. package/dist/utils/react-version.d.ts +3 -0
  331. package/dist/utils/react-version.js +1 -1
  332. package/dist/utils/regex-safety.d.ts +10 -0
  333. package/dist/utils/regex-safety.js +70 -18
  334. package/package.json +9 -5
@@ -1,18 +1,19 @@
1
1
  import { getOrCreateAls } from "./internal/als-registry.js";
2
2
  import { getRequestContext, isInsideUnifiedScope } from "./unified-request-context.js";
3
3
  import { getRequestExecutionContext, runWithExecutionContext } from "./request-context.js";
4
+ import { isInsideWorkStoreScope } from "./internal/work-store-scope.js";
4
5
  import { workUnitAsyncStorage } from "./internal/work-unit-async-storage.js";
5
6
  import { getCdnCacheAdapter } from "./cdn-cache.js";
6
7
  import { isStagedCacheabilityProbeActive } from "./cacheability-classification.js";
7
- import { fnv1a64 } from "../utils/hash.js";
8
8
  import { MemoryCacheHandler, NoOpCacheHandler, configureMemoryCacheHandler, getCacheHandler, getDataCacheHandler, registerDataCacheHandler, registerLazyDataCacheHandler, setCacheHandler, setDataCacheHandler } from "./cache-handler.js";
9
9
  import { encodeCacheTag, encodeCacheTags } from "../utils/encode-cache-tag.js";
10
+ import { fnv1a64, sha256Hex } from "../utils/hash.js";
11
+ import { addCollectedRequestTags, getCurrentFetchSoftTags, runWithDetachedFetchObservations } from "./fetch-cache-state.js";
10
12
  import { makeHangingPromise } from "./internal/make-hanging-promise.js";
11
13
  import { getHeadersAccessPhase, markDynamicUsage } from "./internal/headers-state.js";
12
14
  import { isDraftModeEnabled } from "./headers.js";
13
15
  import { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext } from "./internal/cache-context-accessor.js";
14
- import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
15
- import { addCollectedRequestTags, getCurrentFetchSoftTags } from "./fetch-cache.js";
16
+ import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
16
17
  //#region src/shims/cache.ts
17
18
  /**
18
19
  * next/cache shim
@@ -322,6 +323,8 @@ const UNSTABLE_CACHE_KEY_PREFIX = "unstable_cache:v2";
322
323
  * a direct import (avoiding circular dependencies).
323
324
  */
324
325
  const _unstableCacheAls = getOrCreateAls("vinext.unstableCache.als");
326
+ const _useCacheContextAls = getOrCreateAls("vinext.cacheRuntime.contextAls");
327
+ const _unstableCacheCallbackAls = getOrCreateAls("vinext.unstableCache.callbackAls");
325
328
  function serializeUnstableCacheResult(value) {
326
329
  return JSON.stringify(value === void 0 ? { undef: true } : { v: value });
327
330
  }
@@ -347,6 +350,18 @@ function tryDeserializeUnstableCacheResult(body) {
347
350
  function isInsideUnstableCacheScope() {
348
351
  return _unstableCacheAls.getStore() === true;
349
352
  }
353
+ /**
354
+ * Whether an unstable_cache call is nested in another one's callback, as
355
+ * Next.js's `isNestedUnstableCache` decides: only where Next.js has a work
356
+ * store (not in Pages Router or outside a render), and only when the
357
+ * innermost cache scope is that callback rather than a "use cache" function
358
+ * it called.
359
+ * Source: https://github.com/vercel/next.js/blob/canary/packages/next/src/server/web/spec-extension/unstable-cache.ts
360
+ */
361
+ function isNestedUnstableCacheCall() {
362
+ const callback = _unstableCacheCallbackAls.getStore();
363
+ return callback !== void 0 && callback.useCacheContext === _useCacheContextAls.getStore() && isInsideWorkStoreScope();
364
+ }
350
365
  const _UNSTABLE_CACHE_PENDING_REVALIDATIONS_KEY = Symbol.for("vinext.unstableCache.pendingRevalidations");
351
366
  function getPendingUnstableCacheRevalidations() {
352
367
  const existing = _g[_UNSTABLE_CACHE_PENDING_REVALIDATIONS_KEY];
@@ -362,7 +377,7 @@ function waitUntilUnstableCacheRevalidation(promise) {
362
377
  function scheduleUnstableCacheBackgroundRevalidation(cacheKey, refresh) {
363
378
  const pending = getPendingUnstableCacheRevalidations();
364
379
  if (pending.has(cacheKey)) return;
365
- const trackedRevalidation = refresh().then(() => void 0).catch((err) => {
380
+ const trackedRevalidation = runWithDetachedCacheObservations(() => runWithDetachedFetchObservations(() => _useCacheContextAls.exit(refresh))).then(() => void 0).catch((err) => {
366
381
  console.error(`[vinext] unstable_cache background revalidation failed for ${cacheKey}:`, err);
367
382
  }).finally(() => {
368
383
  if (pending.get(cacheKey) === trackedRevalidation) pending.delete(cacheKey);
@@ -370,8 +385,10 @@ function scheduleUnstableCacheBackgroundRevalidation(cacheKey, refresh) {
370
385
  pending.set(cacheKey, trackedRevalidation);
371
386
  waitUntilUnstableCacheRevalidation(trackedRevalidation);
372
387
  }
373
- async function refreshUnstableCacheResult(fn, args, cacheKey, tags, revalidateSeconds) {
374
- const result = await _unstableCacheAls.run(true, () => fn(...args));
388
+ async function refreshUnstableCacheResult(fn, args, keyedArgs, cacheKey, tags, revalidateSeconds) {
389
+ const argsUnchanged = serializeArgsOrNull(args) === keyedArgs;
390
+ const result = await _unstableCacheAls.run(true, () => _unstableCacheCallbackAls.run({ useCacheContext: _useCacheContextAls.getStore() }, () => fn(...args)));
391
+ if (!argsUnchanged) return result;
375
392
  const cacheValue = {
376
393
  kind: "FETCH",
377
394
  data: {
@@ -389,29 +406,40 @@ async function refreshUnstableCacheResult(fn, args, cacheKey, tags, revalidateSe
389
406
  });
390
407
  return result;
391
408
  }
409
+ function serializeArgsOrNull(args) {
410
+ try {
411
+ return JSON.stringify(args);
412
+ } catch {
413
+ return null;
414
+ }
415
+ }
392
416
  /**
393
417
  * Wrap an async function with caching.
394
418
  *
395
- * Returns a new function that caches results. The cache key is derived
396
- * from keyParts + serialized arguments.
419
+ * Returns a new function that caches results. The cache key is a SHA-256
420
+ * digest of the callback source, keyParts and serialized arguments.
397
421
  */
398
422
  function unstable_cache(fn, keyParts, options) {
399
- const baseKey = keyParts ? keyParts.join(":") : fnv1a64(fn.toString());
423
+ if (typeof window !== "undefined") return function cached(...args) {
424
+ return fn.apply(this, args);
425
+ };
426
+ const fixedKey = JSON.stringify([fn.toString(), keyParts ?? null]);
400
427
  const tags = encodeCacheTags(options?.tags ?? []);
401
428
  const revalidateSeconds = options?.revalidate;
402
429
  const cachedFn = async (...args) => {
403
- const argsKey = JSON.stringify(args);
404
- const cacheKey = `${UNSTABLE_CACHE_KEY_PREFIX}:${baseKey}:${argsKey}`;
430
+ const keyedArgs = JSON.stringify(args);
431
+ const invocationKey = `${fixedKey}${keyedArgs}`;
405
432
  addCollectedRequestTags(tags);
406
433
  recordUnstableCacheObservation({
407
434
  kind: "unstable_cache",
408
- keyHash: fnv1a64(cacheKey),
435
+ keyHash: fnv1a64(invocationKey),
409
436
  revalidate: typeof revalidateSeconds === "number" ? revalidateSeconds : revalidateSeconds === false ? false : null,
410
437
  tagCount: tags.length,
411
438
  tagHash: tags.length > 0 ? fnv1a64(JSON.stringify(tags)) : null
412
439
  });
440
+ const cacheKey = `${UNSTABLE_CACHE_KEY_PREFIX}:${await sha256Hex(invocationKey)}`;
413
441
  const isDraftMode = isDraftModeEnabled();
414
- if (!isDraftMode) {
442
+ if (!isDraftMode && !isNestedUnstableCacheCall()) {
415
443
  const softTags = getCurrentFetchSoftTags();
416
444
  const existing = _hasPendingRevalidatedTag([...tags, ...softTags]) ? null : await getDataCacheHandler().get(cacheKey, {
417
445
  kind: "FETCH",
@@ -423,7 +451,7 @@ function unstable_cache(fn, keyParts, options) {
423
451
  if (cached.ok) {
424
452
  if (existing.cacheState === "stale") {
425
453
  if (shouldServeStaleUnstableCacheEntry()) {
426
- scheduleUnstableCacheBackgroundRevalidation(cacheKey, () => refreshUnstableCacheResult(fn, args, cacheKey, tags, revalidateSeconds));
454
+ scheduleUnstableCacheBackgroundRevalidation(cacheKey, () => refreshUnstableCacheResult(fn, args, keyedArgs, cacheKey, tags, revalidateSeconds));
427
455
  return cached.value;
428
456
  }
429
457
  } else return cached.value;
@@ -431,9 +459,9 @@ function unstable_cache(fn, keyParts, options) {
431
459
  }
432
460
  }
433
461
  if (isDraftMode) return await _unstableCacheAls.run(true, () => fn(...args));
434
- return await refreshUnstableCacheResult(fn, args, cacheKey, tags, revalidateSeconds);
462
+ return await refreshUnstableCacheResult(fn, args, keyedArgs, cacheKey, tags, revalidateSeconds);
435
463
  };
436
464
  return cachedFn;
437
465
  }
438
466
  //#endregion
439
- export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, MemoryCacheHandler, NoOpCacheHandler, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLife, cacheLifeProfiles, cacheTag, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, io, isInsideUnstableCacheScope, markActionRevalidation, unstable_noStore as noStore, unstable_noStore, recordUnstableCacheObservation, refresh, registerDataCacheHandler, registerLazyDataCacheHandler, revalidatePath, revalidateTag, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry, unstable_cache, unstable_cacheLife, unstable_cacheTag, unstable_io, updateTag };
467
+ export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, MemoryCacheHandler, NoOpCacheHandler, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLife, cacheLifeProfiles, cacheTag, configureMemoryCacheHandler, getAndClearActionRevalidationKind, getCacheHandler, getDataCacheHandler, getRegisteredCacheContext, getRequestExecutionContext, io, isInsideUnstableCacheScope, markActionRevalidation, unstable_noStore as noStore, unstable_noStore, recordUnstableCacheObservation, refresh, registerDataCacheHandler, registerLazyDataCacheHandler, revalidatePath, revalidateTag, runWithDetachedCacheObservations, runWithExecutionContext, setCacheHandler, setDataCacheHandler, shouldServeStaleUnstableCacheEntry, unstable_cache, unstable_cacheLife, unstable_cacheTag, unstable_io, updateTag };
@@ -10,6 +10,13 @@ export type RouteCacheabilityOutcome = {
10
10
  searchParamsUnread?: true;
11
11
  /** A transient classification failure that may succeed on another bounded attempt. */
12
12
  retryable?: true;
13
+ /**
14
+ * App page RSC: the status and headers that replace the streamed 200 of a
15
+ * render whose special error rejected its document's shell, once the
16
+ * response is complete.
17
+ */
18
+ status?: number;
19
+ headers?: Readonly<Record<string, string>>;
13
20
  tags?: readonly string[];
14
21
  };
15
22
  export type RouteCacheabilityState = {
@@ -54,6 +54,8 @@ export type CdnResponsePolicy = {
54
54
  export declare function splitCacheControlDirectives(cacheControl: string): string[];
55
55
  /** Whether a Cache-Control value contains an exact non-cacheable directive. */
56
56
  export declare function isNonCacheableCacheControl(cacheControl: string, scope?: "shared" | "browser"): boolean;
57
+ /** Whether a request carries credentials a shared response cache must not capture. */
58
+ export declare function hasSharedCacheCredentials(headers: Headers): boolean;
57
59
  /**
58
60
  * The serving strategy for page-level ISR. Implement this to delegate
59
61
  * page/route/image caching to a CDN edge instead of the origin store.
@@ -88,6 +90,12 @@ export type CdnCacheAdapter = {
88
90
  deferCompletedPageResponseAdmission?(response: Response, complete: (response: Response) => Promise<Response>): Response | null;
89
91
  /** Capture the full-route RSC side stream while admitting a completed HTML response. */
90
92
  captureAppPageRscData?(rscData: Promise<ArrayBuffer>): void;
93
+ /**
94
+ * Whether this adapter sends the 304 for a Pages render whose If-None-Match
95
+ * matches. When it does, the render returns the page, so an adapter that
96
+ * stores completed responses stores the page rather than the 304.
97
+ */
98
+ deferNotModifiedResponse?(): boolean;
91
99
  /**
92
100
  * Validate provider-specific request routing before the application handles
93
101
  * the request. Returning a response short-circuits the request pipeline;
@@ -31,6 +31,22 @@ function isNonCacheableCacheControl(cacheControl, scope = "shared") {
31
31
  return name === "no-store" || equals === -1 && (name === "no-cache" || scope === "shared" && name === "private");
32
32
  });
33
33
  }
34
+ /**
35
+ * Request headers that identify the caller. A shared response cache never
36
+ * admits a Route Handler or API response's own policy for a request carrying
37
+ * them, and never replays such a render to refill its data entries.
38
+ * `x-api-key` matches the fetch cache's credential headers.
39
+ */
40
+ const SHARED_CACHE_CREDENTIAL_HEADERS = [
41
+ "authorization",
42
+ "cookie",
43
+ "proxy-authorization",
44
+ "x-api-key"
45
+ ];
46
+ /** Whether a request carries credentials a shared response cache must not capture. */
47
+ function hasSharedCacheCredentials(headers) {
48
+ return SHARED_CACHE_CREDENTIAL_HEADERS.some((name) => headers.has(name));
49
+ }
34
50
  const PENDING_DYNAMIC_CACHE_CONTROL = "no-store, must-revalidate";
35
51
  /**
36
52
  * Default origin-managed ISR strategy: store page artifacts in the data cache,
@@ -95,4 +111,4 @@ function getCdnCacheAdapter() {
95
111
  return _defaultAdapter ??= new DefaultCdnCacheAdapter();
96
112
  }
97
113
  //#endregion
98
- export { DefaultCdnCacheAdapter, getCdnCacheAdapter, isNonCacheableCacheControl, setCdnCacheAdapter, splitCacheControlDirectives };
114
+ export { DefaultCdnCacheAdapter, getCdnCacheAdapter, hasSharedCacheCredentials, isNonCacheableCacheControl, setCdnCacheAdapter, splitCacheControlDirectives };
@@ -0,0 +1,3 @@
1
+ //#region src/shims/disable-smooth-scroll.d.ts
2
+ export declare function disableSmoothScrollDuringRouteTransition(fn: () => void): void;
3
+ //#endregion
@@ -0,0 +1,36 @@
1
+ //#region src/shims/disable-smooth-scroll.ts
2
+ /**
3
+ * Run a route-transition scroll with `scroll-behavior: auto` on `<html>`.
4
+ *
5
+ * Ported from Next.js:
6
+ * packages/next/src/shared/lib/router/utils/disable-smooth-scroll.ts
7
+ *
8
+ * Since Next.js 16 (vercel/next.js#84102) the override is opt-in: it only
9
+ * applies when the root element carries `data-scroll-behavior="smooth"`.
10
+ * Without the attribute, a page-level `scroll-behavior: smooth` is respected
11
+ * and route-change scrolls animate (development warns once about the missing
12
+ * opt-in). Hash-only navigations never use this helper, so in-page anchor
13
+ * jumps keep the smooth behavior.
14
+ */
15
+ let warnedMissingDataScrollBehavior = false;
16
+ function disableSmoothScrollDuringRouteTransition(fn) {
17
+ const htmlElement = document.documentElement;
18
+ if (htmlElement.dataset.scrollBehavior !== "smooth") {
19
+ if (process.env.NODE_ENV === "development" && !warnedMissingDataScrollBehavior && getComputedStyle(htmlElement).scrollBehavior === "smooth") {
20
+ warnedMissingDataScrollBehavior = true;
21
+ console.warn("Detected `scroll-behavior: smooth` on the `<html>` element. To disable smooth scrolling during route transitions, add `data-scroll-behavior=\"smooth\"` to your <html> element. Learn more: https://nextjs.org/docs/messages/missing-data-scroll-behavior");
22
+ }
23
+ fn();
24
+ return;
25
+ }
26
+ const previousScrollBehavior = htmlElement.style.scrollBehavior;
27
+ htmlElement.style.scrollBehavior = "auto";
28
+ htmlElement.getClientRects();
29
+ try {
30
+ fn();
31
+ } finally {
32
+ htmlElement.style.scrollBehavior = previousScrollBehavior;
33
+ }
34
+ }
35
+ //#endregion
36
+ export { disableSmoothScrollDuringRouteTransition };
@@ -0,0 +1,19 @@
1
+ import React from "react";
2
+ //#region src/shims/document-placeholders.d.ts
3
+ /** Attribute `<Head>` adds last on its opening tag. */
4
+ export declare const DOCUMENT_HEAD_OPEN_ATTRIBUTE = "data-vinext-head-open";
5
+ /** Attribute of the `<template>` `<Head>` renders as its last child. */
6
+ export declare const DOCUMENT_HEAD_CLOSE_ATTRIBUTE = "data-vinext-head-close";
7
+ export declare function createDocumentPlaceholderToken(): string;
8
+ export declare function withDocumentPlaceholders(element: React.ReactElement, token: string): React.ReactElement;
9
+ export declare function useDocumentPlaceholderToken(): string | null;
10
+ /**
11
+ * `<Main />`'s placeholder. Without a renderer-provided token (a Document
12
+ * rendered on its own, e.g. in tests) it falls back to a static comment.
13
+ */
14
+ export declare function getDocumentMainPlaceholder(token: string | null): string;
15
+ export declare function getDocumentScriptsPlaceholder(token: string | null): string;
16
+ /** The marker attribute on `<Head>`'s opening tag. */
17
+ export declare function getDocumentHeadOpenMarker(token: string): string;
18
+ export declare function getDocumentHeadCloseMarker(token: string): string;
19
+ //#endregion
@@ -0,0 +1,45 @@
1
+ import React from "react";
2
+ //#region src/shims/document-placeholders.ts
3
+ /**
4
+ * Per-render placeholders for the Pages Router `next/document` shims.
5
+ *
6
+ * The renderers splice the page body, `next/head` output, asset tags and
7
+ * hydration scripts into the serialized custom Document. Each render provides
8
+ * a fresh random token, and `<Head>`, `<Main />` and `<NextScript />` mark
9
+ * their splice points with it. Nothing the Document renders, request data in
10
+ * raw `<script>` text included, can know the token, so nothing can be mistaken
11
+ * for a splice point.
12
+ */
13
+ const DocumentPlaceholderContext = React.createContext(null);
14
+ /** Attribute `<Head>` adds last on its opening tag. */
15
+ const DOCUMENT_HEAD_OPEN_ATTRIBUTE = "data-vinext-head-open";
16
+ /** Attribute of the `<template>` `<Head>` renders as its last child. */
17
+ const DOCUMENT_HEAD_CLOSE_ATTRIBUTE = "data-vinext-head-close";
18
+ function createDocumentPlaceholderToken() {
19
+ return crypto.randomUUID();
20
+ }
21
+ function withDocumentPlaceholders(element, token) {
22
+ return React.createElement(DocumentPlaceholderContext.Provider, { value: token }, element);
23
+ }
24
+ function useDocumentPlaceholderToken() {
25
+ return React.useContext(DocumentPlaceholderContext);
26
+ }
27
+ /**
28
+ * `<Main />`'s placeholder. Without a renderer-provided token (a Document
29
+ * rendered on its own, e.g. in tests) it falls back to a static comment.
30
+ */
31
+ function getDocumentMainPlaceholder(token) {
32
+ return token ? `<!--__NEXT_MAIN__:${token}-->` : "<!-- __NEXT_MAIN__ -->";
33
+ }
34
+ function getDocumentScriptsPlaceholder(token) {
35
+ return token ? `<!--__NEXT_SCRIPTS__:${token}-->` : "<!-- __NEXT_SCRIPTS__ -->";
36
+ }
37
+ /** The marker attribute on `<Head>`'s opening tag. */
38
+ function getDocumentHeadOpenMarker(token) {
39
+ return ` ${DOCUMENT_HEAD_OPEN_ATTRIBUTE}="${token}"`;
40
+ }
41
+ function getDocumentHeadCloseMarker(token) {
42
+ return `<template ${DOCUMENT_HEAD_CLOSE_ATTRIBUTE}="${token}"></template>`;
43
+ }
44
+ //#endregion
45
+ export { DOCUMENT_HEAD_CLOSE_ATTRIBUTE, DOCUMENT_HEAD_OPEN_ATTRIBUTE, createDocumentPlaceholderToken, getDocumentHeadCloseMarker, getDocumentHeadOpenMarker, getDocumentMainPlaceholder, getDocumentScriptsPlaceholder, useDocumentPlaceholderToken, withDocumentPlaceholders };
@@ -1,4 +1,5 @@
1
1
  import { safeJsonStringify } from "../server/html.js";
2
+ import { DOCUMENT_HEAD_CLOSE_ATTRIBUTE, DOCUMENT_HEAD_OPEN_ATTRIBUTE, getDocumentMainPlaceholder, getDocumentScriptsPlaceholder, useDocumentPlaceholderToken } from "./document-placeholders.js";
2
3
  import React from "react";
3
4
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
4
5
  //#region src/shims/document.tsx
@@ -47,7 +48,7 @@ var Head = class extends React.Component {
47
48
  }
48
49
  render() {
49
50
  const { children, nonce, crossOrigin, ...props } = this.props;
50
- return /* @__PURE__ */ jsx("head", {
51
+ return /* @__PURE__ */ jsx(DocumentHeadElement, {
51
52
  ...props,
52
53
  ...nonce ? { [documentAssetMarkerAttributes.headNonce]: nonce } : {},
53
54
  ...crossOrigin ? { [documentAssetMarkerAttributes.headCrossOrigin]: crossOrigin } : {},
@@ -55,10 +56,19 @@ var Head = class extends React.Component {
55
56
  });
56
57
  }
57
58
  };
59
+ function DocumentHeadElement({ children, ...props }) {
60
+ const token = useDocumentPlaceholderToken();
61
+ return /* @__PURE__ */ jsxs("head", {
62
+ ...props,
63
+ ...token ? { [DOCUMENT_HEAD_OPEN_ATTRIBUTE]: token } : {},
64
+ children: [children, token ? /* @__PURE__ */ jsx("template", { [DOCUMENT_HEAD_CLOSE_ATTRIBUTE]: token }) : null]
65
+ });
66
+ }
58
67
  function Main() {
68
+ const token = useDocumentPlaceholderToken();
59
69
  return /* @__PURE__ */ jsx("div", {
60
70
  id: "__next",
61
- dangerouslySetInnerHTML: { __html: "__NEXT_MAIN__" }
71
+ dangerouslySetInnerHTML: { __html: getDocumentMainPlaceholder(token) }
62
72
  });
63
73
  }
64
74
  var NextScript = class extends React.Component {
@@ -80,13 +90,19 @@ var NextScript = class extends React.Component {
80
90
  }
81
91
  render() {
82
92
  const { nonce, crossOrigin } = this.props;
83
- return /* @__PURE__ */ jsx("span", {
93
+ return /* @__PURE__ */ jsx(NextScriptPlaceholder, {
84
94
  ...nonce ? { [documentAssetMarkerAttributes.scriptNonce]: nonce } : {},
85
- ...crossOrigin ? { [documentAssetMarkerAttributes.scriptCrossOrigin]: crossOrigin } : {},
86
- dangerouslySetInnerHTML: { __html: "<!-- __NEXT_SCRIPTS__ -->" }
95
+ ...crossOrigin ? { [documentAssetMarkerAttributes.scriptCrossOrigin]: crossOrigin } : {}
87
96
  });
88
97
  }
89
98
  };
99
+ function NextScriptPlaceholder(props) {
100
+ const token = useDocumentPlaceholderToken();
101
+ return /* @__PURE__ */ jsx("span", {
102
+ ...props,
103
+ dangerouslySetInnerHTML: { __html: getDocumentScriptsPlaceholder(token) }
104
+ });
105
+ }
90
106
  var Document = class extends React.Component {
91
107
  static getInitialProps(ctx) {
92
108
  return ctx.defaultGetInitialProps(ctx);
@@ -2,5 +2,6 @@ import React from "react";
2
2
  //#region src/shims/dynamic-preload-chunks.d.ts
3
3
  export declare function DynamicPreloadChunks(props: {
4
4
  moduleIds?: readonly string[];
5
+ assets: "styles" | "scripts";
5
6
  }): React.FunctionComponentElement<React.FragmentProps> | null;
6
7
  //#endregion
@@ -56,6 +56,7 @@ function DynamicPreloadChunks(props) {
56
56
  for (const file of files) {
57
57
  const assetHref = dynamicPreloadHref(file);
58
58
  if (assetHref.endsWith(".css")) {
59
+ if (props.assets !== "styles") continue;
59
60
  const href = appendAssetDeploymentIdQuery(assetHref);
60
61
  if (initialStylesheetHrefs?.has(href)) continue;
61
62
  preloadLinks.push(React.createElement("link", {
@@ -68,15 +69,18 @@ function DynamicPreloadChunks(props) {
68
69
  }));
69
70
  continue;
70
71
  }
71
- if (assetHref.endsWith(".js")) preloadLinks.push(React.createElement("link", {
72
- key: assetHref,
73
- rel: "modulepreload",
74
- href: assetHref,
75
- as: "script",
76
- crossOrigin,
77
- fetchPriority: "low",
78
- nonce
79
- }));
72
+ if (assetHref.endsWith(".js")) {
73
+ if (props.assets !== "scripts") continue;
74
+ preloadLinks.push(React.createElement("link", {
75
+ key: assetHref,
76
+ rel: "modulepreload",
77
+ href: assetHref,
78
+ as: "script",
79
+ crossOrigin,
80
+ fetchPriority: "low",
81
+ nonce
82
+ }));
83
+ }
80
84
  }
81
85
  return preloadLinks.length > 0 ? React.createElement(React.Fragment, null, ...preloadLinks) : null;
82
86
  }
@@ -4,7 +4,7 @@ import { DynamicOptions, DynamicOptionsLoadingProps, LoadableComponent, Loadable
4
4
  type DynamicInput<P> = DynamicOptions<P> | Loader<P>;
5
5
  /**
6
6
  * Retained for the Pages Router render pipeline, which calls this before
7
- * rendering. Dynamic imports now use React.lazy + Suspense, so there is no
7
+ * rendering. Dynamic imports now use React.lazy, so there is no
8
8
  * separate preload work to await.
9
9
  */
10
10
  export declare function flushPreloads(): Promise<void[]>;
@@ -1,19 +1,22 @@
1
+ import { AppRouterTreeContext } from "./app-router-tree-context.js";
1
2
  import { DynamicPreloadChunks } from "./dynamic-preload-chunks.js";
2
3
  import React from "react";
3
4
  //#region src/shims/dynamic.ts
4
5
  /**
5
6
  * next/dynamic shim
6
7
  *
7
- * SSR-safe dynamic imports. On the server, uses React.lazy + Suspense so that
8
+ * SSR-safe dynamic imports. On the server, uses React.lazy so that
8
9
  * renderToReadableStream suspends until the dynamically-imported component is
9
- * available. On the client, also uses React.lazy for code splitting.
10
+ * available. On the client, also uses React.lazy for code splitting. As in
11
+ * the Next.js App Router, a Suspense boundary is added only for `ssr: false`
12
+ * or an explicit `loading` component. Other trees (Pages Router) keep it.
10
13
  *
11
14
  * Works in RSC, SSR, and client environments:
12
- * - RSC: Uses React.lazy + Suspense (available in React 19.x react-server).
15
+ * - RSC: Uses React.lazy (available in React 19.x react-server).
13
16
  * Falls back to async component pattern if a future React version
14
17
  * strips lazy from react-server.
15
- * - SSR: React.lazy + Suspense (renderToReadableStream suspends)
16
- * - Client: React.lazy + Suspense (standard code splitting)
18
+ * - SSR: React.lazy (renderToReadableStream suspends)
19
+ * - Client: React.lazy (standard code splitting)
17
20
  *
18
21
  * Supports:
19
22
  * - dynamic(import('./Component'))
@@ -115,8 +118,55 @@ function getDynamicErrorBoundary() {
115
118
  }
116
119
  const isServer = typeof window === "undefined";
117
120
  /**
121
+ * Whether this dynamic() renders in an App Router tree. RSC renders the App
122
+ * Router only, and react-server has no context support. On the server, the
123
+ * App Router SSR entry marks its tree; in the browser, App Router documents
124
+ * set `window.next.appDir` before anything renders, which also covers
125
+ * separate client roots (e.g. a modal rendered with createRoot). Everything
126
+ * else (Pages Router pages, `pages/_document`, ad-hoc react-dom/server
127
+ * renders) keeps the boundary, since Pages next/dynamic is react-loadable,
128
+ * which never suspends.
129
+ */
130
+ function useIsAppRouterTree() {
131
+ if (!isServer) return window.next?.appDir === true;
132
+ return AppRouterTreeContext ? React.use(AppRouterTreeContext) : true;
133
+ }
134
+ /**
135
+ * The element tree around an SSR-enabled dynamic() component. The client
136
+ * renders empty slots where the server renders the preload chunks, so both
137
+ * sides render the same shape and useId values inside the dynamic component
138
+ * match on hydration.
139
+ *
140
+ * Match Next.js App Router Loadable: the component only gets a Suspense
141
+ * boundary when it has a `loading` component. Without one, the lazy component
142
+ * suspends up to the nearest parent boundary, so the server shell waits for
143
+ * the import instead of flushing an empty boundary and streaming the
144
+ * component in after first paint. Other trees always get the boundary.
145
+ *
146
+ * React hoists the preload links out of place, but a hoisted <link> right
147
+ * after a text node leaves a `<!-- -->` separator behind. Next.js avoids it by
148
+ * hinting scripts with ReactDOM.preload(), which renders nothing. vinext
149
+ * renders real modulepreload links (preloadModule() drops the nonce and
150
+ * fetchPriority), so they go where text rarely precedes them: first inside the
151
+ * boundary, or after the content when there is no boundary (a component whose
152
+ * output ends in text still gets a separator after it). Stylesheets stay
153
+ * before the boundary: a precedence stylesheet inside it makes React outline
154
+ * the boundary even when its content is already resolved, and rendering them
155
+ * ahead of the content keeps their nonce when the content links the same CSS.
156
+ * A dynamic component with CSS right after text therefore still gets the
157
+ * separator.
158
+ */
159
+ function createDynamicBoundary(fallback, content, preloadModuleIds, hasBoundary) {
160
+ const preloadChunks = (assets) => isServer ? React.createElement(DynamicPreloadChunks, {
161
+ moduleIds: preloadModuleIds,
162
+ assets
163
+ }) : null;
164
+ if (!hasBoundary) return React.createElement(React.Fragment, null, preloadChunks("styles"), content, preloadChunks("scripts"));
165
+ return React.createElement(React.Fragment, null, preloadChunks("styles"), React.createElement(React.Suspense, { fallback }, preloadChunks("scripts"), content));
166
+ }
167
+ /**
118
168
  * Retained for the Pages Router render pipeline, which calls this before
119
- * rendering. Dynamic imports now use React.lazy + Suspense, so there is no
169
+ * rendering. Dynamic imports now use React.lazy, so there is no
120
170
  * separate preload work to await.
121
171
  */
122
172
  function flushPreloads() {
@@ -170,6 +220,7 @@ function dynamic(dynamicInput, options) {
170
220
  }
171
221
  const LazyServer = createLazyComponent(loader);
172
222
  const ServerDynamic = (props) => {
223
+ const isAppRouterTree = useIsAppRouterTree();
173
224
  const fallback = LoadingComponent ? React.createElement(LoadingComponent, createDynamicLoadingProps()) : null;
174
225
  const lazyElement = createElementWithProps(LazyServer, props);
175
226
  let content = lazyElement;
@@ -181,7 +232,7 @@ function dynamic(dynamicInput, options) {
181
232
  resetKey: 0
182
233
  }, lazyElement);
183
234
  }
184
- return React.createElement(React.Fragment, null, React.createElement(DynamicPreloadChunks, { moduleIds: preloadModuleIds }), React.createElement(React.Suspense, { fallback }, content));
235
+ return createDynamicBoundary(fallback, content, preloadModuleIds, LoadingComponent != null || !isAppRouterTree);
185
236
  };
186
237
  ServerDynamic.displayName = "DynamicServer";
187
238
  return ServerDynamic;
@@ -189,6 +240,7 @@ function dynamic(dynamicInput, options) {
189
240
  const InitialLazyComponent = createLazyComponent(loader);
190
241
  const ClientDynamic = (props) => {
191
242
  const { LazyComponent, retry, retryKey } = useRetryableLazyComponent(loader, InitialLazyComponent);
243
+ const isAppRouterTree = useIsAppRouterTree();
192
244
  const fallback = LoadingComponent ? React.createElement(LoadingComponent, createDynamicLoadingProps({ retry })) : null;
193
245
  const lazyElement = createElementWithProps(LazyComponent, props);
194
246
  let content = lazyElement;
@@ -200,7 +252,7 @@ function dynamic(dynamicInput, options) {
200
252
  resetKey: retryKey
201
253
  }, lazyElement);
202
254
  }
203
- return React.createElement(React.Suspense, { fallback }, content);
255
+ return createDynamicBoundary(fallback, content, preloadModuleIds, LoadingComponent != null || !isAppRouterTree);
204
256
  };
205
257
  ClientDynamic.displayName = "DynamicClient";
206
258
  return ClientDynamic;
@@ -2,4 +2,11 @@ import { AppRouterInstance } from "./internal/app-router-context.js";
2
2
  //#region src/shims/error-boundary-navigation.d.ts
3
3
  export declare function useErrorBoundaryPathname(): string;
4
4
  export declare function useErrorBoundaryRouter(): AppRouterInstance;
5
+ /**
6
+ * Whether following a redirect() would refetch the URL the browser is at,
7
+ * which renders the same redirect again. As in the navigation planner, only the
8
+ * exact URL refreshes the page; any hash change, including removing the
9
+ * current hash, only scrolls.
10
+ */
11
+ export declare function isRedirectToCurrentUrl(redirect: string): boolean;
5
12
  //#endregion
@@ -1,6 +1,7 @@
1
1
  import { stripBasePath } from "../utils/base-path.js";
2
2
  import { markPprFallbackShellDynamicBoundary } from "./ppr-fallback-shell.js";
3
3
  import { AppRouterContext } from "./internal/app-router-context.js";
4
+ import { toCanonicalBrowserNavigationHref, toSameOriginAppPath } from "./url-utils.js";
4
5
  import { getNavigationContext } from "./navigation-context-state.js";
5
6
  import "./navigation-server.js";
6
7
  import * as React$1 from "react";
@@ -8,6 +9,7 @@ import * as React$1 from "react";
8
9
  const CLIENT_NAVIGATION_STATE_KEY = Symbol.for("vinext.clientNavigationState");
9
10
  const CLIENT_NAVIGATION_RENDER_CONTEXT_KEY = Symbol.for("vinext.clientNavigationRenderContext");
10
11
  const BASE_PATH = process.env.__NEXT_ROUTER_BASEPATH ?? "";
12
+ const TRAILING_SLASH = process.env.__VINEXT_TRAILING_SLASH === "true";
11
13
  function getClientNavigationState() {
12
14
  return globalThis[CLIENT_NAVIGATION_STATE_KEY];
13
15
  }
@@ -40,5 +42,21 @@ function useErrorBoundaryRouter() {
40
42
  if (router === null) throw new Error("invariant expected app router to be mounted");
41
43
  return router;
42
44
  }
45
+ /**
46
+ * Whether following a redirect() would refetch the URL the browser is at,
47
+ * which renders the same redirect again. As in the navigation planner, only the
48
+ * exact URL refreshes the page; any hash change, including removing the
49
+ * current hash, only scrolls.
50
+ */
51
+ function isRedirectToCurrentUrl(redirect) {
52
+ if (typeof window === "undefined") return false;
53
+ try {
54
+ const current = new URL(window.location.href);
55
+ const target = new URL(toCanonicalBrowserNavigationHref(toSameOriginAppPath(redirect, BASE_PATH) ?? redirect, current.href, BASE_PATH, TRAILING_SLASH), current.href);
56
+ return target.hash === current.hash && target.origin === current.origin && target.pathname === current.pathname && target.search === current.search;
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
43
61
  //#endregion
44
- export { useErrorBoundaryPathname, useErrorBoundaryRouter };
62
+ export { isRedirectToCurrentUrl, useErrorBoundaryPathname, useErrorBoundaryRouter };
@@ -29,6 +29,11 @@ type CapturedError = {
29
29
  type RedirectBoundaryState = {
30
30
  redirect: string | null;
31
31
  redirectType: "push" | "replace" | null;
32
+ previousResetKey: string | null;
33
+ };
34
+ type RedirectBoundaryProps = {
35
+ children?: React.ReactNode;
36
+ resetKey?: string | null;
32
37
  };
33
38
  type ErrorBoundaryInnerProps = {
34
39
  isImplicitRootErrorBoundary?: boolean;
@@ -39,18 +44,13 @@ export type ErrorBoundaryState = {
39
44
  previousPathname: string | null;
40
45
  previousResetKey: string | null;
41
46
  };
42
- export declare class RedirectErrorBoundary extends React.Component<{
43
- children?: React.ReactNode;
44
- }, RedirectBoundaryState> {
45
- constructor(props: {
46
- children?: React.ReactNode;
47
- });
48
- static getDerivedStateFromError(error: unknown): RedirectBoundaryState;
47
+ export declare class RedirectErrorBoundary extends React.Component<RedirectBoundaryProps, RedirectBoundaryState> {
48
+ constructor(props: RedirectBoundaryProps);
49
+ static getDerivedStateFromProps(props: RedirectBoundaryProps, state: RedirectBoundaryState): RedirectBoundaryState | null;
50
+ static getDerivedStateFromError(error: unknown): Omit<RedirectBoundaryState, "previousResetKey">;
49
51
  render(): string | number | bigint | boolean | React.JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | Iterable<React.ReactNode> | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | React.ReactPortal | null | undefined> | null | undefined;
50
52
  }
51
- export declare function RedirectBoundary({ children }: {
52
- children?: React.ReactNode;
53
- }): React.JSX.Element;
53
+ export declare function RedirectBoundary({ children, resetKey }: RedirectBoundaryProps): React.JSX.Element;
54
54
  /**
55
55
  * Generic ErrorBoundary used to wrap route segments with error.tsx.
56
56
  * This must be a client component since error boundaries use