vinext 0.0.50 → 0.0.52

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 (462) hide show
  1. package/dist/build/google-fonts/fallback-metrics-data.js +14031 -0
  2. package/dist/build/google-fonts/fallback-metrics-data.js.map +1 -0
  3. package/dist/build/google-fonts/fallback-metrics.d.ts +13 -0
  4. package/dist/build/google-fonts/fallback-metrics.js +46 -0
  5. package/dist/build/google-fonts/fallback-metrics.js.map +1 -0
  6. package/dist/build/precompress.d.ts +13 -2
  7. package/dist/build/precompress.js +23 -13
  8. package/dist/build/precompress.js.map +1 -1
  9. package/dist/build/prerender.d.ts +4 -15
  10. package/dist/build/prerender.js +83 -53
  11. package/dist/build/prerender.js.map +1 -1
  12. package/dist/build/report.d.ts +5 -4
  13. package/dist/build/report.js +196 -348
  14. package/dist/build/report.js.map +1 -1
  15. package/dist/check.js +5 -0
  16. package/dist/check.js.map +1 -1
  17. package/dist/cli-args.d.ts +1 -0
  18. package/dist/cli-args.js +5 -0
  19. package/dist/cli-args.js.map +1 -1
  20. package/dist/cli.js +99 -3
  21. package/dist/cli.js.map +1 -1
  22. package/dist/client/navigation-runtime.d.ts +47 -0
  23. package/dist/client/navigation-runtime.js +156 -0
  24. package/dist/client/navigation-runtime.js.map +1 -0
  25. package/dist/client/pages-router-link-navigation.d.ts +26 -0
  26. package/dist/client/pages-router-link-navigation.js +14 -0
  27. package/dist/client/pages-router-link-navigation.js.map +1 -0
  28. package/dist/client/vinext-next-data.d.ts +12 -2
  29. package/dist/client/vinext-next-data.js +50 -1
  30. package/dist/client/vinext-next-data.js.map +1 -0
  31. package/dist/client/window-next.d.ts +3 -1
  32. package/dist/client/window-next.js.map +1 -1
  33. package/dist/cloudflare/kv-cache-handler.js +2 -1
  34. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  35. package/dist/config/config-matchers.d.ts +63 -16
  36. package/dist/config/config-matchers.js +143 -8
  37. package/dist/config/config-matchers.js.map +1 -1
  38. package/dist/config/dotenv.d.ts +11 -1
  39. package/dist/config/dotenv.js.map +1 -1
  40. package/dist/config/next-config.d.ts +107 -5
  41. package/dist/config/next-config.js +233 -7
  42. package/dist/config/next-config.js.map +1 -1
  43. package/dist/config/tsconfig-paths.d.ts +13 -0
  44. package/dist/config/tsconfig-paths.js +117 -0
  45. package/dist/config/tsconfig-paths.js.map +1 -0
  46. package/dist/deploy.js +104 -41
  47. package/dist/deploy.js.map +1 -1
  48. package/dist/entries/app-browser-entry.d.ts +2 -2
  49. package/dist/entries/app-browser-entry.js +34 -3
  50. package/dist/entries/app-browser-entry.js.map +1 -1
  51. package/dist/entries/app-rsc-entry.d.ts +19 -1
  52. package/dist/entries/app-rsc-entry.js +89 -23
  53. package/dist/entries/app-rsc-entry.js.map +1 -1
  54. package/dist/entries/app-rsc-manifest.d.ts +10 -0
  55. package/dist/entries/app-rsc-manifest.js +57 -7
  56. package/dist/entries/app-rsc-manifest.js.map +1 -1
  57. package/dist/entries/app-ssr-entry.d.ts +3 -3
  58. package/dist/entries/app-ssr-entry.js +4 -4
  59. package/dist/entries/app-ssr-entry.js.map +1 -1
  60. package/dist/entries/pages-client-entry.js +21 -7
  61. package/dist/entries/pages-client-entry.js.map +1 -1
  62. package/dist/entries/pages-server-entry.js +77 -9
  63. package/dist/entries/pages-server-entry.js.map +1 -1
  64. package/dist/entries/runtime-entry-module.d.ts +2 -1
  65. package/dist/entries/runtime-entry-module.js +9 -3
  66. package/dist/entries/runtime-entry-module.js.map +1 -1
  67. package/dist/index.js +260 -75
  68. package/dist/index.js.map +1 -1
  69. package/dist/plugins/client-reference-dedup.d.ts +15 -2
  70. package/dist/plugins/client-reference-dedup.js +138 -16
  71. package/dist/plugins/client-reference-dedup.js.map +1 -1
  72. package/dist/plugins/css-data-url.d.ts +7 -0
  73. package/dist/plugins/css-data-url.js +81 -0
  74. package/dist/plugins/css-data-url.js.map +1 -0
  75. package/dist/plugins/fonts.d.ts +2 -2
  76. package/dist/plugins/fonts.js +20 -9
  77. package/dist/plugins/fonts.js.map +1 -1
  78. package/dist/plugins/middleware-server-only.d.ts +54 -0
  79. package/dist/plugins/middleware-server-only.js +91 -0
  80. package/dist/plugins/middleware-server-only.js.map +1 -0
  81. package/dist/plugins/optimize-imports.js +4 -4
  82. package/dist/plugins/optimize-imports.js.map +1 -1
  83. package/dist/plugins/sass.d.ts +34 -0
  84. package/dist/plugins/sass.js +22 -0
  85. package/dist/plugins/sass.js.map +1 -0
  86. package/dist/plugins/strip-server-exports.js +5 -8
  87. package/dist/plugins/strip-server-exports.js.map +1 -1
  88. package/dist/routing/app-route-graph.d.ts +50 -2
  89. package/dist/routing/app-route-graph.js +140 -16
  90. package/dist/routing/app-route-graph.js.map +1 -1
  91. package/dist/routing/app-router.d.ts +2 -2
  92. package/dist/routing/app-router.js +2 -2
  93. package/dist/routing/app-router.js.map +1 -1
  94. package/dist/routing/route-pattern.d.ts +56 -1
  95. package/dist/routing/route-pattern.js +60 -1
  96. package/dist/routing/route-pattern.js.map +1 -1
  97. package/dist/routing/utils.d.ts +2 -1
  98. package/dist/routing/utils.js +4 -1
  99. package/dist/routing/utils.js.map +1 -1
  100. package/dist/server/api-handler.js +139 -37
  101. package/dist/server/api-handler.js.map +1 -1
  102. package/dist/server/app-browser-action-result.d.ts +27 -2
  103. package/dist/server/app-browser-action-result.js +63 -2
  104. package/dist/server/app-browser-action-result.js.map +1 -1
  105. package/dist/server/app-browser-entry.js +493 -195
  106. package/dist/server/app-browser-entry.js.map +1 -1
  107. package/dist/server/app-browser-hydration.d.ts +13 -1
  108. package/dist/server/app-browser-hydration.js +9 -1
  109. package/dist/server/app-browser-hydration.js.map +1 -1
  110. package/dist/server/app-browser-interception-context.d.ts +24 -0
  111. package/dist/server/app-browser-interception-context.js +32 -0
  112. package/dist/server/app-browser-interception-context.js.map +1 -0
  113. package/dist/server/app-browser-navigation-controller.d.ts +17 -2
  114. package/dist/server/app-browser-navigation-controller.js +33 -10
  115. package/dist/server/app-browser-navigation-controller.js.map +1 -1
  116. package/dist/server/app-browser-popstate.d.ts +16 -0
  117. package/dist/server/app-browser-popstate.js +17 -0
  118. package/dist/server/app-browser-popstate.js.map +1 -0
  119. package/dist/server/app-browser-rsc-redirect.d.ts +29 -0
  120. package/dist/server/app-browser-rsc-redirect.js +37 -0
  121. package/dist/server/app-browser-rsc-redirect.js.map +1 -0
  122. package/dist/server/app-browser-state.d.ts +28 -7
  123. package/dist/server/app-browser-state.js +63 -27
  124. package/dist/server/app-browser-state.js.map +1 -1
  125. package/dist/server/app-browser-stream.d.ts +9 -17
  126. package/dist/server/app-browser-stream.js +18 -13
  127. package/dist/server/app-browser-stream.js.map +1 -1
  128. package/dist/server/app-browser-visible-commit.d.ts +7 -1
  129. package/dist/server/app-browser-visible-commit.js +39 -5
  130. package/dist/server/app-browser-visible-commit.js.map +1 -1
  131. package/dist/server/app-elements-wire.d.ts +43 -6
  132. package/dist/server/app-elements-wire.js +189 -7
  133. package/dist/server/app-elements-wire.js.map +1 -1
  134. package/dist/server/app-elements.d.ts +3 -2
  135. package/dist/server/app-elements.js +3 -2
  136. package/dist/server/app-elements.js.map +1 -1
  137. package/dist/server/app-fallback-renderer.d.ts +10 -1
  138. package/dist/server/app-fallback-renderer.js +41 -3
  139. package/dist/server/app-fallback-renderer.js.map +1 -1
  140. package/dist/server/app-history-state.d.ts +26 -0
  141. package/dist/server/app-history-state.js +53 -0
  142. package/dist/server/app-history-state.js.map +1 -0
  143. package/dist/server/app-middleware.d.ts +13 -0
  144. package/dist/server/app-middleware.js +3 -1
  145. package/dist/server/app-middleware.js.map +1 -1
  146. package/dist/server/app-optimistic-routing.d.ts +54 -0
  147. package/dist/server/app-optimistic-routing.js +200 -0
  148. package/dist/server/app-optimistic-routing.js.map +1 -0
  149. package/dist/server/app-page-boundary-render.d.ts +10 -1
  150. package/dist/server/app-page-boundary-render.js +13 -6
  151. package/dist/server/app-page-boundary-render.js.map +1 -1
  152. package/dist/server/app-page-boundary.js +3 -2
  153. package/dist/server/app-page-boundary.js.map +1 -1
  154. package/dist/server/app-page-cache.d.ts +26 -1
  155. package/dist/server/app-page-cache.js +86 -14
  156. package/dist/server/app-page-cache.js.map +1 -1
  157. package/dist/server/app-page-dispatch.d.ts +7 -0
  158. package/dist/server/app-page-dispatch.js +96 -12
  159. package/dist/server/app-page-dispatch.js.map +1 -1
  160. package/dist/server/app-page-element-builder.d.ts +7 -0
  161. package/dist/server/app-page-element-builder.js +34 -5
  162. package/dist/server/app-page-element-builder.js.map +1 -1
  163. package/dist/server/app-page-execution.d.ts +28 -1
  164. package/dist/server/app-page-execution.js +91 -7
  165. package/dist/server/app-page-execution.js.map +1 -1
  166. package/dist/server/app-page-head.d.ts +7 -0
  167. package/dist/server/app-page-head.js +23 -3
  168. package/dist/server/app-page-head.js.map +1 -1
  169. package/dist/server/app-page-probe.d.ts +23 -1
  170. package/dist/server/app-page-probe.js +29 -1
  171. package/dist/server/app-page-probe.js.map +1 -1
  172. package/dist/server/app-page-render-observation.d.ts +35 -0
  173. package/dist/server/app-page-render-observation.js +68 -0
  174. package/dist/server/app-page-render-observation.js.map +1 -0
  175. package/dist/server/app-page-render.d.ts +7 -1
  176. package/dist/server/app-page-render.js +81 -4
  177. package/dist/server/app-page-render.js.map +1 -1
  178. package/dist/server/app-page-request.d.ts +1 -0
  179. package/dist/server/app-page-request.js.map +1 -1
  180. package/dist/server/app-page-response.js +7 -5
  181. package/dist/server/app-page-response.js.map +1 -1
  182. package/dist/server/app-page-route-wiring.d.ts +3 -1
  183. package/dist/server/app-page-route-wiring.js +59 -24
  184. package/dist/server/app-page-route-wiring.js.map +1 -1
  185. package/dist/server/app-page-stream.d.ts +5 -0
  186. package/dist/server/app-page-stream.js +2 -0
  187. package/dist/server/app-page-stream.js.map +1 -1
  188. package/dist/server/app-prerender-static-params.d.ts +2 -1
  189. package/dist/server/app-prerender-static-params.js +44 -8
  190. package/dist/server/app-prerender-static-params.js.map +1 -1
  191. package/dist/server/app-route-handler-cache.d.ts +2 -2
  192. package/dist/server/app-route-handler-cache.js +3 -2
  193. package/dist/server/app-route-handler-cache.js.map +1 -1
  194. package/dist/server/app-route-handler-dispatch.d.ts +6 -1
  195. package/dist/server/app-route-handler-dispatch.js +1 -1
  196. package/dist/server/app-route-handler-dispatch.js.map +1 -1
  197. package/dist/server/app-route-handler-execution.d.ts +17 -2
  198. package/dist/server/app-route-handler-execution.js.map +1 -1
  199. package/dist/server/app-route-handler-response.js +5 -4
  200. package/dist/server/app-route-handler-response.js.map +1 -1
  201. package/dist/server/app-router-entry.js +7 -15
  202. package/dist/server/app-router-entry.js.map +1 -1
  203. package/dist/server/app-rsc-cache-busting.d.ts +19 -1
  204. package/dist/server/app-rsc-cache-busting.js +36 -1
  205. package/dist/server/app-rsc-cache-busting.js.map +1 -1
  206. package/dist/server/app-rsc-embedded-chunks.d.ts +9 -0
  207. package/dist/server/app-rsc-embedded-chunks.js +34 -0
  208. package/dist/server/app-rsc-embedded-chunks.js.map +1 -0
  209. package/dist/server/app-rsc-errors.d.ts +4 -1
  210. package/dist/server/app-rsc-errors.js +1 -1
  211. package/dist/server/app-rsc-errors.js.map +1 -1
  212. package/dist/server/app-rsc-handler.d.ts +21 -5
  213. package/dist/server/app-rsc-handler.js +38 -15
  214. package/dist/server/app-rsc-handler.js.map +1 -1
  215. package/dist/server/app-rsc-render-mode.d.ts +4 -3
  216. package/dist/server/app-rsc-render-mode.js +7 -1
  217. package/dist/server/app-rsc-render-mode.js.map +1 -1
  218. package/dist/server/app-rsc-request-normalization.d.ts +4 -1
  219. package/dist/server/app-rsc-request-normalization.js +4 -1
  220. package/dist/server/app-rsc-request-normalization.js.map +1 -1
  221. package/dist/server/app-rsc-response-finalizer.d.ts +8 -1
  222. package/dist/server/app-rsc-response-finalizer.js +10 -3
  223. package/dist/server/app-rsc-response-finalizer.js.map +1 -1
  224. package/dist/server/app-rsc-route-matching.d.ts +23 -0
  225. package/dist/server/app-rsc-route-matching.js +47 -25
  226. package/dist/server/app-rsc-route-matching.js.map +1 -1
  227. package/dist/server/app-server-action-execution.d.ts +35 -3
  228. package/dist/server/app-server-action-execution.js +87 -33
  229. package/dist/server/app-server-action-execution.js.map +1 -1
  230. package/dist/server/app-ssr-entry.d.ts +3 -0
  231. package/dist/server/app-ssr-entry.js +83 -58
  232. package/dist/server/app-ssr-entry.js.map +1 -1
  233. package/dist/server/app-ssr-error-meta.d.ts +14 -0
  234. package/dist/server/app-ssr-error-meta.js +50 -0
  235. package/dist/server/app-ssr-error-meta.js.map +1 -0
  236. package/dist/server/app-ssr-stream.d.ts +7 -2
  237. package/dist/server/app-ssr-stream.js +26 -15
  238. package/dist/server/app-ssr-stream.js.map +1 -1
  239. package/dist/server/artifact-compatibility.d.ts +13 -3
  240. package/dist/server/artifact-compatibility.js +12 -8
  241. package/dist/server/artifact-compatibility.js.map +1 -1
  242. package/dist/server/cache-headers.d.ts +7 -0
  243. package/dist/server/cache-headers.js +19 -0
  244. package/dist/server/cache-headers.js.map +1 -0
  245. package/dist/server/cache-proof.d.ts +170 -5
  246. package/dist/server/cache-proof.js +472 -18
  247. package/dist/server/cache-proof.js.map +1 -1
  248. package/dist/server/client-reuse-manifest.d.ts +99 -0
  249. package/dist/server/client-reuse-manifest.js +212 -0
  250. package/dist/server/client-reuse-manifest.js.map +1 -0
  251. package/dist/server/default-global-error-module.d.ts +20 -0
  252. package/dist/server/default-global-error-module.js +20 -0
  253. package/dist/server/default-global-error-module.js.map +1 -0
  254. package/dist/server/dev-lockfile.d.ts +110 -0
  255. package/dist/server/dev-lockfile.js +180 -0
  256. package/dist/server/dev-lockfile.js.map +1 -0
  257. package/dist/server/dev-server.d.ts +9 -1
  258. package/dist/server/dev-server.js +76 -19
  259. package/dist/server/dev-server.js.map +1 -1
  260. package/dist/server/edge-api-runtime.d.ts +5 -0
  261. package/dist/server/edge-api-runtime.js +8 -0
  262. package/dist/server/edge-api-runtime.js.map +1 -0
  263. package/dist/server/file-based-metadata.d.ts +13 -0
  264. package/dist/server/file-based-metadata.js +49 -2
  265. package/dist/server/file-based-metadata.js.map +1 -1
  266. package/dist/server/headers.d.ts +20 -1
  267. package/dist/server/headers.js +22 -2
  268. package/dist/server/headers.js.map +1 -1
  269. package/dist/server/html.js +1 -1
  270. package/dist/server/html.js.map +1 -1
  271. package/dist/server/http-error-responses.d.ts +26 -1
  272. package/dist/server/http-error-responses.js +32 -2
  273. package/dist/server/http-error-responses.js.map +1 -1
  274. package/dist/server/isr-cache.d.ts +8 -3
  275. package/dist/server/isr-cache.js +24 -6
  276. package/dist/server/isr-cache.js.map +1 -1
  277. package/dist/server/metadata-route-response.js +22 -5
  278. package/dist/server/metadata-route-response.js.map +1 -1
  279. package/dist/server/metadata-routes.js +27 -8
  280. package/dist/server/metadata-routes.js.map +1 -1
  281. package/dist/server/middleware-runtime.d.ts +15 -0
  282. package/dist/server/middleware-runtime.js +60 -7
  283. package/dist/server/middleware-runtime.js.map +1 -1
  284. package/dist/server/middleware.d.ts +13 -1
  285. package/dist/server/middleware.js +16 -2
  286. package/dist/server/middleware.js.map +1 -1
  287. package/dist/server/navigation-planner.d.ts +26 -6
  288. package/dist/server/navigation-planner.js +358 -24
  289. package/dist/server/navigation-planner.js.map +1 -1
  290. package/dist/server/navigation-trace.d.ts +9 -1
  291. package/dist/server/navigation-trace.js +8 -0
  292. package/dist/server/navigation-trace.js.map +1 -1
  293. package/dist/server/normalize-path.d.ts +2 -1
  294. package/dist/server/normalize-path.js +4 -1
  295. package/dist/server/normalize-path.js.map +1 -1
  296. package/dist/server/pages-api-route.d.ts +27 -1
  297. package/dist/server/pages-api-route.js +25 -3
  298. package/dist/server/pages-api-route.js.map +1 -1
  299. package/dist/server/pages-data-route.d.ts +77 -0
  300. package/dist/server/pages-data-route.js +97 -0
  301. package/dist/server/pages-data-route.js.map +1 -0
  302. package/dist/server/pages-i18n.d.ts +51 -1
  303. package/dist/server/pages-i18n.js +61 -1
  304. package/dist/server/pages-i18n.js.map +1 -1
  305. package/dist/server/pages-page-data.d.ts +32 -4
  306. package/dist/server/pages-page-data.js +52 -19
  307. package/dist/server/pages-page-data.js.map +1 -1
  308. package/dist/server/pages-page-response.d.ts +11 -1
  309. package/dist/server/pages-page-response.js +6 -4
  310. package/dist/server/pages-page-response.js.map +1 -1
  311. package/dist/server/prod-server.d.ts +26 -1
  312. package/dist/server/prod-server.js +150 -44
  313. package/dist/server/prod-server.js.map +1 -1
  314. package/dist/server/request-pipeline.d.ts +11 -2
  315. package/dist/server/request-pipeline.js +28 -11
  316. package/dist/server/request-pipeline.js.map +1 -1
  317. package/dist/server/seed-cache.d.ts +12 -31
  318. package/dist/server/seed-cache.js +22 -35
  319. package/dist/server/seed-cache.js.map +1 -1
  320. package/dist/server/server-action-not-found.d.ts +16 -3
  321. package/dist/server/server-action-not-found.js +27 -4
  322. package/dist/server/server-action-not-found.js.map +1 -1
  323. package/dist/server/server-globals.d.ts +5 -0
  324. package/dist/server/server-globals.js +37 -0
  325. package/dist/server/server-globals.js.map +1 -0
  326. package/dist/server/skip-cache-proof.d.ts +41 -0
  327. package/dist/server/skip-cache-proof.js +101 -0
  328. package/dist/server/skip-cache-proof.js.map +1 -0
  329. package/dist/server/static-file-cache.d.ts +1 -1
  330. package/dist/server/static-file-cache.js +7 -6
  331. package/dist/server/static-file-cache.js.map +1 -1
  332. package/dist/shims/cache-runtime.d.ts +19 -2
  333. package/dist/shims/cache-runtime.js +67 -11
  334. package/dist/shims/cache-runtime.js.map +1 -1
  335. package/dist/shims/cache.d.ts +5 -18
  336. package/dist/shims/cache.js +2 -0
  337. package/dist/shims/cache.js.map +1 -1
  338. package/dist/shims/client-locale.d.ts +15 -0
  339. package/dist/shims/client-locale.js +13 -0
  340. package/dist/shims/client-locale.js.map +1 -0
  341. package/dist/shims/default-global-error.d.ts +32 -0
  342. package/dist/shims/default-global-error.js +181 -0
  343. package/dist/shims/default-global-error.js.map +1 -0
  344. package/dist/shims/document.d.ts +59 -3
  345. package/dist/shims/document.js +36 -5
  346. package/dist/shims/document.js.map +1 -1
  347. package/dist/shims/error-boundary.d.ts +2 -2
  348. package/dist/shims/error-boundary.js +6 -8
  349. package/dist/shims/error-boundary.js.map +1 -1
  350. package/dist/shims/error.d.ts +18 -1
  351. package/dist/shims/error.js +56 -1
  352. package/dist/shims/error.js.map +1 -1
  353. package/dist/shims/fetch-cache.d.ts +4 -1
  354. package/dist/shims/fetch-cache.js +40 -5
  355. package/dist/shims/fetch-cache.js.map +1 -1
  356. package/dist/shims/font-google-base.d.ts +22 -8
  357. package/dist/shims/font-google-base.js +41 -71
  358. package/dist/shims/font-google-base.js.map +1 -1
  359. package/dist/shims/font-local.d.ts +3 -20
  360. package/dist/shims/font-local.js +23 -75
  361. package/dist/shims/font-local.js.map +1 -1
  362. package/dist/shims/font-utils.d.ts +51 -0
  363. package/dist/shims/font-utils.js +97 -0
  364. package/dist/shims/font-utils.js.map +1 -0
  365. package/dist/shims/form.js +13 -6
  366. package/dist/shims/form.js.map +1 -1
  367. package/dist/shims/hash-scroll.d.ts +7 -0
  368. package/dist/shims/hash-scroll.js +30 -0
  369. package/dist/shims/hash-scroll.js.map +1 -0
  370. package/dist/shims/headers.d.ts +8 -11
  371. package/dist/shims/headers.js +22 -2
  372. package/dist/shims/headers.js.map +1 -1
  373. package/dist/shims/image.d.ts +1 -0
  374. package/dist/shims/image.js +144 -78
  375. package/dist/shims/image.js.map +1 -1
  376. package/dist/shims/internal/app-router-context.d.ts +6 -6
  377. package/dist/shims/internal/app-router-context.js +17 -6
  378. package/dist/shims/internal/app-router-context.js.map +1 -1
  379. package/dist/shims/link-prefetch.d.ts +9 -1
  380. package/dist/shims/link-prefetch.js +11 -6
  381. package/dist/shims/link-prefetch.js.map +1 -1
  382. package/dist/shims/link.d.ts +33 -5
  383. package/dist/shims/link.js +205 -50
  384. package/dist/shims/link.js.map +1 -1
  385. package/dist/shims/metadata.d.ts +16 -30
  386. package/dist/shims/metadata.js +91 -32
  387. package/dist/shims/metadata.js.map +1 -1
  388. package/dist/shims/navigation.d.ts +164 -17
  389. package/dist/shims/navigation.js +355 -84
  390. package/dist/shims/navigation.js.map +1 -1
  391. package/dist/shims/navigation.react-server.d.ts +3 -2
  392. package/dist/shims/navigation.react-server.js +5 -2
  393. package/dist/shims/navigation.react-server.js.map +1 -1
  394. package/dist/shims/og.d.ts +18 -2
  395. package/dist/shims/og.js +49 -1
  396. package/dist/shims/og.js.map +1 -0
  397. package/dist/shims/pages-router-runtime.d.ts +7 -0
  398. package/dist/shims/pages-router-runtime.js +16 -0
  399. package/dist/shims/pages-router-runtime.js.map +1 -0
  400. package/dist/shims/request-state-types.d.ts +1 -1
  401. package/dist/shims/root-params.d.ts +3 -1
  402. package/dist/shims/root-params.js +11 -3
  403. package/dist/shims/root-params.js.map +1 -1
  404. package/dist/shims/router-state.d.ts +1 -0
  405. package/dist/shims/router-state.js.map +1 -1
  406. package/dist/shims/router.d.ts +40 -7
  407. package/dist/shims/router.js +355 -250
  408. package/dist/shims/router.js.map +1 -1
  409. package/dist/shims/script.js +110 -32
  410. package/dist/shims/script.js.map +1 -1
  411. package/dist/shims/server.d.ts +21 -4
  412. package/dist/shims/server.js +31 -10
  413. package/dist/shims/server.js.map +1 -1
  414. package/dist/shims/slot.d.ts +1 -0
  415. package/dist/shims/slot.js +45 -1
  416. package/dist/shims/slot.js.map +1 -1
  417. package/dist/shims/unified-request-context.d.ts +1 -1
  418. package/dist/shims/unified-request-context.js +2 -0
  419. package/dist/shims/unified-request-context.js.map +1 -1
  420. package/dist/shims/unrecognized-action-error.d.ts +35 -0
  421. package/dist/shims/unrecognized-action-error.js +41 -0
  422. package/dist/shims/unrecognized-action-error.js.map +1 -0
  423. package/dist/shims/url-safety.d.ts +23 -1
  424. package/dist/shims/url-safety.js +29 -2
  425. package/dist/shims/url-safety.js.map +1 -1
  426. package/dist/shims/url-utils.d.ts +21 -1
  427. package/dist/shims/url-utils.js +67 -3
  428. package/dist/shims/url-utils.js.map +1 -1
  429. package/dist/typegen.d.ts +10 -0
  430. package/dist/typegen.js +242 -0
  431. package/dist/typegen.js.map +1 -0
  432. package/dist/utils/asset-prefix.d.ts +97 -0
  433. package/dist/utils/asset-prefix.js +124 -0
  434. package/dist/utils/asset-prefix.js.map +1 -0
  435. package/dist/utils/base-path.d.ts +7 -1
  436. package/dist/utils/base-path.js +10 -1
  437. package/dist/utils/base-path.js.map +1 -1
  438. package/dist/utils/cache-control-metadata.d.ts +2 -1
  439. package/dist/utils/cache-control-metadata.js +1 -3
  440. package/dist/utils/cache-control-metadata.js.map +1 -1
  441. package/dist/utils/domain-locale.d.ts +2 -1
  442. package/dist/utils/domain-locale.js +9 -1
  443. package/dist/utils/domain-locale.js.map +1 -1
  444. package/dist/utils/lazy-chunks.d.ts +1 -1
  445. package/dist/utils/lazy-chunks.js +1 -1
  446. package/dist/utils/lazy-chunks.js.map +1 -1
  447. package/dist/utils/navigation-signal.d.ts +1 -2
  448. package/dist/utils/navigation-signal.js +1 -1
  449. package/dist/utils/navigation-signal.js.map +1 -1
  450. package/dist/utils/prerender-output-paths.d.ts +15 -0
  451. package/dist/utils/prerender-output-paths.js +24 -0
  452. package/dist/utils/prerender-output-paths.js.map +1 -0
  453. package/dist/utils/query.d.ts +17 -1
  454. package/dist/utils/query.js +36 -1
  455. package/dist/utils/query.js.map +1 -1
  456. package/dist/utils/record.d.ts +5 -0
  457. package/dist/utils/record.js +8 -0
  458. package/dist/utils/record.js.map +1 -0
  459. package/dist/utils/sorted-array.d.ts +9 -0
  460. package/dist/utils/sorted-array.js +22 -0
  461. package/dist/utils/sorted-array.js.map +1 -0
  462. package/package.json +13 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-globals.js","names":[],"sources":["../../src/server/server-globals.ts"],"sourcesContent":["/**\n * Server runtime global setup shared by vinext's generated server entries.\n *\n * This module intentionally runs its installer at import time. Generated entry\n * modules import user pages and layouts as static dependencies, so any global\n * correction that must happen before user module evaluation has to live in a\n * side-effect dependency. A runtime function call from the generated entry\n * body would run after static user imports have already evaluated.\n */\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\ntype BrowserGlobalName = \"window\" | \"document\";\n\nfunction clearBrowserGlobal(name: BrowserGlobalName): void {\n const descriptor = Object.getOwnPropertyDescriptor(globalThis, name);\n\n if (!descriptor && typeof Reflect.get(globalThis, name) === \"undefined\") return;\n\n if (!descriptor) {\n Object.defineProperty(globalThis, name, {\n configurable: true,\n value: undefined,\n writable: true,\n });\n } else if (descriptor.configurable) {\n Reflect.deleteProperty(globalThis, name);\n } else {\n Reflect.set(globalThis, name, undefined);\n }\n\n if (typeof Reflect.get(globalThis, name) !== \"undefined\") {\n throw new Error(\n `[vinext] Server runtime exposes a non-removable \\`${name}\\` global. ` +\n \"This breaks Next.js SSR semantics where browser globals must be absent.\",\n );\n }\n}\n\nexport function installServerGlobals(): void {\n clearBrowserGlobal(\"window\");\n clearBrowserGlobal(\"document\");\n\n // Next.js's edge sandbox exposes AsyncLocalStorage as a global. Cloudflare\n // Workers exposes it via node:async_hooks under nodejs_compat, so mirror the\n // global binding for user code written against Next.js's runtime.\n if (typeof Reflect.get(globalThis, \"AsyncLocalStorage\") === \"undefined\") {\n Object.defineProperty(globalThis, \"AsyncLocalStorage\", {\n configurable: true,\n value: AsyncLocalStorage,\n writable: true,\n });\n }\n}\n\ninstallServerGlobals();\n"],"mappings":";;;;;;;;;;;AAaA,SAAS,mBAAmB,MAA+B;CACzD,MAAM,aAAa,OAAO,yBAAyB,YAAY,KAAK;CAEpE,IAAI,CAAC,cAAc,OAAO,QAAQ,IAAI,YAAY,KAAK,KAAK,aAAa;CAEzE,IAAI,CAAC,YACH,OAAO,eAAe,YAAY,MAAM;EACtC,cAAc;EACd,OAAO,KAAA;EACP,UAAU;EACX,CAAC;MACG,IAAI,WAAW,cACpB,QAAQ,eAAe,YAAY,KAAK;MAExC,QAAQ,IAAI,YAAY,MAAM,KAAA,EAAU;CAG1C,IAAI,OAAO,QAAQ,IAAI,YAAY,KAAK,KAAK,aAC3C,MAAM,IAAI,MACR,qDAAqD,KAAK,oFAE3D;;AAIL,SAAgB,uBAA6B;CAC3C,mBAAmB,SAAS;CAC5B,mBAAmB,WAAW;CAK9B,IAAI,OAAO,QAAQ,IAAI,YAAY,oBAAoB,KAAK,aAC1D,OAAO,eAAe,YAAY,qBAAqB;EACrD,cAAc;EACd,OAAO;EACP,UAAU;EACX,CAAC;;AAIN,sBAAsB"}
