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
@@ -0,0 +1,118 @@
1
+ //#region src/shims/cache-adapter-instantiate.ts
2
+ const REQUIREMENTS = {
3
+ data: {
4
+ methods: [
5
+ "get",
6
+ "set",
7
+ "revalidateTag"
8
+ ],
9
+ booleans: [],
10
+ description: "A data cache adapter implements get, set and revalidateTag."
11
+ },
12
+ cdn: {
13
+ methods: [
14
+ "get",
15
+ "set",
16
+ "revalidateTag",
17
+ "buildResponseHeaders"
18
+ ],
19
+ booleans: ["ownsBackgroundRevalidation"],
20
+ description: "A CDN cache adapter implements get, set, revalidateTag and buildResponseHeaders, and sets ownsBackgroundRevalidation to a boolean."
21
+ }
22
+ };
23
+ /**
24
+ * Whether `value` has a [[Construct]] internal method. A Proxy is
25
+ * constructible exactly when its target is; its no-op `construct` trap
26
+ * answers without running the export or reading any of its properties.
27
+ */
28
+ function isConstructor(value) {
29
+ if (typeof value !== "function") return false;
30
+ try {
31
+ new new Proxy(value, { construct: () => ({}) })();
32
+ return true;
33
+ } catch {
34
+ return false;
35
+ }
36
+ }
37
+ const CLASS_SOURCE = /^class\b/;
38
+ /**
39
+ * Whether an export is class syntax and must be invoked with `new`. The
40
+ * [[Construct]] check excludes methods named `class`, whose source text
41
+ * also starts with that word.
42
+ */
43
+ function isClassExport(value) {
44
+ if (!isConstructor(value)) return false;
45
+ try {
46
+ return CLASS_SOURCE.test(Function.prototype.toString.call(value));
47
+ } catch {
48
+ return false;
49
+ }
50
+ }
51
+ function describeValue(value) {
52
+ if (value === null) return "null";
53
+ if (Array.isArray(value)) return "an array";
54
+ if (typeof value === "object") return "an object";
55
+ return typeof value === "undefined" ? "undefined" : `a ${typeof value}`;
56
+ }
57
+ const ignore = () => {};
58
+ /**
59
+ * Attach a no-op rejection handler with the intrinsic `Promise.prototype.then`,
60
+ * which throws on a non-Promise before reading anything from it. Returns the
61
+ * derived promise, which a Promise subclass's species constructor chooses.
62
+ */
63
+ function handleRejection(promise) {
64
+ return Promise.prototype.then.call(promise, void 0, ignore);
65
+ }
66
+ /**
67
+ * Whether `value` is a Promise, judged by its internal slot or this realm's
68
+ * Promise prototype chain, never by a `then` member: adapter contracts are
69
+ * structural and do not reserve `then`, so an adapter's own `then` method is
70
+ * never read or invoked.
71
+ *
72
+ * A Promise from any realm passes the intrinsic `then`'s brand check, which
73
+ * also attaches a no-op rejection handler, so the discarded result cannot
74
+ * become an unhandled rejection. The derived promise that call returns is
75
+ * handled too, since a subclass's species constructor may return a rejected
76
+ * one.
77
+ *
78
+ * Known limitation: when a Promise subclass's `constructor` or
79
+ * `Symbol.species` lookup throws, that call fails after the brand check, and
80
+ * no handler can be attached (every way of observing a Promise goes through
81
+ * that lookup or its `then`). Such a Promise is still rejected when it comes
82
+ * from this realm, the one adapter modules are evaluated in; one from another
83
+ * realm is judged by its members like any other value.
84
+ */
85
+ function markHandledIfPromise(value) {
86
+ let derived;
87
+ try {
88
+ derived = handleRejection(value);
89
+ } catch {
90
+ try {
91
+ return value instanceof Promise;
92
+ } catch {
93
+ return false;
94
+ }
95
+ }
96
+ try {
97
+ handleRejection(derived);
98
+ } catch {}
99
+ return true;
100
+ }
101
+ function instantiateCacheAdapter(exported, args, slot) {
102
+ const label = `cache.${slot} adapter`;
103
+ const requirements = REQUIREMENTS[slot];
104
+ if (typeof exported !== "function") {
105
+ const hint = exported !== null && typeof exported === "object" ? " To use an adapter object directly, export a factory that returns it: `export default () => adapter`." : exported === void 0 ? " Check that the module has a default export." : "";
106
+ throw new TypeError(`${label}: the module's default export must be a factory function or a class that receives { env, options }, got ${describeValue(exported)}.${hint}`);
107
+ }
108
+ const adapter = isClassExport(exported) ? new exported(args) : exported(args);
109
+ const isObjectLike = adapter !== null && typeof adapter === "object" || typeof adapter === "function";
110
+ if (isObjectLike && markHandledIfPromise(adapter)) throw new TypeError(`${label}: the default export returned a Promise. Adapter factories must return the adapter synchronously; defer async setup to the adapter's methods.`);
111
+ if (!isObjectLike) throw new TypeError(`${label}: the default export must produce an adapter object, got ${describeValue(adapter)}. ${requirements.description}`);
112
+ const record = adapter;
113
+ const problems = [...requirements.methods.filter((method) => typeof record[method] !== "function").map((method) => `method ${method}`), ...requirements.booleans.filter((property) => typeof record[property] !== "boolean").map((property) => `boolean ${property}`)];
114
+ if (problems.length > 0) throw new TypeError(`${label}: the adapter produced by the default export is missing ${problems.join(", ")}. ${requirements.description}`);
115
+ return adapter;
116
+ }
117
+ //#endregion
118
+ export { instantiateCacheAdapter, isClassExport, isConstructor };
@@ -4,48 +4,12 @@ import { RegisterCachedFunctionOptions } from "./cache-runtime.js";
4
4
  declare const CACHE_CAPTURE_TYPE = "use-cache-captures";
5
5
  type CacheCaptureEnvelope = {
6
6
  type: typeof CACHE_CAPTURE_TYPE;
7
- encrypted: string | PromiseLike<string>;
7
+ encrypted: Promise<string>;
8
8
  };
9
- /**
10
- * Flight serializes a promise as its resolved value and drops its own fields.
11
- * Next.js params are promises that also expose their resolved fields, and the
12
- * cache key is built from those fields, so the payload carries each such
13
- * promise's fields next to the arguments and decoding assigns them back.
14
- */
15
- type EncodedCacheArguments = {
16
- args: unknown[];
17
- thenableObjects: EncodedThenableObject[];
18
- };
19
- /**
20
- * Flight writes each object once, so `promise` decodes to the same promise as
21
- * every other reference to it, including ones inside resolved values, and the
22
- * fields share references with the arguments. The fields build the cache key;
23
- * the resolved value can differ: the params proxy hides params named like
24
- * promise or React fields (`value`, `status`) from its own keys but still
25
- * resolves to them.
26
- */
27
- type EncodedThenableObject = {
28
- fields: Record<string, unknown>;
29
- promise: PromiseLike<unknown>;
30
- };
31
- export declare function encryptCacheCaptures(captures: unknown[]): CacheCaptureEnvelope;
32
- /**
33
- * What to do when a read would run a getter: `reject` throws
34
- * `UnreplayableCacheArgumentsError`, `skip` leaves the getter unread.
35
- */
36
- type GetterHandling = "reject" | "skip";
37
- /**
38
- * Collect the own fields of every promise-augmented object in the arguments,
39
- * including ones inside resolved promise values. The arguments are passed to
40
- * Flight as they are, so Flight keeps their shared references and cycles.
41
- * With `getters: "reject"`, throws `UnreplayableCacheArgumentsError` when the
42
- * arguments hold a getter; with `"skip"`, promise fields behind a getter are
43
- * not recorded.
44
- */
45
- export declare function encodeCacheArguments(args: unknown[], getters?: GetterHandling): Promise<EncodedCacheArguments>;
46
- /** Restore the promise fields that `encodeCacheArguments` captured before Flight encoding. */
47
- export declare function decodeCacheArguments(value: unknown): unknown[];
48
- export declare function registerCachedFunction<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => Promise<TResult>, id: string, variant: string, options: RegisterCachedFunctionOptions): (...args: TArgs) => Promise<TResult>;
49
- /** Load and invoke one transformed cache function through its server-reference identity. */
9
+ export declare function encryptCacheCaptures(referenceId: string, captures: unknown[]): CacheCaptureEnvelope;
10
+ export declare function registerCachedFunction<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => Promise<TResult>, id: string, variant: string, { captureCount, ...options }: RegisterCachedFunctionOptions & {
11
+ captureCount?: number;
12
+ }): (...args: TArgs) => Promise<TResult>;
13
+ /** Replay the persisted payload without re-reading or re-encoding caller objects. */
50
14
  export declare function invokeCacheFunction(invocation: VinextCacheFunctionInvocation, loadServerAction: (id: string) => Promise<unknown>): Promise<void>;