@@ -0,0 +1,41 @@
1
+ import { ArtifactCompatibilityEnvelope, ArtifactCompatibilityEvaluationOptions } from "./artifact-compatibility.js";
2
+ import { StaticLayoutArtifactReuseDecision } from "./cache-proof.js";
3
+ import { ClientReuseManifestEntry, ClientReuseManifestEntryRejection, ClientReuseManifestSkipDisposition, ClientReuseManifestTraceFields } from "./client-reuse-manifest.js";
4
+
5
+ //#region src/server/skip-cache-proof.d.ts
6
+ type SkipCacheInvalidationProof = Readonly<{
7
+ kind: "invalidated";
8
+ invalidationEpoch: string | null;
9
+ }> | Readonly<{
10
+ kind: "unknown";
11
+ }> | Readonly<{
12
+ kind: "valid";
13
+ }>;
14
+ type SkipCacheArtifactProof = Readonly<{
15
+ compatibility: ArtifactCompatibilityEnvelope;
16
+ invalidation: SkipCacheInvalidationProof;
17
+ payloadHash: string | null;
18
+ }>;
19
+ type SkipCacheCrossCheckAcceptanceCode = "SKIP_CACHE_CROSS_CHECK_PASSED";
20
+ type SkipCacheCrossCheckVerified = Readonly<{
21
+ code: SkipCacheCrossCheckAcceptanceCode;
22
+ entryId: string;
23
+ fields: ClientReuseManifestTraceFields;
24
+ kind: "verified";
25
+ skipDisposition: ClientReuseManifestSkipDisposition;
26
+ }>;
27
+ type SkipCacheCrossCheckRejected = Readonly<{
28
+ kind: "rejected";
29
+ rejection: ClientReuseManifestEntryRejection;
30
+ skipDisposition: ClientReuseManifestSkipDisposition;
31
+ }>;
32
+ type SkipCacheCrossCheckResult = SkipCacheCrossCheckRejected | SkipCacheCrossCheckVerified;
33
+ type CrossCheckClientReuseManifestEntryWithCacheInput = Readonly<{
34
+ artifact: SkipCacheArtifactProof;
35
+ cacheDecision: StaticLayoutArtifactReuseDecision | null;
36
+ entry: ClientReuseManifestEntry;
37
+ }> & ArtifactCompatibilityEvaluationOptions;
38
+ declare function crossCheckClientReuseManifestEntryWithCache(input: CrossCheckClientReuseManifestEntryWithCacheInput): SkipCacheCrossCheckResult;
39
+ //#endregion
40
+ export { SkipCacheInvalidationProof, crossCheckClientReuseManifestEntryWithCache };
41
+ //# sourceMappingURL=skip-cache-proof.d.ts.map
@@ -0,0 +1,101 @@
1
+ import { evaluateArtifactCompatibility } from "./artifact-compatibility.js";
2
+ import { createClientReusePayloadHash } from "./client-reuse-manifest.js";
3
+ //#region src/server/skip-cache-proof.ts
4
+ const ARTIFACT_COMPATIBILITY_PROOF_FIELDS = [
5
+ "schemaVersion",
6
+ "graphVersion",
7
+ "deploymentVersion",
8
+ "appElementsSchemaVersion",
9
+ "rscPayloadSchemaVersion",
10
+ "rootBoundaryId",
11
+ "renderEpoch"
12
+ ];
13
+ function createDisabledSkipDisposition() {
14
+ return {
15
+ code: "SKIP_MODEL_DISABLED",
16
+ enabled: false,
17
+ mode: "renderAndSend"
18
+ };
19
+ }
20
+ function rejectSkipCacheCrossCheck(entry, code, fields = {}) {
21
+ return {
22
+ kind: "rejected",
23
+ rejection: {
24
+ code,
25
+ entryId: entry.id,
26
+ fields
27
+ },
28
+ skipDisposition: createDisabledSkipDisposition()
29
+ };
30
+ }
31
+ function collectArtifactCompatibilityProofMismatches(artifactCompatibility, proofCompatibility) {
32
+ const mismatchedFields = [];
33
+ for (const field of ARTIFACT_COMPATIBILITY_PROOF_FIELDS) if (artifactCompatibility[field] !== proofCompatibility[field]) mismatchedFields.push(field);
34
+ return mismatchedFields;
35
+ }
36
+ function assertNever(value) {
37
+ throw new Error(`Unhandled skip/cache proof state: ${String(value)}`);
38
+ }
39
+ function crossCheckInvalidationProof(entry, invalidation) {
40
+ switch (invalidation.kind) {
41
+ case "valid": return null;
42
+ case "unknown": return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_INVALIDATION_UNKNOWN");
43
+ case "invalidated": return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_INVALIDATED", { invalidationEpoch: invalidation.invalidationEpoch });
44
+ default: return assertNever(invalidation);
45
+ }
46
+ }
47
+ function crossCheckClientReuseManifestEntryWithCache(input) {
48
+ const { cacheDecision, entry } = input;
49
+ if (cacheDecision === null) return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_PROOF_MISSING");
50
+ if (cacheDecision.kind === "fallback") return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_PROOF_REJECTED", {
51
+ cacheProofCode: cacheDecision.fallback.code,
52
+ cacheProofMode: cacheDecision.fallback.mode,
53
+ cacheProofScope: cacheDecision.fallback.scope
54
+ });
55
+ const { proof } = cacheDecision;
56
+ if (entry.kind !== "layout" || proof.reuseClass !== "static-layout") return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_REUSE_CLASS_UNSUPPORTED", {
57
+ entryKind: entry.kind,
58
+ reuseClass: proof.reuseClass
59
+ });
60
+ if (entry.id !== proof.candidateOutput.layoutId) return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_ENTRY_ID_MISMATCH", {
61
+ cacheEntryId: proof.candidateOutput.layoutId,
62
+ manifestEntryId: entry.id
63
+ });
64
+ const artifactProofMismatches = collectArtifactCompatibilityProofMismatches(input.artifact.compatibility, proof.candidateArtifactCompatibility);
65
+ if (artifactProofMismatches.length > 0) return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_ARTIFACT_PROOF_MISMATCH", { mismatchedFields: artifactProofMismatches });
66
+ const artifactCompatibility = evaluateArtifactCompatibility(input.artifact.compatibility, entry.artifactCompatibility, { compatibilityMap: input.compatibilityMap });
67
+ if (artifactCompatibility.kind === "unknown") return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_ARTIFACT_COMPATIBILITY_UNKNOWN", {
68
+ compatibilityFallback: artifactCompatibility.fallback,
69
+ reason: artifactCompatibility.reason
70
+ });
71
+ if (artifactCompatibility.kind === "incompatible") return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_ARTIFACT_COMPATIBILITY_INCOMPATIBLE", {
72
+ compatibilityFallback: artifactCompatibility.fallback,
73
+ reason: artifactCompatibility.reason
74
+ });
75
+ if (entry.variantCacheKey !== proof.variant.cacheKey) return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_VARIANT_MISMATCH", {
76
+ cacheVariantCacheKeyHash: createClientReusePayloadHash(proof.variant.cacheKey),
77
+ entryVariantCacheKeyHash: createClientReusePayloadHash(entry.variantCacheKey)
78
+ });
79
+ if (input.artifact.payloadHash === null) return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_PAYLOAD_HASH_MISSING");
80
+ if (entry.payloadHash !== input.artifact.payloadHash) return rejectSkipCacheCrossCheck(entry, "SKIP_CACHE_PAYLOAD_HASH_MISMATCH", {
81
+ cachePayloadHash: input.artifact.payloadHash,
82
+ entryPayloadHash: entry.payloadHash
83
+ });
84
+ const invalidationRejection = crossCheckInvalidationProof(entry, input.artifact.invalidation);
85
+ if (invalidationRejection) return invalidationRejection;
86
+ return {
87
+ kind: "verified",
88
+ code: "SKIP_CACHE_CROSS_CHECK_PASSED",
89
+ entryId: entry.id,
90
+ fields: {
91
+ entryKind: entry.kind,
92
+ reuseClass: proof.reuseClass,
93
+ variantCacheKeyHash: createClientReusePayloadHash(proof.variant.cacheKey)
94
+ },
95
+ skipDisposition: createDisabledSkipDisposition()
96
+ };
97
+ }
98
+ //#endregion
99
+ export { crossCheckClientReuseManifestEntryWithCache };
100
+
101
+ //# sourceMappingURL=skip-cache-proof.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skip-cache-proof.js","names":[],"sources":["../../src/server/skip-cache-proof.ts"],"sourcesContent":["import {\n evaluateArtifactCompatibility,\n type ArtifactCompatibilityEnvelope,\n type ArtifactCompatibilityEvaluationOptions,\n} from \"./artifact-compatibility.js\";\nimport type { StaticLayoutArtifactReuseDecision } from \"./cache-proof.js\";\nimport {\n createClientReusePayloadHash,\n type ClientReuseManifestEntry,\n type ClientReuseManifestEntryRejection,\n type ClientReuseManifestSkipDisposition,\n type ClientReuseManifestTraceFields,\n} from \"./client-reuse-manifest.js\";\n\nexport type SkipCacheInvalidationProof =\n | Readonly<{ kind: \"invalidated\"; invalidationEpoch: string | null }>\n | Readonly<{ kind: \"unknown\" }>\n | Readonly<{ kind: \"valid\" }>;\n\ntype SkipCacheArtifactProof = Readonly<{\n compatibility: ArtifactCompatibilityEnvelope;\n invalidation: SkipCacheInvalidationProof;\n payloadHash: string | null;\n}>;\n\ntype SkipCacheCrossCheckAcceptanceCode = \"SKIP_CACHE_CROSS_CHECK_PASSED\";\n\ntype SkipCacheCrossCheckVerified = Readonly<{\n code: SkipCacheCrossCheckAcceptanceCode;\n entryId: string;\n fields: ClientReuseManifestTraceFields;\n kind: \"verified\";\n skipDisposition: ClientReuseManifestSkipDisposition;\n}>;\n\ntype SkipCacheCrossCheckRejected = Readonly<{\n kind: \"rejected\";\n rejection: ClientReuseManifestEntryRejection;\n skipDisposition: ClientReuseManifestSkipDisposition;\n}>;\n\ntype SkipCacheCrossCheckResult = SkipCacheCrossCheckRejected | SkipCacheCrossCheckVerified;\n\ntype CrossCheckClientReuseManifestEntryWithCacheInput = Readonly<{\n artifact: SkipCacheArtifactProof;\n cacheDecision: StaticLayoutArtifactReuseDecision | null;\n entry: ClientReuseManifestEntry;\n}> &\n ArtifactCompatibilityEvaluationOptions;\n\nconst ARTIFACT_COMPATIBILITY_PROOF_FIELDS: readonly (keyof ArtifactCompatibilityEnvelope)[] = [\n \"schemaVersion\",\n \"graphVersion\",\n \"deploymentVersion\",\n \"appElementsSchemaVersion\",\n \"rscPayloadSchemaVersion\",\n \"rootBoundaryId\",\n \"renderEpoch\",\n];\n\nfunction createDisabledSkipDisposition(): ClientReuseManifestSkipDisposition {\n return {\n code: \"SKIP_MODEL_DISABLED\",\n enabled: false,\n mode: \"renderAndSend\",\n };\n}\n\nfunction rejectSkipCacheCrossCheck(\n entry: ClientReuseManifestEntry,\n code: ClientReuseManifestEntryRejection[\"code\"],\n fields: ClientReuseManifestTraceFields = {},\n): SkipCacheCrossCheckRejected {\n return {\n kind: \"rejected\",\n rejection: {\n code,\n entryId: entry.id,\n fields,\n },\n skipDisposition: createDisabledSkipDisposition(),\n };\n}\n\nfunction collectArtifactCompatibilityProofMismatches(\n artifactCompatibility: ArtifactCompatibilityEnvelope,\n proofCompatibility: ArtifactCompatibilityEnvelope,\n): readonly string[] {\n const mismatchedFields: string[] = [];\n for (const field of ARTIFACT_COMPATIBILITY_PROOF_FIELDS) {\n if (artifactCompatibility[field] !== proofCompatibility[field]) {\n mismatchedFields.push(field);\n }\n }\n return mismatchedFields;\n}\n\nfunction assertNever(value: never): never {\n throw new Error(`Unhandled skip/cache proof state: ${String(value)}`);\n}\n\nfunction crossCheckInvalidationProof(\n entry: ClientReuseManifestEntry,\n invalidation: SkipCacheInvalidationProof,\n): SkipCacheCrossCheckRejected | null {\n switch (invalidation.kind) {\n case \"valid\":\n return null;\n case \"unknown\":\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_INVALIDATION_UNKNOWN\");\n case \"invalidated\":\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_INVALIDATED\", {\n invalidationEpoch: invalidation.invalidationEpoch,\n });\n default:\n return assertNever(invalidation);\n }\n}\n\nexport function crossCheckClientReuseManifestEntryWithCache(\n input: CrossCheckClientReuseManifestEntryWithCacheInput,\n): SkipCacheCrossCheckResult {\n const { cacheDecision, entry } = input;\n if (cacheDecision === null) {\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_PROOF_MISSING\");\n }\n if (cacheDecision.kind === \"fallback\") {\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_PROOF_REJECTED\", {\n cacheProofCode: cacheDecision.fallback.code,\n cacheProofMode: cacheDecision.fallback.mode,\n cacheProofScope: cacheDecision.fallback.scope,\n });\n }\n\n const { proof } = cacheDecision;\n if (entry.kind !== \"layout\" || proof.reuseClass !== \"static-layout\") {\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_REUSE_CLASS_UNSUPPORTED\", {\n entryKind: entry.kind,\n reuseClass: proof.reuseClass,\n });\n }\n\n if (entry.id !== proof.candidateOutput.layoutId) {\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_ENTRY_ID_MISMATCH\", {\n cacheEntryId: proof.candidateOutput.layoutId,\n manifestEntryId: entry.id,\n });\n }\n\n const artifactProofMismatches = collectArtifactCompatibilityProofMismatches(\n input.artifact.compatibility,\n proof.candidateArtifactCompatibility,\n );\n if (artifactProofMismatches.length > 0) {\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_ARTIFACT_PROOF_MISMATCH\", {\n mismatchedFields: artifactProofMismatches,\n });\n }\n\n const artifactCompatibility = evaluateArtifactCompatibility(\n input.artifact.compatibility,\n entry.artifactCompatibility,\n { compatibilityMap: input.compatibilityMap },\n );\n if (artifactCompatibility.kind === \"unknown\") {\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_ARTIFACT_COMPATIBILITY_UNKNOWN\", {\n compatibilityFallback: artifactCompatibility.fallback,\n reason: artifactCompatibility.reason,\n });\n }\n if (artifactCompatibility.kind === \"incompatible\") {\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_ARTIFACT_COMPATIBILITY_INCOMPATIBLE\", {\n compatibilityFallback: artifactCompatibility.fallback,\n reason: artifactCompatibility.reason,\n });\n }\n\n if (entry.variantCacheKey !== proof.variant.cacheKey) {\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_VARIANT_MISMATCH\", {\n cacheVariantCacheKeyHash: createClientReusePayloadHash(proof.variant.cacheKey),\n entryVariantCacheKeyHash: createClientReusePayloadHash(entry.variantCacheKey),\n });\n }\n\n if (input.artifact.payloadHash === null) {\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_PAYLOAD_HASH_MISSING\");\n }\n\n if (entry.payloadHash !== input.artifact.payloadHash) {\n return rejectSkipCacheCrossCheck(entry, \"SKIP_CACHE_PAYLOAD_HASH_MISMATCH\", {\n cachePayloadHash: input.artifact.payloadHash,\n entryPayloadHash: entry.payloadHash,\n });\n }\n\n const invalidationRejection = crossCheckInvalidationProof(entry, input.artifact.invalidation);\n if (invalidationRejection) return invalidationRejection;\n\n return {\n kind: \"verified\",\n code: \"SKIP_CACHE_CROSS_CHECK_PASSED\",\n entryId: entry.id,\n fields: {\n entryKind: entry.kind,\n reuseClass: proof.reuseClass,\n variantCacheKeyHash: createClientReusePayloadHash(proof.variant.cacheKey),\n },\n skipDisposition: createDisabledSkipDisposition(),\n };\n}\n"],"mappings":"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"}
@@ -21,7 +21,7 @@ type StaticFileEntry = {
21
21
  *
22
22
  * Usage:
23
23
  * const cache = await StaticFileCache.create(clientDir);
24
- * const entry = cache.lookup("/assets/app-abc123.js");
24
+ * const entry = cache.lookup("/_next/static/app-abc123.js");
25
25
  * // entry.br?.headers, entry.original.headers, etc.
26
26
  */
27
27
  declare class StaticFileCache {
@@ -1,5 +1,6 @@
1
+ import "../utils/asset-prefix.js";
1
2
  import path from "node:path";
2
- import fsp from "node:fs/promises";
3
+ import fs from "node:fs/promises";
3
4
  //#region src/server/static-file-cache.ts
4
5
  /**
5
6
  * Startup metadata cache for static file serving.
@@ -48,7 +49,7 @@ const BUFFER_THRESHOLD = 64 * 1024;
48
49
  *
49
50
  * Usage:
50
51
  * const cache = await StaticFileCache.create(clientDir);
51
- * const entry = cache.lookup("/assets/app-abc123.js");
52
+ * const entry = cache.lookup("/_next/static/app-abc123.js");
52
53
  * // entry.br?.headers, entry.original.headers, etc.
53
54
  */
54
55
  var StaticFileCache = class StaticFileCache {
@@ -74,7 +75,7 @@ var StaticFileCache = class StaticFileCache {
74
75
  if (relativePath.startsWith(".vite/") || relativePath === ".vite") continue;
75
76
  const ext = path.extname(relativePath);
76
77
  const contentType = CONTENT_TYPES[ext] ?? "application/octet-stream";
77
- const isHashed = relativePath.startsWith("assets/");
78
+ const isHashed = relativePath.startsWith(`_next/static/`) || relativePath.includes(`/_next/static/`);
78
79
  const cacheControl = isHashed ? "public, max-age=31536000, immutable" : "public, max-age=3600";
79
80
  const etag = isHashed && etagFromFilenameHash(relativePath, ext) || `W/"${fileInfo.size}-${Math.floor(fileInfo.mtimeMs / 1e3)}"`;
80
81
  const baseHeaders = {
@@ -134,7 +135,7 @@ var StaticFileCache = class StaticFileCache {
134
135
  }
135
136
  }
136
137
  for (let i = 0; i < toBuffer.length; i += 64) await Promise.all(toBuffer.slice(i, i + 64).map(async (v) => {
137
- v.buffer = await fsp.readFile(v.path);
138
+ v.buffer = await fs.readFile(v.path);
138
139
  }));
139
140
  return new StaticFileCache(entries);
140
141
  }
@@ -190,7 +191,7 @@ const STAT_BATCH_SIZE = 64;
190
191
  async function* walkFilesWithStats(dir, base = dir) {
191
192
  let entries;
192
193
  try {
193
- entries = await fsp.readdir(dir, { withFileTypes: true });
194
+ entries = await fs.readdir(dir, { withFileTypes: true });
194
195
  } catch {
195
196
  return;
196
197
  }
@@ -202,7 +203,7 @@ async function* walkFilesWithStats(dir, base = dir) {
202
203
  }
203
204
  for (let i = 0; i < files.length; i += STAT_BATCH_SIZE) {
204
205
  const batch = files.slice(i, i + STAT_BATCH_SIZE);
205
- const stats = await Promise.all(batch.map((f) => fsp.stat(f)));
206
+ const stats = await Promise.all(batch.map((f) => fs.stat(f)));
206
207
  for (let j = 0; j < batch.length; j++) yield {
207
208
  relativePath: path.relative(base, batch[j]),
208
209
  fullPath: batch[j],
@@ -1 +1 @@
1
- {"version":3,"file":"static-file-cache.js","names":[],"sources":["../../src/server/static-file-cache.ts"],"sourcesContent":["/**\n * Startup metadata cache for static file serving.\n *\n * Walks dist/client/ once at server boot, pre-computes response headers for\n * every file variant (original, brotli, gzip, zstd), and caches everything\n * in memory. The per-request hot path is just: Map.get() → string compare\n * (ETag) → writeHead(precomputed) → pipe.\n *\n * Modeled after sirv's production mode. Key insight from sirv: pre-compute\n * ALL response headers at startup — Content-Type, Content-Length, ETag,\n * Cache-Control, Content-Encoding, Vary — as reusable objects. The common\n * per-request path (no extraHeaders) does zero object allocation for headers.\n */\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\n\n/** Content-type lookup for static assets. Shared with prod-server.ts. */\nexport const CONTENT_TYPES: Record<string, string> = {\n \".js\": \"application/javascript\",\n \".mjs\": \"application/javascript\",\n \".css\": \"text/css\",\n \".html\": \"text/html\",\n \".json\": \"application/json\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".eot\": \"application/vnd.ms-fontobject\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".map\": \"application/json\",\n \".rsc\": \"text/x-component\",\n};\n\n/**\n * Files below this size are buffered in memory at startup for zero-syscall\n * serving via res.end(buffer). Above this, files stream via createReadStream.\n * 64KB covers virtually all precompressed assets (a 200KB JS bundle compresses\n * to ~50KB with brotli q5).\n */\nconst BUFFER_THRESHOLD = 64 * 1024;\n\n/** A servable file variant with pre-computed response headers. */\ntype FileVariant = {\n /** Absolute file path (used for streaming large files). */\n path: string;\n /** Uncompressed or encoded byte size for buffer-threshold decisions. */\n size: number;\n /** Pre-computed response headers. */\n headers: Record<string, string>;\n /** In-memory buffer for small files (below BUFFER_THRESHOLD). */\n buffer?: Buffer;\n};\n\ntype StaticFileEntry = {\n /** Weak ETag for conditional request matching. */\n etag: string;\n /** Pre-computed headers for 304 Not Modified response. */\n notModifiedHeaders: Record<string, string>;\n /** Original file variant (uncompressed). */\n original: FileVariant;\n /** Brotli precompressed variant, if .br file exists. */\n br?: FileVariant;\n /** Gzip precompressed variant, if .gz file exists. */\n gz?: FileVariant;\n /** Zstandard precompressed variant, if .zst file exists. */\n zst?: FileVariant;\n};\n\n/**\n * In-memory cache of static file metadata, populated once at server startup.\n *\n * Usage:\n * const cache = await StaticFileCache.create(clientDir);\n * const entry = cache.lookup(\"/assets/app-abc123.js\");\n * // entry.br?.headers, entry.original.headers, etc.\n */\nexport class StaticFileCache {\n private readonly entries: Map<string, StaticFileEntry>;\n\n private constructor(entries: Map<string, StaticFileEntry>) {\n this.entries = entries;\n }\n\n /**\n * Scan the client directory and build the cache.\n *\n * Gracefully handles non-existent directories (returns an empty cache).\n */\n static async create(clientDir: string): Promise<StaticFileCache> {\n const entries = new Map<string, StaticFileEntry>();\n\n // First pass: collect all regular files with their metadata\n const allFiles = new Map<string, { fullPath: string; size: number; mtimeMs: number }>();\n\n for await (const { relativePath, fullPath, stat } of walkFilesWithStats(clientDir)) {\n allFiles.set(relativePath, { fullPath, size: stat.size, mtimeMs: stat.mtimeMs });\n }\n\n // Second pass: build cache entries with pre-computed headers per variant\n for (const [relativePath, fileInfo] of allFiles) {\n // Skip precompressed variants — they're linked to their originals\n if (\n relativePath.endsWith(\".br\") ||\n relativePath.endsWith(\".gz\") ||\n relativePath.endsWith(\".zst\")\n )\n continue;\n\n // Skip .vite/ internal directory\n if (relativePath.startsWith(\".vite/\") || relativePath === \".vite\") continue;\n\n const ext = path.extname(relativePath);\n const contentType = CONTENT_TYPES[ext] ?? \"application/octet-stream\";\n const isHashed = relativePath.startsWith(\"assets/\");\n const cacheControl = isHashed\n ? \"public, max-age=31536000, immutable\"\n : \"public, max-age=3600\";\n const etag =\n (isHashed && etagFromFilenameHash(relativePath, ext)) ||\n `W/\"${fileInfo.size}-${Math.floor(fileInfo.mtimeMs / 1000)}\"`;\n\n // Base headers shared by all variants (Content-Type, Cache-Control, ETag)\n const baseHeaders = {\n \"Content-Type\": contentType,\n \"Cache-Control\": cacheControl,\n ETag: etag,\n };\n\n // Pre-compute original variant headers\n const original: FileVariant = {\n path: fileInfo.fullPath,\n size: fileInfo.size,\n headers: { ...baseHeaders, \"Content-Length\": String(fileInfo.size) },\n };\n\n const entry: StaticFileEntry = {\n etag,\n notModifiedHeaders: { ETag: etag, \"Cache-Control\": cacheControl },\n original,\n };\n\n // Pre-compute compressed variant headers (with Content-Encoding, Vary, correct Content-Length)\n const brInfo = allFiles.get(relativePath + \".br\");\n if (brInfo) {\n entry.br = buildVariant(brInfo, baseHeaders, \"br\");\n }\n\n const gzInfo = allFiles.get(relativePath + \".gz\");\n if (gzInfo) {\n entry.gz = buildVariant(gzInfo, baseHeaders, \"gzip\");\n }\n\n const zstInfo = allFiles.get(relativePath + \".zst\");\n if (zstInfo) {\n entry.zst = buildVariant(zstInfo, baseHeaders, \"zstd\");\n }\n\n // When compressed variants exist, the original needs Vary too so\n // shared caches don't serve uncompressed to compression-capable clients.\n if (entry.br || entry.gz || entry.zst) {\n original.headers[\"Vary\"] = \"Accept-Encoding\";\n entry.notModifiedHeaders[\"Vary\"] = \"Accept-Encoding\";\n }\n\n // Register under the URL pathname (leading /)\n // NOTE: aliases below share the same entry by reference, so all header\n // mutations (e.g. Vary above) must happen before registration.\n const pathname = \"/\" + relativePath;\n entries.set(pathname, entry);\n\n // Register HTML fallback aliases (same entry object — no duplication)\n if (ext === \".html\") {\n if (relativePath.endsWith(\"/index.html\")) {\n const dirPath = \"/\" + relativePath.slice(0, -\"/index.html\".length);\n if (dirPath !== \"/\") {\n entries.set(dirPath, entry);\n }\n } else {\n const withoutExt = \"/\" + relativePath.slice(0, -ext.length);\n entries.set(withoutExt, entry);\n }\n }\n }\n\n // Third pass: buffer small files in memory for zero-syscall serving.\n // For small compressed variants (e.g. a 50KB JS bundle → ~15KB brotli),\n // res.end(buffer) is ~2x faster than createReadStream().pipe() because\n // it skips fd open/close and stream plumbing overhead.\n // Reads are chunked at 64 concurrent to avoid fd exhaustion on large projects.\n // Deduplicate at the entry level first: HTML aliases share the same\n // StaticFileEntry by reference, so entries.values() yields duplicates for\n // paths like /about and /about.html. Deduping entries avoids iterating\n // their variants multiple times on sites with many HTML pages.\n const toBuffer: FileVariant[] = [];\n const seenEntries = new Set<StaticFileEntry>();\n for (const entry of entries.values()) {\n if (seenEntries.has(entry)) continue;\n seenEntries.add(entry);\n for (const variant of [entry.original, entry.br, entry.gz, entry.zst]) {\n if (!variant || variant.size > BUFFER_THRESHOLD) continue;\n toBuffer.push(variant);\n }\n }\n for (let i = 0; i < toBuffer.length; i += 64) {\n await Promise.all(\n toBuffer.slice(i, i + 64).map(async (v) => {\n v.buffer = await fsp.readFile(v.path);\n }),\n );\n }\n\n return new StaticFileCache(entries);\n }\n\n /**\n * Look up cached metadata for a URL pathname.\n *\n * Returns undefined if the file is not in the cache. The root path \"/\"\n * always returns undefined — index.html is served by SSR/RSC.\n */\n lookup(pathname: string): StaticFileEntry | undefined {\n if (pathname === \"/\") return undefined;\n\n // Block .vite/ access (including encoded variants that were decoded before lookup)\n if (pathname.startsWith(\"/.vite/\") || pathname === \"/.vite\") return undefined;\n\n return this.entries.get(pathname);\n }\n}\n\n/**\n * Extract a stable weak ETag from a Vite hashed filename (e.g. `app-DqZc3R4n.js`).\n * The hash is a content hash computed by the bundler — deterministic across\n * identical builds regardless of filesystem timestamps.\n *\n * Must be a weak validator (W/) because the same tag is shared across\n * content-encoded variants (original, .br, .gz, .zst) which are byte-different.\n * Returns null if the filename doesn't contain a recognizable hash suffix,\n * so the caller can fall back to mtime-based ETags.\n */\nexport function etagFromFilenameHash(relativePath: string, ext: string): string | null {\n const basename = path.basename(relativePath, ext);\n const lastDash = basename.lastIndexOf(\"-\");\n if (lastDash === -1 || lastDash === basename.length - 1) return null;\n const suffix = basename.slice(lastDash + 1);\n // Vite emits 8-char base64url hashes; allow 6-12 for other bundlers.\n // If Rolldown changes its hash length, update this range.\n return suffix.length >= 6 && suffix.length <= 12 && /^[A-Za-z0-9_-]+$/.test(suffix)\n ? `W/\"${suffix}\"`\n : null;\n}\n\nfunction buildVariant(\n info: { fullPath: string; size: number },\n baseHeaders: Record<string, string>,\n encoding: string,\n): FileVariant {\n return {\n path: info.fullPath,\n size: info.size,\n headers: {\n ...baseHeaders,\n \"Content-Encoding\": encoding,\n \"Content-Length\": String(info.size),\n Vary: \"Accept-Encoding\",\n },\n };\n}\n\n/** Batch size for concurrent stat() calls during directory walk. */\nconst STAT_BATCH_SIZE = 64;\n\n/**\n * Walk a directory recursively, yielding file paths and stats.\n *\n * Batches stat() calls per directory to avoid sequential syscall overhead\n * for large dist/client/ directories.\n */\nasync function* walkFilesWithStats(\n dir: string,\n base: string = dir,\n): AsyncGenerator<{\n relativePath: string;\n fullPath: string;\n stat: { size: number; mtimeMs: number };\n}> {\n let entries;\n try {\n entries = await fsp.readdir(dir, { withFileTypes: true });\n } catch {\n return; // directory doesn't exist or unreadable\n }\n\n // Recurse into subdirectories first (they yield their own batched stats)\n const files: string[] = [];\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n yield* walkFilesWithStats(fullPath, base);\n } else if (entry.isFile()) {\n files.push(fullPath);\n }\n }\n\n // Batch stat() calls for files in this directory\n for (let i = 0; i < files.length; i += STAT_BATCH_SIZE) {\n const batch = files.slice(i, i + STAT_BATCH_SIZE);\n const stats = await Promise.all(batch.map((f) => fsp.stat(f)));\n for (let j = 0; j < batch.length; j++) {\n yield {\n relativePath: path.relative(base, batch[j]),\n fullPath: batch[j],\n stat: { size: stats[j].size, mtimeMs: stats[j].mtimeMs },\n };\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"static-file-cache.js","names":["fsp"],"sources":["../../src/server/static-file-cache.ts"],"sourcesContent":["/**\n * Startup metadata cache for static file serving.\n *\n * Walks dist/client/ once at server boot, pre-computes response headers for\n * every file variant (original, brotli, gzip, zstd), and caches everything\n * in memory. The per-request hot path is just: Map.get() → string compare\n * (ETag) → writeHead(precomputed) → pipe.\n *\n * Modeled after sirv's production mode. Key insight from sirv: pre-compute\n * ALL response headers at startup — Content-Type, Content-Length, ETag,\n * Cache-Control, Content-Encoding, Vary — as reusable objects. The common\n * per-request path (no extraHeaders) does zero object allocation for headers.\n */\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { ASSET_PREFIX_URL_DIR } from \"../utils/asset-prefix.js\";\n\n/** Content-type lookup for static assets. Shared with prod-server.ts. */\nexport const CONTENT_TYPES: Record<string, string> = {\n \".js\": \"application/javascript\",\n \".mjs\": \"application/javascript\",\n \".css\": \"text/css\",\n \".html\": \"text/html\",\n \".json\": \"application/json\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".eot\": \"application/vnd.ms-fontobject\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".map\": \"application/json\",\n \".rsc\": \"text/x-component\",\n};\n\n/**\n * Files below this size are buffered in memory at startup for zero-syscall\n * serving via res.end(buffer). Above this, files stream via createReadStream.\n * 64KB covers virtually all precompressed assets (a 200KB JS bundle compresses\n * to ~50KB with brotli q5).\n */\nconst BUFFER_THRESHOLD = 64 * 1024;\n\n/** A servable file variant with pre-computed response headers. */\ntype FileVariant = {\n /** Absolute file path (used for streaming large files). */\n path: string;\n /** Uncompressed or encoded byte size for buffer-threshold decisions. */\n size: number;\n /** Pre-computed response headers. */\n headers: Record<string, string>;\n /** In-memory buffer for small files (below BUFFER_THRESHOLD). */\n buffer?: Buffer;\n};\n\ntype StaticFileEntry = {\n /** Weak ETag for conditional request matching. */\n etag: string;\n /** Pre-computed headers for 304 Not Modified response. */\n notModifiedHeaders: Record<string, string>;\n /** Original file variant (uncompressed). */\n original: FileVariant;\n /** Brotli precompressed variant, if .br file exists. */\n br?: FileVariant;\n /** Gzip precompressed variant, if .gz file exists. */\n gz?: FileVariant;\n /** Zstandard precompressed variant, if .zst file exists. */\n zst?: FileVariant;\n};\n\n/**\n * In-memory cache of static file metadata, populated once at server startup.\n *\n * Usage:\n * const cache = await StaticFileCache.create(clientDir);\n * const entry = cache.lookup(\"/_next/static/app-abc123.js\");\n * // entry.br?.headers, entry.original.headers, etc.\n */\nexport class StaticFileCache {\n private readonly entries: Map<string, StaticFileEntry>;\n\n private constructor(entries: Map<string, StaticFileEntry>) {\n this.entries = entries;\n }\n\n /**\n * Scan the client directory and build the cache.\n *\n * Gracefully handles non-existent directories (returns an empty cache).\n */\n static async create(clientDir: string): Promise<StaticFileCache> {\n const entries = new Map<string, StaticFileEntry>();\n\n // First pass: collect all regular files with their metadata\n const allFiles = new Map<string, { fullPath: string; size: number; mtimeMs: number }>();\n\n for await (const { relativePath, fullPath, stat } of walkFilesWithStats(clientDir)) {\n allFiles.set(relativePath, { fullPath, size: stat.size, mtimeMs: stat.mtimeMs });\n }\n\n // Second pass: build cache entries with pre-computed headers per variant\n for (const [relativePath, fileInfo] of allFiles) {\n // Skip precompressed variants — they're linked to their originals\n if (\n relativePath.endsWith(\".br\") ||\n relativePath.endsWith(\".gz\") ||\n relativePath.endsWith(\".zst\")\n )\n continue;\n\n // Skip .vite/ internal directory\n if (relativePath.startsWith(\".vite/\") || relativePath === \".vite\") continue;\n\n const ext = path.extname(relativePath);\n const contentType = CONTENT_TYPES[ext] ?? \"application/octet-stream\";\n // Files under Vite's `assetsDir` are content-hashed. The default\n // layout writes to `<ASSET_PREFIX_URL_DIR>/` (Next.js's canonical\n // convention); when `assetPrefix` is a path prefix the layout\n // becomes `<prefix>/<ASSET_PREFIX_URL_DIR>/...`. Both forms get\n // long-lived `immutable` cache headers — the hash in the filename\n // invalidates safely.\n //\n // `relativePath` is the path relative to `clientDir`, with no\n // leading slash. Because of that, `startsWith(\"<dir>/\")` and\n // `includes(\"/<dir>/\")` are NOT equivalent — the former covers the\n // default and absolute-URL prefix layouts (no parent directory),\n // the latter covers the path-prefix layout (under an arbitrary\n // parent like `cdn/`).\n const isHashed =\n relativePath.startsWith(`${ASSET_PREFIX_URL_DIR}/`) ||\n relativePath.includes(`/${ASSET_PREFIX_URL_DIR}/`);\n const cacheControl = isHashed\n ? \"public, max-age=31536000, immutable\"\n : \"public, max-age=3600\";\n const etag =\n (isHashed && etagFromFilenameHash(relativePath, ext)) ||\n `W/\"${fileInfo.size}-${Math.floor(fileInfo.mtimeMs / 1000)}\"`;\n\n // Base headers shared by all variants (Content-Type, Cache-Control, ETag)\n const baseHeaders = {\n \"Content-Type\": contentType,\n \"Cache-Control\": cacheControl,\n ETag: etag,\n };\n\n // Pre-compute original variant headers\n const original: FileVariant = {\n path: fileInfo.fullPath,\n size: fileInfo.size,\n headers: { ...baseHeaders, \"Content-Length\": String(fileInfo.size) },\n };\n\n const entry: StaticFileEntry = {\n etag,\n notModifiedHeaders: { ETag: etag, \"Cache-Control\": cacheControl },\n original,\n };\n\n // Pre-compute compressed variant headers (with Content-Encoding, Vary, correct Content-Length)\n const brInfo = allFiles.get(relativePath + \".br\");\n if (brInfo) {\n entry.br = buildVariant(brInfo, baseHeaders, \"br\");\n }\n\n const gzInfo = allFiles.get(relativePath + \".gz\");\n if (gzInfo) {\n entry.gz = buildVariant(gzInfo, baseHeaders, \"gzip\");\n }\n\n const zstInfo = allFiles.get(relativePath + \".zst\");\n if (zstInfo) {\n entry.zst = buildVariant(zstInfo, baseHeaders, \"zstd\");\n }\n\n // When compressed variants exist, the original needs Vary too so\n // shared caches don't serve uncompressed to compression-capable clients.\n if (entry.br || entry.gz || entry.zst) {\n original.headers[\"Vary\"] = \"Accept-Encoding\";\n entry.notModifiedHeaders[\"Vary\"] = \"Accept-Encoding\";\n }\n\n // Register under the URL pathname (leading /)\n // NOTE: aliases below share the same entry by reference, so all header\n // mutations (e.g. Vary above) must happen before registration.\n const pathname = \"/\" + relativePath;\n entries.set(pathname, entry);\n\n // Register HTML fallback aliases (same entry object — no duplication)\n if (ext === \".html\") {\n if (relativePath.endsWith(\"/index.html\")) {\n const dirPath = \"/\" + relativePath.slice(0, -\"/index.html\".length);\n if (dirPath !== \"/\") {\n entries.set(dirPath, entry);\n }\n } else {\n const withoutExt = \"/\" + relativePath.slice(0, -ext.length);\n entries.set(withoutExt, entry);\n }\n }\n }\n\n // Third pass: buffer small files in memory for zero-syscall serving.\n // For small compressed variants (e.g. a 50KB JS bundle → ~15KB brotli),\n // res.end(buffer) is ~2x faster than createReadStream().pipe() because\n // it skips fd open/close and stream plumbing overhead.\n // Reads are chunked at 64 concurrent to avoid fd exhaustion on large projects.\n // Deduplicate at the entry level first: HTML aliases share the same\n // StaticFileEntry by reference, so entries.values() yields duplicates for\n // paths like /about and /about.html. Deduping entries avoids iterating\n // their variants multiple times on sites with many HTML pages.\n const toBuffer: FileVariant[] = [];\n const seenEntries = new Set<StaticFileEntry>();\n for (const entry of entries.values()) {\n if (seenEntries.has(entry)) continue;\n seenEntries.add(entry);\n for (const variant of [entry.original, entry.br, entry.gz, entry.zst]) {\n if (!variant || variant.size > BUFFER_THRESHOLD) continue;\n toBuffer.push(variant);\n }\n }\n for (let i = 0; i < toBuffer.length; i += 64) {\n await Promise.all(\n toBuffer.slice(i, i + 64).map(async (v) => {\n v.buffer = await fsp.readFile(v.path);\n }),\n );\n }\n\n return new StaticFileCache(entries);\n }\n\n /**\n * Look up cached metadata for a URL pathname.\n *\n * Returns undefined if the file is not in the cache. The root path \"/\"\n * always returns undefined — index.html is served by SSR/RSC.\n */\n lookup(pathname: string): StaticFileEntry | undefined {\n if (pathname === \"/\") return undefined;\n\n // Block .vite/ access (including encoded variants that were decoded before lookup)\n if (pathname.startsWith(\"/.vite/\") || pathname === \"/.vite\") return undefined;\n\n return this.entries.get(pathname);\n }\n}\n\n/**\n * Extract a stable weak ETag from a Vite hashed filename (e.g. `app-DqZc3R4n.js`).\n * The hash is a content hash computed by the bundler — deterministic across\n * identical builds regardless of filesystem timestamps.\n *\n * Must be a weak validator (W/) because the same tag is shared across\n * content-encoded variants (original, .br, .gz, .zst) which are byte-different.\n * Returns null if the filename doesn't contain a recognizable hash suffix,\n * so the caller can fall back to mtime-based ETags.\n */\nexport function etagFromFilenameHash(relativePath: string, ext: string): string | null {\n const basename = path.basename(relativePath, ext);\n const lastDash = basename.lastIndexOf(\"-\");\n if (lastDash === -1 || lastDash === basename.length - 1) return null;\n const suffix = basename.slice(lastDash + 1);\n // Vite emits 8-char base64url hashes; allow 6-12 for other bundlers.\n // If Rolldown changes its hash length, update this range.\n return suffix.length >= 6 && suffix.length <= 12 && /^[A-Za-z0-9_-]+$/.test(suffix)\n ? `W/\"${suffix}\"`\n : null;\n}\n\nfunction buildVariant(\n info: { fullPath: string; size: number },\n baseHeaders: Record<string, string>,\n encoding: string,\n): FileVariant {\n return {\n path: info.fullPath,\n size: info.size,\n headers: {\n ...baseHeaders,\n \"Content-Encoding\": encoding,\n \"Content-Length\": String(info.size),\n Vary: \"Accept-Encoding\",\n },\n };\n}\n\n/** Batch size for concurrent stat() calls during directory walk. */\nconst STAT_BATCH_SIZE = 64;\n\n/**\n * Walk a directory recursively, yielding file paths and stats.\n *\n * Batches stat() calls per directory to avoid sequential syscall overhead\n * for large dist/client/ directories.\n */\nasync function* walkFilesWithStats(\n dir: string,\n base: string = dir,\n): AsyncGenerator<{\n relativePath: string;\n fullPath: string;\n stat: { size: number; mtimeMs: number };\n}> {\n let entries;\n try {\n entries = await fsp.readdir(dir, { withFileTypes: true });\n } catch {\n return; // directory doesn't exist or unreadable\n }\n\n // Recurse into subdirectories first (they yield their own batched stats)\n const files: string[] = [];\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n yield* walkFilesWithStats(fullPath, base);\n } else if (entry.isFile()) {\n files.push(fullPath);\n }\n }\n\n // Batch stat() calls for files in this directory\n for (let i = 0; i < files.length; i += STAT_BATCH_SIZE) {\n const batch = files.slice(i, i + STAT_BATCH_SIZE);\n const stats = await Promise.all(batch.map((f) => fsp.stat(f)));\n for (let j = 0; j < batch.length; j++) {\n yield {\n relativePath: path.relative(base, batch[j]),\n fullPath: batch[j],\n stat: { size: stats[j].size, mtimeMs: stats[j].mtimeMs },\n };\n }\n }\n}\n"],"mappings":"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"}
@@ -2,10 +2,27 @@ import { CacheLifeConfig } from "./cache.js";
2
2
  import * as _$node_async_hooks0 from "node:async_hooks";
3
3
 
4
4
  //#region src/shims/cache-runtime.d.ts
5
+ /**
6
+ * Used purely as `cause` for the nested-dynamic cache error: its captured stack
7
+ * points at the inner "use cache" invocation that propagated a dynamic cache
8
+ * life up to the outer cache. Constructed eagerly while the caller is still on
9
+ * the synchronous stack.
10
+ */
11
+ declare class NestedDynamicUseCacheError extends Error {
12
+ constructor();
13
+ }
5
14
  type CacheContext = {
6
15
  /** Tags collected via cacheTag() during execution */tags: string[]; /** Cache life configs collected via cacheLife() — minimum-wins rule applies */
7
16
  lifeConfigs: CacheLifeConfig[]; /** Cache variant: "default" | "remote" | "private" */
8
- variant: string;
17
+ variant: string; /** Whether cacheLife() was called with an explicit revalidate value */
18
+ hasExplicitRevalidate: boolean; /** Whether cacheLife() was called with an explicit expire value */
19
+ hasExplicitExpire: boolean;
20
+ /**
21
+ * The first nested public "use cache" invocation with a dynamic cache life
22
+ * (revalidate === 0 or expire < DYNAMIC_EXPIRE) that propagated up to this
23
+ * cache. Used as `cause` for the nested-dynamic cache error.
24
+ */
25
+ dynamicNestedCacheError: Error | undefined;
9
26
  };
10
27
  declare const cacheContextStorage: _$node_async_hooks0.AsyncLocalStorage<CacheContext>;
11
28
  /**
@@ -47,5 +64,5 @@ declare function clearPrivateCache(): void;
47
64
  */
48
65
  declare function registerCachedFunction<T extends (...args: any[]) => Promise<any>>(fn: T, id: string, variant?: string): T;
49
66
  //#endregion
50
- export { CacheContext, PrivateCacheState, cacheContextStorage, clearPrivateCache, getCacheContext, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
67
+ export { CacheContext, NestedDynamicUseCacheError, PrivateCacheState, cacheContextStorage, clearPrivateCache, getCacheContext, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
51
68
  //# sourceMappingURL=cache-runtime.d.ts.map
@@ -32,6 +32,44 @@ import { _registerCacheContextAccessor, _setRequestScopedCacheLife, cacheLifePro
32
32
  * - "use cache: remote" — shared cache (explicit)
33
33
  * - "use cache: private" — per-request cache (not shared across requests)
34
34
  */
35
+ /** Threshold below which expire is considered "dynamic" (5 minutes in seconds). */
36
+ const DYNAMIC_EXPIRE = 300;
37
+ /**
38
+ * Used purely as `cause` for the nested-dynamic cache error: its captured stack
39
+ * points at the inner "use cache" invocation that propagated a dynamic cache
40
+ * life up to the outer cache. Constructed eagerly while the caller is still on
41
+ * the synchronous stack.
42
+ */
43
+ var NestedDynamicUseCacheError = class extends Error {
44
+ constructor() {
45
+ super("This \"use cache\" has a dynamic cache life that was propagated to its parent.");
46
+ this.name = "Nested dynamic \"use cache\"";
47
+ }
48
+ };
49
+ /**
50
+ * Returns the human-readable phrase describing the current context for use in
51
+ * nested-dynamic error messages. The throw is gated to fire only during the
52
+ * build's prerender phase (`VINEXT_PRERENDER=1`) or development; this phrase
53
+ * tells the user which one they're in so the message isn't misleading.
54
+ *
55
+ * `VINEXT_PRERENDER` takes priority over `NODE_ENV=development`: if the
56
+ * prerender flag is set, the user really is prerendering regardless of
57
+ * NODE_ENV (this matters for scenarios like a dev-config prerender). Defaults
58
+ * to "during prerendering" to match Next.js wording when called from a
59
+ * context we don't recognize (the throw also wouldn't fire in that case).
60
+ */
61
+ function nestedCacheContextPhrase() {
62
+ if (typeof process === "undefined") return "during prerendering";
63
+ if (process.env.VINEXT_PRERENDER === "1") return "during prerendering";
64
+ if (process.env.NODE_ENV === "development") return "in development";
65
+ return "during prerendering";
66
+ }
67
+ function getNestedCacheZeroRevalidateErrorMessage() {
68
+ return `A "use cache" with zero \`revalidate\` is nested inside another "use cache" that has no explicit \`cacheLife\`, which is not allowed ${nestedCacheContextPhrase()}. Add \`cacheLife()\` to the outer "use cache" to choose whether it should be prerendered (with non-zero \`revalidate\`) or remain dynamic (with zero \`revalidate\`). Read more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife`;
69
+ }
70
+ function getNestedCacheShortExpireErrorMessage() {
71
+ return `A "use cache" with short \`expire\` (under 5 minutes) is nested inside another "use cache" that has no explicit \`cacheLife\`, which is not allowed ${nestedCacheContextPhrase()}. Add \`cacheLife()\` to the outer "use cache" to choose whether it should be prerendered (with longer \`expire\`) or remain dynamic (with short \`expire\`). Read more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife`;
72
+ }
35
73
  const cacheContextStorage = getOrCreateAls("vinext.cacheRuntime.contextAls");
36
74
  _registerCacheContextAccessor(() => cacheContextStorage.getStore() ?? null);
37
75
  /**
@@ -227,13 +265,7 @@ function registerCachedFunction(fn, id, variant) {
227
265
  recordRequestScopedCacheControl(existing.cacheControl);
228
266
  return result;
229
267
  } catch {}
230
- const ctx = {
231
- tags: [],
232
- lifeConfigs: [],
233
- variant: cacheVariant || "default"
234
- };
235
- const result = await cacheContextStorage.run(ctx, () => fn(...args));
236
- const effectiveLife = resolveCacheLife(ctx.lifeConfigs);
268
+ const { result, ctx, effectiveLife } = await runCachedFunctionWithContext(fn, args, cacheVariant);
237
269
  recordRequestScopedCacheLife(effectiveLife);
238
270
  const revalidateSeconds = effectiveLife.revalidate ?? cacheLifeProfiles.default.revalidate ?? 900;
239
271
  try {
@@ -280,14 +312,38 @@ function recordRequestScopedCacheLife(cacheLife) {
280
312
  _setRequestScopedCacheLife(cacheLife);
281
313
  }
282
314
  async function executeWithContext(fn, args, variant) {
315
+ const { result, ctx: _ctx, effectiveLife } = await runCachedFunctionWithContext(fn, args, variant);
316
+ recordRequestScopedCacheLife(effectiveLife);
317
+ return result;
318
+ }
319
+ async function runCachedFunctionWithContext(fn, args, variant) {
320
+ const parentCtx = cacheContextStorage.getStore();
321
+ let eagerError;
322
+ if (parentCtx && parentCtx.variant !== "private") {
323
+ eagerError = new NestedDynamicUseCacheError();
324
+ if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(eagerError, runCachedFunctionWithContext);
325
+ }
283
326
  const ctx = {
284
327
  tags: [],
285
328
  lifeConfigs: [],
286
- variant: variant || "default"
329
+ variant: variant || "default",
330
+ hasExplicitRevalidate: false,
331
+ hasExplicitExpire: false,
332
+ dynamicNestedCacheError: void 0
287
333
  };
288
334
  const result = await cacheContextStorage.run(ctx, () => fn(...args));
289
- recordRequestScopedCacheLife(resolveCacheLife(ctx.lifeConfigs));
290
- return result;
335
+ const effectiveLife = resolveCacheLife(ctx.lifeConfigs);
336
+ if (parentCtx) parentCtx.lifeConfigs.push(effectiveLife);
337
+ if (parentCtx && eagerError && (effectiveLife.revalidate === 0 || effectiveLife.expire !== void 0 && effectiveLife.expire < DYNAMIC_EXPIRE)) parentCtx.dynamicNestedCacheError ??= eagerError;
338
+ if (typeof process !== "undefined" && (process.env.VINEXT_PRERENDER === "1" || process.env.NODE_ENV === "development") && ctx.dynamicNestedCacheError) {
339
+ if (effectiveLife.revalidate === 0 && !ctx.hasExplicitRevalidate) throw new Error(getNestedCacheZeroRevalidateErrorMessage(), { cause: ctx.dynamicNestedCacheError });
340
+ if (effectiveLife.expire !== void 0 && effectiveLife.expire < DYNAMIC_EXPIRE && !ctx.hasExplicitExpire) throw new Error(getNestedCacheShortExpireErrorMessage(), { cause: ctx.dynamicNestedCacheError });
341
+ }
342
+ return {
343
+ result,
344
+ ctx,
345
+ effectiveLife
346
+ };
291
347
  }
292
348
  /**
293
349
  * Recursively unwrap "thenable objects" — values created by
@@ -346,6 +402,6 @@ function stableStringify(value, seen) {
346
402
  return JSON.stringify(value);
347
403
  }
348
404
  //#endregion
349
- export { cacheContextStorage, clearPrivateCache, getCacheContext, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
405
+ export { NestedDynamicUseCacheError, cacheContextStorage, clearPrivateCache, getCacheContext, registerCachedFunction, replyToCacheKey, runWithPrivateCache };
350
406
 
351
407
  //# sourceMappingURL=cache-runtime.js.map