51
15
  //#endregion
@@ -1,190 +1,81 @@
1
- import { isThenableObject, isUseCacheFunction, registerCachedFunction as registerCachedFunction$1 } from "./cache-runtime.js";
1
+ import { restoreFlightReply, snapshotFlightReply } from "./cache-flight-arguments.js";
2
+ import { isUseCacheFunction, memoizeInCacheScope, registerCachedFunction as registerCachedFunction$1, replayCachedFunction } from "./cache-runtime.js";
2
3
  import { decryptActionBoundArgs, encryptActionBoundArgs } from "@vitejs/plugin-rsc/utils/encryption-runtime";
4
+ import { createFromReadableStream, renderToReadableStream } from "@vitejs/plugin-rsc/react/rsc";
3
5
  //#region src/shims/cache-callable-runtime.ts
4
6
  const CACHE_CAPTURE_TYPE = "use-cache-captures";
5
- function encryptCacheCaptures(captures) {
6
- return {
7
- type: CACHE_CAPTURE_TYPE,
8
- encrypted: encryptCaptures(captures)
9
- };
10
- }
11
- async function decryptCacheCaptures(value) {
12
- if (!isCacheCaptureEnvelope(value)) return;
13
- return decryptCacheArguments(value.encrypted);
14
- }
15
- async function encryptCaptures(captures) {
16
- return encryptActionBoundArgs(await encodeCacheArguments(captures, "skip"));
17
- }
18
- async function encryptCacheArguments(args) {
19
- return encryptActionBoundArgs(await encodeCacheArguments(args));
20
- }
21
- async function decryptCacheArguments(encrypted) {
22
- return decodeCacheArguments(await decryptActionBoundArgs(Promise.resolve(encrypted)));
23
- }
24
- function isThenable(value) {
25
- return "then" in value && typeof value.then === "function";
26
- }
27
- function isPlainRecord(value) {
28
- const prototype = Object.getPrototypeOf(value);
29
- return (prototype === Object.prototype || prototype === null) && !("$$typeof" in value);
30
- }
31
- /**
32
- * The arguments hold a getter. Flight reads it again while serializing, and a
33
- * getter can return a different value, such as a new promise, on every read,
34
- * so the recorded promise fields may not match what Flight serializes.
35
- */
36
- var UnreplayableCacheArgumentsError = class extends Error {
37
- constructor() {
38
- super("Cache function arguments with getters cannot be replayed");
39
- }
40
- };
41
- /**
42
- * The own entries of `value` that Flight serializes: every index below an
43
- * array's `length`, including holes and non-enumerable indices, as
44
- * `JSON.stringify` reads them, and the enumerable own keys of anything else.
45
- * A getter, own or inherited through an array hole, is never run.
46
- */
47
- function ownEntries(value, getters) {
48
- const keys = Array.isArray(value) ? Array.from({ length: value.length }, (_, index) => String(index)) : Object.keys(value);
49
- const entries = [];
50
- for (const key of keys) {
51
- if (readsGetter(value, key)) {
52
- if (getters === "reject") throw new UnreplayableCacheArgumentsError();
53
- continue;
54
- }
55
- entries.push([key, Reflect.get(value, key)]);
56
- }
57
- return entries;
58
- }
59
- /**
60
- * Whether reading `key` from `value` runs a getter. An array hole reads
61
- * through the prototype chain, which can hold an indexed data property or
62
- * accessor. A setter-only accessor reads as `undefined` without running code.
63
- */
64
- function readsGetter(value, key) {
65
- for (let target = value; target !== null; target = Reflect.getPrototypeOf(target)) {
66
- const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
67
- if (descriptor) return typeof descriptor.get === "function";
68
- }
69
- return false;
70
- }
71
- /** Members of the values Flight serializes recursively, which can hold params. */
72
- function flightMembers(value, getters) {
73
- if (value instanceof Map) return [...value].flat();
74
- if (value instanceof Set) return [...value];
75
- if (isThenableObject(value) || Array.isArray(value) || isPlainRecord(value)) return ownEntries(value, getters).map(([, member]) => member);
76
- return [];
7
+ async function encryptArguments(value) {
8
+ return encryptActionBoundArgs(JSON.stringify(value));
9
+ }
10
+ async function decryptArguments(encrypted) {
11
+ const serialized = await decryptActionBoundArgs(Promise.resolve(encrypted));
12
+ if (typeof serialized !== "string") throw new Error("Invalid cache function arguments");
13
+ const value = JSON.parse(serialized);
14
+ if (value?.version !== 1) throw new Error("Invalid cache function arguments");
15
+ return value;
77
16
  }
78
- /**
79
- * Collect the own fields of every promise-augmented object in the arguments,
80
- * including ones inside resolved promise values. The arguments are passed to
81
- * Flight as they are, so Flight keeps their shared references and cycles.
82
- * With `getters: "reject"`, throws `UnreplayableCacheArgumentsError` when the
83
- * arguments hold a getter; with `"skip"`, promise fields behind a getter are
84
- * not recorded.
85
- */
86
- async function encodeCacheArguments(args, getters = "reject") {
87
- const settled = /* @__PURE__ */ new Map();
88
- for (;;) {
89
- const thenableObjects = [];
90
- const unsettled = [];
91
- const visited = /* @__PURE__ */ new Set();
92
- const pending = [args];
93
- while (pending.length > 0) {
94
- const value = pending.pop();
95
- if (typeof value !== "object" || value === null || visited.has(value)) continue;
96
- visited.add(value);
97
- const children = flightMembers(value, getters);
98
- if (isThenableObject(value)) {
99
- const fields = Object.fromEntries(ownEntries(value, getters));
100
- thenableObjects.push({
101
- fields,
102
- promise: value
103
- });
17
+ function encryptCacheCaptures(referenceId, captures) {
18
+ return memoizedCaptureEnvelope(referenceId, ...captures);
19
+ }
20
+ const memoizedCaptureEnvelope = memoizeInCacheScope((referenceId, ...captures) => ({
21
+ type: CACHE_CAPTURE_TYPE,
22
+ encrypted: encryptCaptures(referenceId, captures)
23
+ }));
24
+ async function encryptCaptures(referenceId, captures) {
25
+ const files = new FormData();
26
+ let nextFileId = 0;
27
+ const temporaryReferences = new class extends WeakMap {
28
+ get(value) {
29
+ let id = super.get(value);
30
+ if (id === void 0 && value instanceof File) {
31
+ id = String(nextFileId++);
32
+ super.set(value, id);
33
+ files.append(id, value);
104
34
  }
105
- if (isThenable(value)) {
106
- const result = settled.get(value);
107
- if (!result) unsettled.push(value);
108
- else if (result.status === "fulfilled") children.push(result.value);
109
- }
110
- for (const child of children) pending.push(child);
35
+ return id;
111
36
  }
112
- if (unsettled.length === 0) return {
113
- args,
114
- thenableObjects
115
- };
116
- const results = await Promise.allSettled(unsettled);
117
- unsettled.forEach((thenable, index) => settled.set(thenable, results[index]));
118
- }
119
- }
120
- /** Restore the promise fields that `encodeCacheArguments` captured before Flight encoding. */
121
- function decodeCacheArguments(value) {
122
- if (typeof value !== "object" || value === null || !("args" in value) || !Array.isArray(value.args) || !("thenableObjects" in value) || !Array.isArray(value.thenableObjects)) throw new Error("Invalid cache function arguments");
123
- adoptFlightThenables(value);
124
- for (const thenableObject of value.thenableObjects) {
125
- if (!isEncodedThenableObject(thenableObject)) throw new Error("Invalid cache function arguments");
126
- Object.assign(thenableObject.promise, thenableObject.fields);
127
- }
128
- return value.args;
129
- }
130
- function isEncodedThenableObject(value) {
131
- if (typeof value !== "object" || value === null || !isPlainRecord(value)) return false;
132
- const { fields, promise } = value;
133
- return typeof fields === "object" && fields !== null && isPlainRecord(fields) && promise instanceof Promise;
134
- }
135
- /**
136
- * Flight decodes promises as React chunks whose own fields are React's
137
- * internal state. Adopt them into native promises, which have no own fields,
138
- * so key serialization sees a promise exactly as the original call did.
139
- * Flight shares one chunk between references to the same promise, so each
140
- * chunk is adopted once, including references inside resolved values.
141
- */
142
- function adoptFlightThenables(value, adopted = /* @__PURE__ */ new WeakMap()) {
143
- if (typeof value !== "object" || value === null) return value;
144
- if (adopted.has(value)) return adopted.get(value);
145
- if (isThenable(value)) {
146
- const promise = Promise.resolve(value).then((resolved) => adoptFlightThenables(resolved, adopted));
147
- promise.catch(() => {});
148
- adopted.set(value, promise);
149
- return promise;
150
- }
151
- if (value instanceof Map) {
152
- adopted.set(value, value);
153
- const entries = [...value];
154
- value.clear();
155
- for (const [key, item] of entries) value.set(adoptFlightThenables(key, adopted), adoptFlightThenables(item, adopted));
156
- return value;
157
- }
158
- if (value instanceof Set) {
159
- adopted.set(value, value);
160
- const items = [...value];
161
- value.clear();
162
- for (const item of items) value.add(adoptFlightThenables(item, adopted));
163
- return value;
164
- }
165
- if (!Array.isArray(value) && !isPlainRecord(value)) return value;
166
- adopted.set(value, value);
167
- for (const key of Object.keys(value)) Reflect.set(value, key, adoptFlightThenables(Reflect.get(value, key), adopted));
168
- return value;
169
- }
170
- function isCacheCaptureEnvelope(value) {
171
- if (typeof value !== "object" || value === null) return false;
172
- if (!("type" in value) || value.type !== CACHE_CAPTURE_TYPE || !("encrypted" in value)) return false;
37
+ }();
38
+ const stream = renderToReadableStream(captures, { temporaryReferences });
39
+ const bytes = await new Response(stream).arrayBuffer();
40
+ return encryptActionBoundArgs(JSON.stringify({
41
+ version: 1,
42
+ referenceId,
43
+ result: Buffer.from(bytes).toString("base64"),
44
+ files: await snapshotFlightReply(files)
45
+ }));
46
+ }
47
+ async function decryptCacheCaptures(value, referenceId, captureCount) {
48
+ if (typeof value !== "object" || value === null || !("type" in value) || value.type !== CACHE_CAPTURE_TYPE || !("encrypted" in value)) throw new Error("Invalid cache capture arguments");
173
49
  const encrypted = value.encrypted;
174
- return typeof encrypted === "string" || typeof encrypted === "object" && encrypted !== null && isThenable(encrypted);
175
- }
176
- function registerCachedFunction(fn, id, variant, options) {
50
+ if (typeof encrypted !== "string" && !(typeof encrypted === "object" && encrypted !== null && "then" in encrypted && typeof encrypted.then === "function")) throw new Error("Invalid cache capture arguments");
51
+ const serialized = await decryptActionBoundArgs(Promise.resolve(encrypted));
52
+ if (typeof serialized !== "string") throw new Error("Invalid cache capture arguments");
53
+ const payload = JSON.parse(serialized);
54
+ if (payload.version !== 1 || payload.referenceId !== referenceId) throw new Error("Invalid cache capture arguments");
55
+ const files = restoreFlightReply(payload.files);
56
+ if (typeof files === "string") throw new Error("Invalid cache capture files");
57
+ const captures = await createFromReadableStream(new Response(Buffer.from(payload.result, "base64")).body, { temporaryReferences: new Map([...files].map(([id, file]) => [`$${id}`, file])) }, { preserveServerReferences: true });
58
+ if (!Array.isArray(captures) || captures.length !== captureCount) throw new Error("Invalid cache capture arguments");
59
+ return captures;
60
+ }
61
+ function registerCachedFunction(fn, id, variant, { captureCount, ...options }) {
62
+ let decryptCaptures;
63
+ if (captureCount !== void 0) {
64
+ const referenceId = options.serverReferenceId;
65
+ if (referenceId === void 0) throw new Error(`Cache function ${id} has captures but no server reference`);
66
+ decryptCaptures = (value) => decryptCacheCaptures(value, referenceId, captureCount);
67
+ }
177
68
  return registerCachedFunction$1(fn, id, variant, {
178
69
  ...options,
179
- decryptCaptures: decryptCacheCaptures,
180
- encodeInvocationArgs: encryptCacheArguments
70
+ ...decryptCaptures ? { decryptCaptures } : {},
71
+ encodeInvocation: encryptArguments
181
72
  });
182
73
  }
183
- /** Load and invoke one transformed cache function through its server-reference identity. */
74
+ /** Replay the persisted payload without re-reading or re-encoding caller objects. */
184
75
  async function invokeCacheFunction(invocation, loadServerAction) {
185
76
  const fn = await loadServerAction(invocation.referenceId);
186
77
  if (!isUseCacheFunction(fn)) throw new Error(`Server reference ${invocation.referenceId} is not a cache function`);
187
- await fn(...await decryptCacheArguments(invocation.encryptedArgs));
78
+ await replayCachedFunction(fn, await decryptArguments(invocation.encryptedArgs));
188
79
  }
189
80
  //#endregion
190
- export { decodeCacheArguments, encodeCacheArguments, encryptCacheCaptures, invokeCacheFunction, registerCachedFunction };
81
+ export { encryptCacheCaptures, invokeCacheFunction, registerCachedFunction };
@@ -0,0 +1,22 @@
1
+ //#region src/shims/cache-flight-arguments.d.ts
2
+ /** The persisted argument transport. React owns the object graph and wire protocol. */
3
+ export type CacheFlightArguments = {
4
+ version: 1;
5
+ reply: string | ([string, string] | [string, string, string, number, string])[];
6
+ pagePropsIndex?: number;
7
+ layoutPropsIndex?: number;
8
+ };
9
+ /** Snapshot only the multipart transport, never traverse user arguments. */
10
+ export declare function snapshotFlightReply(reply: string | FormData, pagePropsIndex?: number): Promise<CacheFlightArguments>;
11
+ export declare function restoreFlightReply(args: CacheFlightArguments): string | FormData;
12
+ /**
13
+ * Like Next.js (use-cache-wrapper.ts, `encodeFormData`), a binary entry is keyed
14
+ * by its bytes alone. Its name, type, and timestamp are replayed but not keyed:
15
+ * native FormData gives each Blob wrapper a wall-clock timestamp.
16
+ *
17
+ * Hashed synchronously, as Next.js derives its key without leaving the task: a
18
+ * cache hit must resolve before React flushes the shell, and an async digest
19
+ * waits for a later event-loop turn.
20
+ */
21
+ export declare function flightArgumentsKey(args: CacheFlightArguments): string;
22
+ //#endregion
@@ -0,0 +1,56 @@
1
+ import { createHash } from "node:crypto";
2
+ //#region src/shims/cache-flight-arguments.ts
3
+ const blobType = Object.getOwnPropertyDescriptor(Blob.prototype, "type").get;
4
+ const fileName = Object.getOwnPropertyDescriptor(File.prototype, "name").get;
5
+ const fileTime = Object.getOwnPropertyDescriptor(File.prototype, "lastModified").get;
6
+ /** Snapshot only the multipart transport, never traverse user arguments. */
7
+ async function snapshotFlightReply(reply, pagePropsIndex) {
8
+ if (typeof reply === "string") return {
9
+ version: 1,
10
+ reply,
11
+ pagePropsIndex
12
+ };
13
+ const entries = [];
14
+ for (const [name, value] of reply) entries.push(typeof value === "string" ? [name, value] : [
15
+ name,
16
+ Buffer.from(await Blob.prototype.arrayBuffer.call(value)).toString("base64"),
17
+ fileName.call(value),
18
+ fileTime.call(value),
19
+ blobType.call(value)
20
+ ]);
21
+ return {
22
+ version: 1,
23
+ reply: entries,
24
+ pagePropsIndex
25
+ };
26
+ }
27
+ function restoreFlightReply(args) {
28
+ if (typeof args.reply === "string") return args.reply;
29
+ const reply = new FormData();
30
+ for (const entry of args.reply) {
31
+ const [name, data] = entry;
32
+ reply.append(name, entry.length === 2 ? data : new File([Buffer.from(data, "base64")], entry[2], {
33
+ lastModified: entry[3],
34
+ type: entry[4]
35
+ }));
36
+ }
37
+ return reply;
38
+ }
39
+ /**
40
+ * Like Next.js (use-cache-wrapper.ts, `encodeFormData`), a binary entry is keyed
41
+ * by its bytes alone. Its name, type, and timestamp are replayed but not keyed:
42
+ * native FormData gives each Blob wrapper a wall-clock timestamp.
43
+ *
44
+ * Hashed synchronously, as Next.js derives its key without leaving the task: a
45
+ * cache hit must resolve before React flushes the shell, and an async digest
46
+ * waits for a later event-loop turn.
47
+ */
48
+ function flightArgumentsKey(args) {
49
+ const reply = typeof args.reply === "string" ? args.reply : args.reply.map((entry) => entry.length === 2 ? entry : [entry[0], { bytes: entry[1] }]);
50
+ return createHash("sha256").update(JSON.stringify({
51
+ ...args,
52
+ reply
53
+ })).digest("base64url");
54
+ }
55
+ //#endregion
56
+ export { flightArgumentsKey, restoreFlightReply, snapshotFlightReply };
@@ -8,7 +8,6 @@ var NoOpCacheHandler = class {
8
8
  async revalidateTag(_tags, _durations) {}
9
9
  };
10
10
  const DEFAULT_MEMORY_CACHE_MAX_SIZE = 52428800;
11
- const MAX_REVALIDATED_TAG_ENTRIES = 1e4;
12
11
  function estimateStringMapSize(map) {
13
12
  if (!map) return 0;
14
13
  let size = 0;
@@ -151,14 +150,7 @@ var MemoryCacheHandler = class {
151
150
  async revalidateTag(tags) {
152
151
  const tagList = Array.isArray(tags) ? tags : [tags];
153
152
  const now = Date.now();
154
- for (const tag of tagList) {
155
- this.tagRevalidatedAt.set(tag, now);
156
- while (this.tagRevalidatedAt.size > MAX_REVALIDATED_TAG_ENTRIES) {
157
- const oldest = this.tagRevalidatedAt.keys().next().value;
158
- if (oldest === void 0) break;
159
- this.tagRevalidatedAt.delete(oldest);
160
- }
161
- }
153
+ for (const tag of tagList) this.tagRevalidatedAt.set(tag, now);
162
154
  }
163
155
  resetRequestCache() {}
164
156
  };
@@ -15,8 +15,17 @@ export type UnstableCacheObservation = Readonly<{
15
15
  tagCount: number;
16
16
  tagHash: string | null;
17
17
  }>;
18
+ /**
19
+ * Collects the cacheLife claims made anywhere below the scope that installed
20
+ * it, including nested scopes that reset `requestScopedCacheLife`. Shallow
21
+ * scope clones share it by reference.
22
+ */
23
+ export type CacheLifeSink = {
24
+ cacheLife: CacheLifeConfig | null;
25
+ };
18
26
  export type CacheState = {
19
27
  actionRevalidationKind: ActionRevalidationKind;
28
+ cacheLifeSink: CacheLifeSink | null;
20
29
  pendingRevalidatedTags: Set<string>;
21
30
  pendingRevalidations: Set<Promise<void>>;
22
31
  requestScopedCacheLife: CacheLifeConfig | null;
@@ -70,6 +79,12 @@ export declare function _captureRequestScopedCacheLifeAccessors(): {
70
79
  };
71
80
  export declare function recordUnstableCacheObservation(observation: UnstableCacheObservation): void;
72
81
  export declare function _peekUnstableCacheObservations(): UnstableCacheObservation[];
82
+ /**
83
+ * Run `fn` with the request's cache settings, including its revalidation mode,
84
+ * but its own record of cache lives and unstable_cache observations, so work
85
+ * done on the request's behalf after the fact leaves the request untouched.
86
+ */
87
+ export declare function runWithDetachedCacheObservations<T>(fn: () => Promise<T>): Promise<T>;
73
88
  export declare function shouldServeStaleUnstableCacheEntry(): boolean;
74
89
  //#endregion
75
90
  export { _recordUseCacheRootParamRead, _registerCacheContextAccessor, getRegisteredCacheContext };
@@ -47,6 +47,7 @@ const ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC = 1;
47
47
  const ACTION_DID_REVALIDATE_DYNAMIC_ONLY = 2;
48
48
  const fallbackState = globalState[FALLBACK_KEY] ??= {
49
49
  actionRevalidationKind: ACTION_DID_NOT_REVALIDATE,
50
+ cacheLifeSink: null,
50
51
  pendingRevalidatedTags: /* @__PURE__ */ new Set(),
51
52
  pendingRevalidations: /* @__PURE__ */ new Set(),
52
53
  requestScopedCacheLife: null,
@@ -60,12 +61,14 @@ function getCacheState() {
60
61
  function _runWithCacheState(fn) {
61
62
  if (isInsideUnifiedScope()) return runWithUnifiedStateMutation((context) => {
62
63
  context.actionRevalidationKind = ACTION_DID_NOT_REVALIDATE;
64
+ context.cacheLifeSink = null;
63
65
  context.requestScopedCacheLife = null;
64
66
  context.unstableCacheObservations = /* @__PURE__ */ new Map();
65
67
  context.unstableCacheRevalidation = "foreground";
66
68
  }, fn);
67
69
  const state = {
68
70
  actionRevalidationKind: ACTION_DID_NOT_REVALIDATE,
71
+ cacheLifeSink: null,
69
72
  pendingRevalidatedTags: /* @__PURE__ */ new Set(),
70
73
  pendingRevalidations: /* @__PURE__ */ new Set(),
71
74
  requestScopedCacheLife: null,
@@ -146,15 +149,17 @@ async function _drainPendingRevalidations() {
146
149
  }
147
150
  if (didReject) throw firstRejection;
148
151
  }
152
+ function mergeCacheLife(current, config) {
153
+ if (current === null) return { ...config };
154
+ if (config.stale !== void 0) current.stale = current.stale !== void 0 ? Math.min(current.stale, config.stale) : config.stale;
155
+ if (config.revalidate !== void 0) current.revalidate = current.revalidate !== void 0 ? Math.min(current.revalidate, config.revalidate) : config.revalidate;
156
+ if (config.expire !== void 0) current.expire = current.expire !== void 0 ? Math.min(current.expire, config.expire) : config.expire;
157
+ return current;
158
+ }
149
159
  function _setRequestScopedCacheLife(config) {
150
160
  const state = getCacheState();
151
- if (state.requestScopedCacheLife === null) {
152
- state.requestScopedCacheLife = { ...config };
153
- return;
154
- }
155
- if (config.stale !== void 0) state.requestScopedCacheLife.stale = state.requestScopedCacheLife.stale !== void 0 ? Math.min(state.requestScopedCacheLife.stale, config.stale) : config.stale;
156
- if (config.revalidate !== void 0) state.requestScopedCacheLife.revalidate = state.requestScopedCacheLife.revalidate !== void 0 ? Math.min(state.requestScopedCacheLife.revalidate, config.revalidate) : config.revalidate;
157
- if (config.expire !== void 0) state.requestScopedCacheLife.expire = state.requestScopedCacheLife.expire !== void 0 ? Math.min(state.requestScopedCacheLife.expire, config.expire) : config.expire;
161
+ state.requestScopedCacheLife = mergeCacheLife(state.requestScopedCacheLife, config);
162
+ if (state.cacheLifeSink) state.cacheLifeSink.cacheLife = mergeCacheLife(state.cacheLifeSink.cacheLife, config);
158
163
  }
159
164
  function _peekRequestScopedCacheLife() {
160
165
  const config = getCacheState().requestScopedCacheLife;
@@ -193,8 +198,26 @@ function recordUnstableCacheObservation(observation) {
193
198
  function _peekUnstableCacheObservations() {
194
199
  return [...getCacheState().unstableCacheObservations.values()].sort((a, b) => a.keyHash.localeCompare(b.keyHash));
195
200
  }
201
+ /**
202
+ * Run `fn` with the request's cache settings, including its revalidation mode,
203
+ * but its own record of cache lives and unstable_cache observations, so work
204
+ * done on the request's behalf after the fact leaves the request untouched.
205
+ */
206
+ function runWithDetachedCacheObservations(fn) {
207
+ if (isInsideUnifiedScope()) return runWithUnifiedStateMutation((context) => {
208
+ context.cacheLifeSink = null;
209
+ context.requestScopedCacheLife = null;
210
+ context.unstableCacheObservations = /* @__PURE__ */ new Map();
211
+ }, fn);
212
+ return cacheAls.run({
213
+ ...getCacheState(),
214
+ cacheLifeSink: null,
215
+ requestScopedCacheLife: null,
216
+ unstableCacheObservations: /* @__PURE__ */ new Map()
217
+ }, fn);
218
+ }
196
219
  function shouldServeStaleUnstableCacheEntry() {
197
220
  return getCacheState().unstableCacheRevalidation === "background";
198
221
  }
199
222
  //#endregion
200
- export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry };
223
+ export { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _captureRequestScopedCacheLifeAccessors, _consumeRequestScopedCacheLife, _drainPendingRevalidations, _hasPendingRevalidatedTag, _initRequestScopedCacheState, _markPendingRevalidatedTag, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _queuePendingRevalidation, _recordUseCacheRootParamRead, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, runWithDetachedCacheObservations, shouldServeStaleUnstableCacheEntry };