@timber-js/app 0.2.0-alpha.208 → 0.2.0-alpha.209

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 (520) hide show
  1. package/dist/_chunks/{primitives-DLAnvsrk.js → actions-BerlqoXA.js} +640 -410
  2. package/dist/_chunks/actions-BerlqoXA.js.map +1 -0
  3. package/dist/_chunks/{als-registry-C6kcfprT.js → als-registry-DaxkVjt5.js} +6 -2
  4. package/dist/_chunks/als-registry-DaxkVjt5.js.map +1 -0
  5. package/dist/_chunks/{build-manifest-DTmSGLRz.js → build-manifest-DWppEdLB.js} +2 -51
  6. package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
  7. package/dist/_chunks/{build-output-helper-9dqCv1pZ.js → build-output-helper-RV_BRcF1.js} +50 -53
  8. package/dist/_chunks/build-output-helper-RV_BRcF1.js.map +1 -0
  9. package/dist/_chunks/{cache-api-CUD9Ezaq.js → cache-api-CR23J_NC.js} +64 -32
  10. package/dist/_chunks/cache-api-CR23J_NC.js.map +1 -0
  11. package/dist/_chunks/{chains-B4bgOl2g.js → chains-CpFg56UB.js} +2 -2
  12. package/dist/_chunks/{chains-B4bgOl2g.js.map → chains-CpFg56UB.js.map} +1 -1
  13. package/dist/_chunks/{cli-check-G8o30ldg.js → cli-check-C6Ev6wBO.js} +11 -52
  14. package/dist/_chunks/cli-check-C6Ev6wBO.js.map +1 -0
  15. package/dist/_chunks/cli-context-By7k2xVo.js +70 -0
  16. package/dist/_chunks/cli-context-By7k2xVo.js.map +1 -0
  17. package/dist/_chunks/{cli-schema-sync--LZKs8Zn.js → cli-schema-sync-CbT2AUUI.js} +3 -3
  18. package/dist/_chunks/{cli-schema-sync--LZKs8Zn.js.map → cli-schema-sync-CbT2AUUI.js.map} +1 -1
  19. package/dist/_chunks/{cloudflare-BFb__LYG.js → cloudflare-Byxl8FWP.js} +96 -53
  20. package/dist/_chunks/{cloudflare-BFb__LYG.js.map → cloudflare-Byxl8FWP.js.map} +1 -1
  21. package/dist/_chunks/{convention-lint-5KzoMg_A.js → convention-lint-jKTwKwPe.js} +21 -6
  22. package/dist/_chunks/convention-lint-jKTwKwPe.js.map +1 -0
  23. package/dist/_chunks/{dev-server-BzBxgYAV.js → dev-server-C4WZdB7L.js} +15 -167
  24. package/dist/_chunks/dev-server-C4WZdB7L.js.map +1 -0
  25. package/dist/_chunks/{error-boundary-BrHmG-2X.js → error-boundary-tA7kVfs4.js} +84 -104
  26. package/dist/_chunks/error-boundary-tA7kVfs4.js.map +1 -0
  27. package/dist/_chunks/{fs-identity-D7vb6GdI.js → fs-identity-BRKuL215.js} +3 -4
  28. package/dist/_chunks/fs-identity-BRKuL215.js.map +1 -0
  29. package/dist/_chunks/{graph-cache-CP4GEmf9.js → graph-cache-CYiUS2aS.js} +4 -5
  30. package/dist/_chunks/graph-cache-CYiUS2aS.js.map +1 -0
  31. package/dist/_chunks/{json-lossy-check-ClNvBM_3.js → json-lossy-check-ip0Qi0MT.js} +6 -3
  32. package/dist/_chunks/json-lossy-check-ip0Qi0MT.js.map +1 -0
  33. package/dist/_chunks/{live-graph-Bm5WTvcr.js → live-graph-Dv-JJCZw.js} +3 -3
  34. package/dist/_chunks/{live-graph-Bm5WTvcr.js.map → live-graph-Dv-JJCZw.js.map} +1 -1
  35. package/dist/_chunks/{logger-k2DQ4EUf.js → logger-DiDt5ppH.js} +192 -51
  36. package/dist/_chunks/logger-DiDt5ppH.js.map +1 -0
  37. package/dist/_chunks/{navigation-root-mHSK9psY.js → navigation-root-BQfo1-kG.js} +2 -2
  38. package/dist/_chunks/{navigation-root-mHSK9psY.js.map → navigation-root-BQfo1-kG.js.map} +1 -1
  39. package/dist/_chunks/{plugin-context-8idfR3UZ.js → plugin-context-BPBPc3lL.js} +28 -4
  40. package/dist/_chunks/plugin-context-BPBPc3lL.js.map +1 -0
  41. package/dist/_chunks/{poison-scan-DG5eI2_z.js → poison-scan-CpeT6_OJ.js} +2 -2
  42. package/dist/_chunks/{poison-scan-DG5eI2_z.js.map → poison-scan-CpeT6_OJ.js.map} +1 -1
  43. package/dist/_chunks/render-timeout-DOf_BBcO.js +46 -0
  44. package/dist/_chunks/render-timeout-DOf_BBcO.js.map +1 -0
  45. package/dist/_chunks/{rsc-payload-path-B_LBodc2.js → rsc-payload-path-dffcs4jp.js} +9 -3
  46. package/dist/_chunks/{rsc-payload-path-B_LBodc2.js.map → rsc-payload-path-dffcs4jp.js.map} +1 -1
  47. package/dist/_chunks/{scanner-BQ5sPIJ7.js → scanner-Bw0oq1HB.js} +2 -2
  48. package/dist/_chunks/{scanner-BQ5sPIJ7.js.map → scanner-Bw0oq1HB.js.map} +1 -1
  49. package/dist/_chunks/{navigation-context-D0TU0Jog.js → segment-context-xtPUGfdq.js} +36 -34
  50. package/dist/_chunks/segment-context-xtPUGfdq.js.map +1 -0
  51. package/dist/_chunks/{singleflight-2lUWfcAk.js → singleflight-BeVMMKi0.js} +4 -3
  52. package/dist/_chunks/{singleflight-2lUWfcAk.js.map → singleflight-BeVMMKi0.js.map} +1 -1
  53. package/dist/_chunks/{sizeof-lXffQ1Vr.js → sizeof-UwzwB1uM.js} +3 -2
  54. package/dist/_chunks/sizeof-UwzwB1uM.js.map +1 -0
  55. package/dist/_chunks/ssr-data-nA3I70_n.js +49 -0
  56. package/dist/_chunks/ssr-data-nA3I70_n.js.map +1 -0
  57. package/dist/_chunks/{state-FippDgxN.js → state-BhNGPsdi.js} +6 -8
  58. package/dist/_chunks/state-BhNGPsdi.js.map +1 -0
  59. package/dist/_chunks/{status-page-marker-CNbpUOPB.js → status-page-marker-gaihi0KZ.js} +53 -20
  60. package/dist/_chunks/status-page-marker-gaihi0KZ.js.map +1 -0
  61. package/dist/_chunks/{walkers-CN2N_bA-.js → walkers-BXExhzzk.js} +2 -2
  62. package/dist/_chunks/{walkers-CN2N_bA-.js.map → walkers-BXExhzzk.js.map} +1 -1
  63. package/dist/_chunks/write-file-atomic-D1qWqHb4.js +32 -0
  64. package/dist/_chunks/write-file-atomic-D1qWqHb4.js.map +1 -0
  65. package/dist/adapters/build-output-helper.d.ts +7 -7
  66. package/dist/adapters/build-output-helper.d.ts.map +1 -1
  67. package/dist/adapters/canonicalize-module.d.ts +8 -0
  68. package/dist/adapters/canonicalize-module.d.ts.map +1 -0
  69. package/dist/adapters/cloudflare-dev.js +1 -1
  70. package/dist/adapters/cloudflare-kv-cache.js +2 -2
  71. package/dist/adapters/cloudflare.d.ts +30 -8
  72. package/dist/adapters/cloudflare.d.ts.map +1 -1
  73. package/dist/adapters/cloudflare.js +2 -2
  74. package/dist/adapters/compress-module.d.ts +8 -0
  75. package/dist/adapters/compress-module.d.ts.map +1 -1
  76. package/dist/adapters/fs-identity.d.ts +2 -3
  77. package/dist/adapters/fs-identity.d.ts.map +1 -1
  78. package/dist/adapters/nitro-presets.d.ts +0 -6
  79. package/dist/adapters/nitro-presets.d.ts.map +1 -1
  80. package/dist/adapters/nitro-preview.d.ts +43 -11
  81. package/dist/adapters/nitro-preview.d.ts.map +1 -1
  82. package/dist/adapters/nitro.d.ts +1 -13
  83. package/dist/adapters/nitro.d.ts.map +1 -1
  84. package/dist/adapters/nitro.js +291 -176
  85. package/dist/adapters/nitro.js.map +1 -1
  86. package/dist/adapters/shared.d.ts +7 -2
  87. package/dist/adapters/shared.d.ts.map +1 -1
  88. package/dist/adapters/types.d.ts +105 -21
  89. package/dist/adapters/types.d.ts.map +1 -1
  90. package/dist/adapters/types.js +0 -0
  91. package/dist/analyze/crawl-entry.js +3 -3
  92. package/dist/analyze/graph-cache.d.ts.map +1 -1
  93. package/dist/analyze/graph-command.js +4 -4
  94. package/dist/cache/index.js +2 -2
  95. package/dist/cache/json-lossy-check.d.ts.map +1 -1
  96. package/dist/cache/singleflight.d.ts.map +1 -1
  97. package/dist/cache/sizeof.d.ts.map +1 -1
  98. package/dist/cache/stores/memory.js +1 -1
  99. package/dist/cache/tag-aware-handler.d.ts.map +1 -1
  100. package/dist/cdn/workers-cache-purge.js +1 -1
  101. package/dist/cli-check.d.ts +7 -37
  102. package/dist/cli-check.d.ts.map +1 -1
  103. package/dist/cli-context.d.ts +54 -0
  104. package/dist/cli-context.d.ts.map +1 -0
  105. package/dist/cli.d.ts +9 -9
  106. package/dist/cli.d.ts.map +1 -1
  107. package/dist/cli.js +20 -24
  108. package/dist/cli.js.map +1 -1
  109. package/dist/client/browser-dev.d.ts +1 -1
  110. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
  111. package/dist/client/browser-entry/hydrate.d.ts +19 -29
  112. package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
  113. package/dist/client/browser-entry/index.d.ts +7 -7
  114. package/dist/client/browser-entry/post-hydration.d.ts +6 -9
  115. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
  116. package/dist/client/browser-entry/router-init.d.ts +6 -11
  117. package/dist/client/browser-entry/router-init.d.ts.map +1 -1
  118. package/dist/client/error-boundary.d.ts +4 -3
  119. package/dist/client/error-boundary.d.ts.map +1 -1
  120. package/dist/client/error-boundary.js +1 -1
  121. package/dist/client/error-reconstituter.d.ts +3 -9
  122. package/dist/client/error-reconstituter.d.ts.map +1 -1
  123. package/dist/client/history.d.ts +12 -11
  124. package/dist/client/history.d.ts.map +1 -1
  125. package/dist/client/index.d.ts +0 -1
  126. package/dist/client/index.d.ts.map +1 -1
  127. package/dist/client/index.js +5 -6
  128. package/dist/client/index.js.map +1 -1
  129. package/dist/client/internal.d.ts +3 -3
  130. package/dist/client/internal.d.ts.map +1 -1
  131. package/dist/client/internal.js +68 -104
  132. package/dist/client/internal.js.map +1 -1
  133. package/dist/client/navigation-commit.d.ts +16 -7
  134. package/dist/client/navigation-commit.d.ts.map +1 -1
  135. package/dist/client/navigation-context.d.ts +3 -5
  136. package/dist/client/navigation-context.d.ts.map +1 -1
  137. package/dist/client/react-root.d.ts +3 -2
  138. package/dist/client/react-root.d.ts.map +1 -1
  139. package/dist/client/router-pipeline.d.ts +1 -6
  140. package/dist/client/router-pipeline.d.ts.map +1 -1
  141. package/dist/client/router-types.d.ts +45 -39
  142. package/dist/client/router-types.d.ts.map +1 -1
  143. package/dist/client/router-url.d.ts +24 -0
  144. package/dist/client/router-url.d.ts.map +1 -0
  145. package/dist/client/router.d.ts.map +1 -1
  146. package/dist/client/rsc-fetch.d.ts +8 -4
  147. package/dist/client/rsc-fetch.d.ts.map +1 -1
  148. package/dist/client/ssr-data.d.ts +18 -64
  149. package/dist/client/ssr-data.d.ts.map +1 -1
  150. package/dist/client/state.d.ts +2 -5
  151. package/dist/client/state.d.ts.map +1 -1
  152. package/dist/client/use-pathname.d.ts +1 -1
  153. package/dist/config-types.d.ts +2 -1
  154. package/dist/config-types.d.ts.map +1 -1
  155. package/dist/config-validation.d.ts.map +1 -1
  156. package/dist/cookies/index.js +1 -1
  157. package/dist/dev-tools/dev-page-shell.d.ts +17 -0
  158. package/dist/dev-tools/dev-page-shell.d.ts.map +1 -1
  159. package/dist/dev-tools/index.d.ts +1 -1
  160. package/dist/dev-tools/index.d.ts.map +1 -1
  161. package/dist/dev-tools/instrumentation.d.ts +17 -2
  162. package/dist/dev-tools/instrumentation.d.ts.map +1 -1
  163. package/dist/dev-tools/overlay.d.ts +6 -27
  164. package/dist/dev-tools/overlay.d.ts.map +1 -1
  165. package/dist/index.d.ts.map +1 -1
  166. package/dist/index.js +531 -373
  167. package/dist/index.js.map +1 -1
  168. package/dist/plugin-context.d.ts +26 -40
  169. package/dist/plugin-context.d.ts.map +1 -1
  170. package/dist/plugins/build-manifest.d.ts.map +1 -1
  171. package/dist/plugins/build-report.d.ts +15 -2
  172. package/dist/plugins/build-report.d.ts.map +1 -1
  173. package/dist/plugins/dev-server.d.ts.map +1 -1
  174. package/dist/plugins/entries.d.ts.map +1 -1
  175. package/dist/plugins/fonts.d.ts +19 -1
  176. package/dist/plugins/fonts.d.ts.map +1 -1
  177. package/dist/plugins/post-build.d.ts +110 -0
  178. package/dist/plugins/post-build.d.ts.map +1 -0
  179. package/dist/plugins/prebuilt-capture.d.ts +11 -4
  180. package/dist/plugins/prebuilt-capture.d.ts.map +1 -1
  181. package/dist/plugins/prebuilt.d.ts +17 -1
  182. package/dist/plugins/prebuilt.d.ts.map +1 -1
  183. package/dist/plugins/prerender-sugar.d.ts.map +1 -1
  184. package/dist/plugins/rsc-assets-manifest.d.ts +33 -0
  185. package/dist/plugins/rsc-assets-manifest.d.ts.map +1 -0
  186. package/dist/plugins/shims.d.ts.map +1 -1
  187. package/dist/plugins/static-build.d.ts +32 -9
  188. package/dist/plugins/static-build.d.ts.map +1 -1
  189. package/dist/routing/codegen-write.d.ts +0 -9
  190. package/dist/routing/codegen-write.d.ts.map +1 -1
  191. package/dist/routing/index.js +2 -2
  192. package/dist/routing/segment-codegen.d.ts.map +1 -1
  193. package/dist/server/access-gate.d.ts.map +1 -1
  194. package/dist/server/action-handler.d.ts +5 -4
  195. package/dist/server/action-handler.d.ts.map +1 -1
  196. package/dist/server/actions.d.ts +46 -7
  197. package/dist/server/actions.d.ts.map +1 -1
  198. package/dist/server/als-registry.d.ts +58 -5
  199. package/dist/server/als-registry.d.ts.map +1 -1
  200. package/dist/server/children-interception.d.ts.map +1 -1
  201. package/dist/server/cookie-context.d.ts +2 -23
  202. package/dist/server/cookie-context.d.ts.map +1 -1
  203. package/dist/server/csp-nonce.d.ts +0 -9
  204. package/dist/server/csp-nonce.d.ts.map +1 -1
  205. package/dist/server/csrf.d.ts +27 -4
  206. package/dist/server/csrf.d.ts.map +1 -1
  207. package/dist/server/debug.d.ts +0 -1
  208. package/dist/server/debug.d.ts.map +1 -1
  209. package/dist/server/default-logger.d.ts +2 -1
  210. package/dist/server/default-logger.d.ts.map +1 -1
  211. package/dist/server/deny-boundary.d.ts +12 -6
  212. package/dist/server/deny-boundary.d.ts.map +1 -1
  213. package/dist/server/deny-renderer.d.ts +2 -2
  214. package/dist/server/deny-renderer.d.ts.map +1 -1
  215. package/dist/server/error-boundary-wrapper.d.ts +7 -3
  216. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  217. package/dist/server/fallback-error.d.ts +9 -2
  218. package/dist/server/fallback-error.d.ts.map +1 -1
  219. package/dist/server/head-response.d.ts +4 -4
  220. package/dist/server/html-injectors.d.ts.map +1 -1
  221. package/dist/server/index.d.ts +0 -1
  222. package/dist/server/index.d.ts.map +1 -1
  223. package/dist/server/index.js +3 -4
  224. package/dist/server/index.js.map +1 -1
  225. package/dist/server/instrumentation.d.ts +10 -3
  226. package/dist/server/instrumentation.d.ts.map +1 -1
  227. package/dist/server/internal.d.ts +1 -4
  228. package/dist/server/internal.d.ts.map +1 -1
  229. package/dist/server/internal.js +961 -581
  230. package/dist/server/internal.js.map +1 -1
  231. package/dist/server/json-status-response.d.ts +34 -0
  232. package/dist/server/json-status-response.d.ts.map +1 -0
  233. package/dist/server/logger.d.ts +26 -0
  234. package/dist/server/logger.d.ts.map +1 -1
  235. package/dist/server/param-coercion.d.ts +11 -6
  236. package/dist/server/param-coercion.d.ts.map +1 -1
  237. package/dist/server/pipeline-helpers.d.ts +95 -7
  238. package/dist/server/pipeline-helpers.d.ts.map +1 -1
  239. package/dist/server/pipeline-interception.d.ts +11 -0
  240. package/dist/server/pipeline-interception.d.ts.map +1 -1
  241. package/dist/server/pipeline-outcome.d.ts +11 -1
  242. package/dist/server/pipeline-outcome.d.ts.map +1 -1
  243. package/dist/server/pipeline-phases.d.ts +2 -2
  244. package/dist/server/pipeline-phases.d.ts.map +1 -1
  245. package/dist/server/pipeline.d.ts +23 -35
  246. package/dist/server/pipeline.d.ts.map +1 -1
  247. package/dist/server/prebuilt/capture-render.d.ts +25 -0
  248. package/dist/server/prebuilt/capture-render.d.ts.map +1 -0
  249. package/dist/server/prebuilt/capture-routes.d.ts +37 -0
  250. package/dist/server/prebuilt/capture-routes.d.ts.map +1 -0
  251. package/dist/server/prebuilt/capture-state.d.ts +79 -35
  252. package/dist/server/prebuilt/capture-state.d.ts.map +1 -1
  253. package/dist/server/prebuilt/lifetime.d.ts +38 -0
  254. package/dist/server/prebuilt/lifetime.d.ts.map +1 -0
  255. package/dist/server/prebuilt/slots.d.ts +7 -0
  256. package/dist/server/prebuilt/slots.d.ts.map +1 -1
  257. package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -1
  258. package/dist/server/prebuilt-builder.d.ts.map +1 -1
  259. package/dist/server/prebuilt-runtime.d.ts.map +1 -1
  260. package/dist/server/primitives.d.ts +6 -81
  261. package/dist/server/primitives.d.ts.map +1 -1
  262. package/dist/server/react-cache-bridge.d.ts +59 -0
  263. package/dist/server/react-cache-bridge.d.ts.map +1 -0
  264. package/dist/server/react-cache-scope.d.ts +49 -0
  265. package/dist/server/react-cache-scope.d.ts.map +1 -0
  266. package/dist/server/render-timeout.d.ts +15 -0
  267. package/dist/server/render-timeout.d.ts.map +1 -1
  268. package/dist/server/render-utils.d.ts +9 -0
  269. package/dist/server/render-utils.d.ts.map +1 -1
  270. package/dist/server/request-context.d.ts +26 -5
  271. package/dist/server/request-context.d.ts.map +1 -1
  272. package/dist/server/route-element-builder.d.ts.map +1 -1
  273. package/dist/server/route-handler.d.ts.map +1 -1
  274. package/dist/server/route-matcher.d.ts +7 -0
  275. package/dist/server/route-matcher.d.ts.map +1 -1
  276. package/dist/server/rsc-entry/action-middleware-runner.d.ts +22 -22
  277. package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -1
  278. package/dist/server/rsc-entry/api-handler.d.ts +7 -0
  279. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  280. package/dist/server/rsc-entry/deny-fallback.d.ts +32 -6
  281. package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
  282. package/dist/server/rsc-entry/error-renderer.d.ts +11 -18
  283. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  284. package/dist/server/rsc-entry/helpers.d.ts +0 -1
  285. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  286. package/dist/server/rsc-entry/index.d.ts +5 -15
  287. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  288. package/dist/server/rsc-entry/render-route.d.ts +5 -6
  289. package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
  290. package/dist/server/rsc-entry/render-signals.d.ts +65 -0
  291. package/dist/server/rsc-entry/render-signals.d.ts.map +1 -0
  292. package/dist/server/rsc-entry/revalidate-renderer.d.ts +6 -16
  293. package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
  294. package/dist/server/rsc-entry/rsc-payload.d.ts +7 -3
  295. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  296. package/dist/server/rsc-entry/rsc-stream.d.ts +8 -53
  297. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  298. package/dist/server/rsc-entry/ssr-bridge.d.ts +2 -2
  299. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  300. package/dist/server/rsc-entry/ssr-renderer.d.ts +9 -4
  301. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  302. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +1 -1
  303. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -1
  304. package/dist/server/signal-identity.d.ts +43 -0
  305. package/dist/server/signal-identity.d.ts.map +1 -0
  306. package/dist/server/slot-resolver.d.ts +4 -3
  307. package/dist/server/slot-resolver.d.ts.map +1 -1
  308. package/dist/server/slot-subtree-contain.d.ts.map +1 -1
  309. package/dist/server/ssr-bridge-types.d.ts +91 -53
  310. package/dist/server/ssr-bridge-types.d.ts.map +1 -1
  311. package/dist/server/ssr-entry.d.ts +8 -5
  312. package/dist/server/ssr-entry.d.ts.map +1 -1
  313. package/dist/server/ssr-render.d.ts +26 -40
  314. package/dist/server/ssr-render.d.ts.map +1 -1
  315. package/dist/server/ssr-wrappers.d.ts +1 -1
  316. package/dist/server/static-generator.d.ts.map +1 -1
  317. package/dist/server/stream-utils.d.ts +12 -0
  318. package/dist/server/stream-utils.d.ts.map +1 -1
  319. package/dist/server/tracing.d.ts +12 -16
  320. package/dist/server/tracing.d.ts.map +1 -1
  321. package/dist/server/types.d.ts +1 -1
  322. package/dist/server/version-skew.d.ts +3 -3
  323. package/dist/shared/csrf-reject.d.ts +16 -0
  324. package/dist/shared/csrf-reject.d.ts.map +1 -0
  325. package/dist/shared/error-digest.d.ts +28 -0
  326. package/dist/shared/error-digest.d.ts.map +1 -0
  327. package/dist/shared/payload-root.d.ts +11 -10
  328. package/dist/shared/payload-root.d.ts.map +1 -1
  329. package/dist/shared/rsc-payload-path.d.ts +6 -0
  330. package/dist/shared/rsc-payload-path.d.ts.map +1 -1
  331. package/dist/utils/write-file-atomic.d.ts +17 -0
  332. package/dist/utils/write-file-atomic.d.ts.map +1 -0
  333. package/docs/api/30-api-server.mdx +17 -14
  334. package/docs/api/32-api-cache.mdx +51 -23
  335. package/docs/api/34-api-config.mdx +34 -6
  336. package/docs/api/36-cli.mdx +11 -1
  337. package/docs/learn/03-fetching-data.mdx +17 -1
  338. package/docs/learn/04-access-control.mdx +1 -1
  339. package/docs/learn/10-caching.mdx +29 -11
  340. package/docs/learn/11-middleware.mdx +8 -2
  341. package/docs/learn/12-error-handling.mdx +6 -1
  342. package/package.json +5 -1
  343. package/src/adapters/build-output-helper.ts +55 -53
  344. package/src/adapters/canonicalize-module.ts +29 -0
  345. package/src/adapters/cloudflare.ts +105 -63
  346. package/src/adapters/compress-module.ts +16 -5
  347. package/src/adapters/fs-identity.ts +2 -3
  348. package/src/adapters/nitro-presets.ts +0 -15
  349. package/src/adapters/nitro-preview.ts +272 -136
  350. package/src/adapters/nitro.ts +119 -82
  351. package/src/adapters/shared.ts +23 -14
  352. package/src/adapters/types.ts +110 -21
  353. package/src/analyze/graph-cache.ts +3 -4
  354. package/src/cache/json-lossy-check.ts +3 -9
  355. package/src/cache/singleflight.ts +5 -2
  356. package/src/cache/sizeof.ts +3 -1
  357. package/src/cache/tag-aware-handler.ts +43 -26
  358. package/src/cli-check.ts +8 -98
  359. package/src/cli-context.ts +119 -0
  360. package/src/cli.ts +19 -28
  361. package/src/client/browser-dev.ts +1 -1
  362. package/src/client/browser-entry/action-dispatch.ts +26 -4
  363. package/src/client/browser-entry/hydrate.ts +53 -58
  364. package/src/client/browser-entry/index.ts +16 -27
  365. package/src/client/browser-entry/post-hydration.ts +6 -40
  366. package/src/client/browser-entry/router-init.ts +66 -84
  367. package/src/client/error-boundary.tsx +9 -41
  368. package/src/client/error-reconstituter.tsx +10 -5
  369. package/src/client/history.ts +18 -21
  370. package/src/client/index.ts +0 -1
  371. package/src/client/internal.ts +2 -7
  372. package/src/client/navigation-commit.ts +35 -18
  373. package/src/client/navigation-context.ts +3 -39
  374. package/src/client/react-root.ts +3 -2
  375. package/src/client/router-pipeline.ts +65 -128
  376. package/src/client/router-types.ts +46 -44
  377. package/src/client/router-url.ts +32 -0
  378. package/src/client/router.ts +43 -22
  379. package/src/client/rsc-fetch.ts +117 -155
  380. package/src/client/ssr-data.ts +19 -80
  381. package/src/client/state.ts +2 -9
  382. package/src/client/use-pathname.ts +1 -1
  383. package/src/config-types.ts +2 -1
  384. package/src/config-validation.ts +2 -1
  385. package/src/dev-tools/dev-page-shell.ts +18 -0
  386. package/src/dev-tools/index.ts +0 -2
  387. package/src/dev-tools/instrumentation.ts +50 -2
  388. package/src/dev-tools/overlay.ts +8 -238
  389. package/src/index.ts +24 -14
  390. package/src/plugin-context.ts +39 -40
  391. package/src/plugins/build-manifest.ts +4 -11
  392. package/src/plugins/build-report.ts +70 -70
  393. package/src/plugins/dev-server.ts +24 -44
  394. package/src/plugins/entries.ts +2 -1
  395. package/src/plugins/fonts.ts +35 -7
  396. package/src/plugins/post-build.ts +327 -0
  397. package/src/plugins/prebuilt-capture.ts +28 -32
  398. package/src/plugins/prebuilt.ts +54 -39
  399. package/src/plugins/prerender-sugar.ts +0 -4
  400. package/src/plugins/{adapter-build.ts → rsc-assets-manifest.ts} +20 -109
  401. package/src/plugins/shims.ts +1 -0
  402. package/src/plugins/static-build.ts +42 -74
  403. package/src/routing/codegen-write.ts +25 -3
  404. package/src/routing/segment-codegen.ts +3 -2
  405. package/src/rsc-runtime/vendor-types.d.ts +8 -0
  406. package/src/server/access-gate.tsx +2 -1
  407. package/src/server/action-client.ts +1 -1
  408. package/src/server/action-handler.ts +253 -110
  409. package/src/server/actions.ts +73 -25
  410. package/src/server/als-registry.ts +73 -5
  411. package/src/server/chain-url-parts.ts +1 -1
  412. package/src/server/children-interception.ts +2 -1
  413. package/src/server/cookie-context.ts +18 -48
  414. package/src/server/csp-nonce.ts +0 -12
  415. package/src/server/csrf.ts +140 -8
  416. package/src/server/debug.ts +0 -1
  417. package/src/server/default-logger.ts +2 -1
  418. package/src/server/deny-boundary.ts +25 -13
  419. package/src/server/deny-renderer.ts +30 -97
  420. package/src/server/error-boundary-wrapper.ts +7 -3
  421. package/src/server/fallback-error.ts +26 -11
  422. package/src/server/flight-scripts.ts +1 -1
  423. package/src/server/head-response.ts +4 -4
  424. package/src/server/html-injector-core.ts +2 -2
  425. package/src/server/html-injectors.ts +2 -4
  426. package/src/server/index.ts +0 -4
  427. package/src/server/instrumentation.ts +10 -3
  428. package/src/server/internal.ts +1 -6
  429. package/src/server/json-status-response.ts +105 -0
  430. package/src/server/logger.ts +39 -3
  431. package/src/server/param-coercion.ts +15 -12
  432. package/src/server/pipeline-helpers.ts +257 -12
  433. package/src/server/pipeline-interception.ts +133 -0
  434. package/src/server/pipeline-outcome.ts +103 -31
  435. package/src/server/pipeline-phases.ts +127 -237
  436. package/src/server/pipeline.ts +204 -207
  437. package/src/server/prebuilt/capture-render.ts +118 -0
  438. package/src/server/prebuilt/capture-routes.ts +104 -0
  439. package/src/server/prebuilt/capture-state.ts +155 -48
  440. package/src/server/prebuilt/lifetime.ts +151 -0
  441. package/src/server/prebuilt/slots.ts +14 -2
  442. package/src/server/prebuilt/synthetic-store.ts +3 -0
  443. package/src/server/prebuilt-builder.ts +30 -320
  444. package/src/server/prebuilt-runtime.ts +125 -129
  445. package/src/server/primitives.ts +8 -168
  446. package/src/server/react-cache-bridge.ts +124 -0
  447. package/src/server/react-cache-scope.ts +104 -0
  448. package/src/server/render-timeout.ts +20 -0
  449. package/src/server/render-utils.ts +11 -1
  450. package/src/server/request-context.ts +36 -9
  451. package/src/server/route-element-builder.ts +11 -6
  452. package/src/server/route-handler.ts +36 -23
  453. package/src/server/route-matcher.ts +15 -1
  454. package/src/server/rsc-entry/action-middleware-runner.ts +79 -123
  455. package/src/server/rsc-entry/api-handler.ts +27 -103
  456. package/src/server/rsc-entry/deny-fallback.ts +93 -26
  457. package/src/server/rsc-entry/error-renderer.ts +39 -91
  458. package/src/server/rsc-entry/helpers.ts +2 -4
  459. package/src/server/rsc-entry/index.ts +64 -58
  460. package/src/server/rsc-entry/render-route.ts +15 -80
  461. package/src/server/rsc-entry/render-signals.ts +108 -0
  462. package/src/server/rsc-entry/revalidate-renderer.ts +56 -57
  463. package/src/server/rsc-entry/rsc-payload.ts +28 -61
  464. package/src/server/rsc-entry/rsc-stream.ts +113 -213
  465. package/src/server/rsc-entry/ssr-bridge.ts +2 -2
  466. package/src/server/rsc-entry/ssr-renderer.ts +182 -263
  467. package/src/server/rsc-entry/wrap-action-dispatch.ts +12 -14
  468. package/src/server/signal-identity.ts +112 -0
  469. package/src/server/slot-resolver.ts +18 -18
  470. package/src/server/slot-subtree-contain.ts +2 -1
  471. package/src/server/ssr-bridge-types.ts +92 -56
  472. package/src/server/ssr-entry.ts +87 -111
  473. package/src/server/ssr-render.ts +55 -64
  474. package/src/server/ssr-wrappers.tsx +2 -2
  475. package/src/server/static-generator.ts +7 -42
  476. package/src/server/static-not-found.ts +3 -3
  477. package/src/server/stream-utils.ts +51 -0
  478. package/src/server/tracing.ts +58 -75
  479. package/src/server/types.ts +1 -1
  480. package/src/server/version-skew.ts +5 -5
  481. package/src/shared/csrf-reject.ts +15 -0
  482. package/src/shared/error-digest.ts +46 -0
  483. package/src/shared/payload-root.ts +11 -10
  484. package/src/shared/rsc-payload-path.ts +8 -1
  485. package/src/utils/write-file-atomic.ts +32 -0
  486. package/dist/_chunks/actions-jNrXdzgs.js +0 -346
  487. package/dist/_chunks/actions-jNrXdzgs.js.map +0 -1
  488. package/dist/_chunks/als-registry-C6kcfprT.js.map +0 -1
  489. package/dist/_chunks/build-manifest-DTmSGLRz.js.map +0 -1
  490. package/dist/_chunks/build-output-helper-9dqCv1pZ.js.map +0 -1
  491. package/dist/_chunks/cache-api-CUD9Ezaq.js.map +0 -1
  492. package/dist/_chunks/cli-check-G8o30ldg.js.map +0 -1
  493. package/dist/_chunks/convention-lint-5KzoMg_A.js.map +0 -1
  494. package/dist/_chunks/dev-server-BzBxgYAV.js.map +0 -1
  495. package/dist/_chunks/error-boundary-BrHmG-2X.js.map +0 -1
  496. package/dist/_chunks/fs-identity-D7vb6GdI.js.map +0 -1
  497. package/dist/_chunks/graph-cache-CP4GEmf9.js.map +0 -1
  498. package/dist/_chunks/json-lossy-check-ClNvBM_3.js.map +0 -1
  499. package/dist/_chunks/logger-k2DQ4EUf.js.map +0 -1
  500. package/dist/_chunks/navigation-context-D0TU0Jog.js.map +0 -1
  501. package/dist/_chunks/plugin-context-8idfR3UZ.js.map +0 -1
  502. package/dist/_chunks/primitives-DLAnvsrk.js.map +0 -1
  503. package/dist/_chunks/segment-context-D9_89u34.js +0 -34
  504. package/dist/_chunks/segment-context-D9_89u34.js.map +0 -1
  505. package/dist/_chunks/sizeof-lXffQ1Vr.js.map +0 -1
  506. package/dist/_chunks/ssr-data-D6T6Y3ef.js +0 -60
  507. package/dist/_chunks/ssr-data-D6T6Y3ef.js.map +0 -1
  508. package/dist/_chunks/state-FippDgxN.js.map +0 -1
  509. package/dist/_chunks/status-page-marker-CNbpUOPB.js.map +0 -1
  510. package/dist/client/types.d.ts +0 -14
  511. package/dist/client/types.d.ts.map +0 -1
  512. package/dist/plugins/adapter-build.d.ts +0 -38
  513. package/dist/plugins/adapter-build.d.ts.map +0 -1
  514. package/dist/server/asset-headers.d.ts +0 -32
  515. package/dist/server/asset-headers.d.ts.map +0 -1
  516. package/dist/server/dev-source-map.d.ts +0 -22
  517. package/dist/server/dev-source-map.d.ts.map +0 -1
  518. package/src/client/types.ts +0 -21
  519. package/src/server/asset-headers.ts +0 -59
  520. package/src/server/dev-source-map.ts +0 -31
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Candidate routes for the post-build capture pass
3
+ * (server/prebuilt-builder.ts, design/44-render-at-build-time.md §Build
4
+ * Phase): which pages carry prebuilt components, and which param combos
5
+ * to capture them for.
6
+ */
7
+
8
+ import type { CoercedParams } from '../../shared/param-value.ts';
9
+ import type { ManifestFile, ManifestSegmentNode } from '../route-matcher.ts';
10
+ import { hasDynamicSegments } from '../sitemap-generator.ts';
11
+
12
+ // ─── Route collection ─────────────────────────────────────────────────────
13
+
14
+ export interface CandidateRoute {
15
+ urlPath: string;
16
+ page: ManifestFile;
17
+ /** Layout files along the chain that declare prebuilt components. */
18
+ layoutsToLoad: ManifestFile[];
19
+ /** Component IDs attributed to this route's page + layout chain. */
20
+ componentIds: string[];
21
+ /** Component IDs from layout files (receive SlotOutlet as children). */
22
+ layoutComponentIds: Set<string>;
23
+ }
24
+
25
+ /**
26
+ * Walk the manifest tree and collect pages whose file chain (page +
27
+ * layouts above it) has prebuilt components attributed to it. Slots and
28
+ * intercepting/private segments are not walked — slot-scoped prebuilt is
29
+ * already unkeyable at request time when slot params diverge (see
30
+ * resolveKeyParams in prebuilt-runtime.ts), so the build doesn't model
31
+ * slots either.
32
+ */
33
+ export function collectCandidateRoutes(
34
+ root: ManifestSegmentNode,
35
+ fileComponentMap: Record<string, string[]>
36
+ ): CandidateRoute[] {
37
+ const routes: CandidateRoute[] = [];
38
+
39
+ const walk = (node: ManifestSegmentNode, layoutChain: ManifestFile[]) => {
40
+ if (node.segmentType === 'intercepting' || node.segmentType === 'private') return;
41
+ const chain = node.layout ? [...layoutChain, node.layout] : layoutChain;
42
+
43
+ if (node.page) {
44
+ const componentIds = new Set<string>();
45
+ const layoutIds = new Set<string>();
46
+ for (const f of chain)
47
+ for (const id of fileComponentMap[f.filePath] ?? []) {
48
+ componentIds.add(id);
49
+ layoutIds.add(id);
50
+ }
51
+ for (const id of fileComponentMap[node.page.filePath] ?? []) componentIds.add(id);
52
+ if (componentIds.size > 0) {
53
+ routes.push({
54
+ urlPath: node.urlPath,
55
+ page: node.page,
56
+ layoutsToLoad: chain.filter((l) => (fileComponentMap[l.filePath] ?? []).length > 0),
57
+ componentIds: Array.from(componentIds),
58
+ layoutComponentIds: layoutIds,
59
+ });
60
+ }
61
+ }
62
+
63
+ for (const child of node.children) walk(child, chain);
64
+ };
65
+
66
+ walk(root, []);
67
+ return routes;
68
+ }
69
+
70
+ // ─── Param enumeration ────────────────────────────────────────────────────
71
+
72
+ export type ParamCombo = CoercedParams;
73
+
74
+ /**
75
+ * Resolve the param combos to capture for a route. Static routes have
76
+ * exactly one combo (the empty record) — `export const prerender`-style
77
+ * components on static pages need no enumerator. Dynamic routes require
78
+ * `generateStaticSegmentParams` (design/44 §generateStaticSegmentParams);
79
+ * without it every request renders live and the wrapper is a no-op.
80
+ */
81
+ export async function enumerateCombos(
82
+ route: CandidateRoute,
83
+ pageModule: Record<string, unknown>,
84
+ log: (message: string) => void
85
+ ): Promise<ParamCombo[] | null> {
86
+ if (!hasDynamicSegments(route.urlPath)) return [{}];
87
+
88
+ const generateFn = pageModule.generateStaticSegmentParams;
89
+ if (typeof generateFn !== 'function') {
90
+ log(
91
+ `[timber] cache.component: route ${route.urlPath} has prebuilt components but no ` +
92
+ `generateStaticSegmentParams export — all its entries will render dynamically ` +
93
+ `until the page declares its param combos`
94
+ );
95
+ return null;
96
+ }
97
+ const combos: unknown = await (generateFn as () => unknown)();
98
+ if (!Array.isArray(combos)) {
99
+ throw new Error(
100
+ `generateStaticSegmentParams must return an array of param records, got ${typeof combos}`
101
+ );
102
+ }
103
+ return combos as ParamCombo[];
104
+ }
@@ -1,89 +1,196 @@
1
1
  /**
2
- * Build-time capture state — the channel between the post-build capture
3
- * pass (server/prebuilt-builder.ts) and the `__prebuilt` wrapper
4
- * (server/prebuilt-runtime.ts).
2
+ * Capture state — the channel between a payload capture and the
3
+ * `__prebuilt` wrappers that render inside it (server/prebuilt-runtime.ts).
5
4
  *
6
- * During capture, a wrapped component's subtree may render OTHER wrapped
7
- * components. With no payload source registered (the capture pass runs
8
- * before artifacts exist), those inner wrappers render live and their
9
- * output is baked flat into the outer entry — the nesting clamp of
10
- * design/45-cache-lifetimes.md §Nesting Semantics (TIM-1136). The capture
11
- * pass is the designated detection point for that clamp, so the wrapper
12
- * reports every render that happens while a capture is active:
5
+ * Two callers capture a wrapped component's flight payload:
13
6
  *
14
- * - **Cycle**: the inner wrapper IS the component being captured (directly
15
- * or transitively — the transitive case still renders the outer's own
16
- * wrapper, so the identity check catches both). Left alone this recurses
7
+ * - **Build time**: the post-build capture pass (server/prebuilt-builder.ts)
8
+ * renders each registry entry in turn.
9
+ * - **Request time**: `captureComponentPayload()` in prebuilt-runtime.ts
10
+ * renders a component in isolation for an inline re-render (full miss,
11
+ * stale entry, tombstone) or an SWR background re-render. These run
12
+ * concurrently with other requests' renders — and with each other.
13
+ *
14
+ * During a capture, the component's subtree may render OTHER wrapped
15
+ * components. Those inner wrappers render live and their output is baked
16
+ * flat into the outer entry — the nesting clamp of
17
+ * design/45-cache-lifetimes.md §Nesting Semantics (TIM-1136). The wrapper
18
+ * reports every render that happens inside a capture:
19
+ *
20
+ * - **Cycle**: the inner render IS the entry being captured — same
21
+ * component id AND same props key (TIM-1547). Left alone this recurses
17
22
  * until the render times out; instead the wrapper throws
18
23
  * `PrebuiltCaptureCycleError`, failing that entry with an error naming
19
- * the cycle while the build continues (doc 44 skip-and-report policy).
20
- * - **Nesting**: any other wrapper render is recorded as an (outer, inner)
21
- * pair. The builder warns after the entry completes when the inner
22
- * declares a refresh channel the outer cannot honor (doc 45 clamp rule).
24
+ * the cycle (build continues per doc 44 skip-and-report policy; at
25
+ * request time the re-render fails and is not cached, and the wrapper
26
+ * falls back as for any failed re-render). A component that renders
27
+ * itself with different props (a comment thread, a tree) is legitimate
28
+ * recursion with a base case and bakes flat like any other nesting.
29
+ * - **Nesting**: any other wrapper render is recorded per inner component
30
+ * with the tags it resolved to. Both capture callers run the clamp rule
31
+ * over those records when the entry completes (prebuilt/lifetime.ts).
32
+ *
33
+ * Identity is the capture ROOT only. A wrapper cannot see the wrappers
34
+ * between it and the root: Flight renders a component's children after
35
+ * the wrapper has returned, in Flight's own async context, not in a frame
36
+ * the wrapper could enter. So a same-key cycle that closes below the root
37
+ * (`A(p1) → A(p2) → A(p2) → …`) is not detected here; it is also an
38
+ * infinite recursion without caching, and the capture's render timeout
39
+ * fails it.
23
40
  *
24
- * Captures run strictly sequentially (one entry at a time), so a single
25
- * module-level slot is sufficient — there is never a second active capture
26
- * to confuse renders between. At request time `active` is null and
27
- * `noteWrapperRender` is a single null-check.
41
+ * The props key is the props half of the cache key (data props only,
42
+ * framework children outlet stripped — the same inputs the cache key
43
+ * hashes). The params half is left out: every render inside one capture
44
+ * reads the same segment params, so props decide identity. Unkeyable props
45
+ * (live React elements, …) cannot be proven identical and are never a
46
+ * cycle.
47
+ *
48
+ * Each capture's state lives in an AsyncLocalStorage store entered by
49
+ * `CaptureScope.run()`, so it is visible only to renders started inside
50
+ * that capture — including work Flight resumes after an await, which runs
51
+ * in the context the awaited promise was created in. A concurrent request
52
+ * rendering the same component is not a cycle, and a concurrent request
53
+ * rendering a different cached component still revives it from cache
54
+ * instead of baking it live (TIM-1536). Outside any capture
55
+ * `noteWrapperRender` is a single store lookup.
28
56
  */
29
57
 
58
+ import {
59
+ prebuiltCaptureAls,
60
+ requestContextAls,
61
+ type PrebuiltCaptureStore,
62
+ } from '../als-registry.ts';
30
63
  import type { PrebuiltComponentOptions } from '../prebuilt-runtime.ts';
64
+ import { computeComponentCacheKey, splitSlotProps } from './cache-key.ts';
65
+ import { resolveTags } from './lifetime.ts';
66
+ import { withoutChildrenOutlet } from './slots.ts';
31
67
 
32
68
  /** A wrapped component that rendered inside an active capture. */
33
69
  export interface NestedWrapperRender {
34
70
  innerId: string;
35
71
  options: PrebuiltComponentOptions;
72
+ /**
73
+ * Every tag the inner resolved to across its renders in this capture;
74
+ * null when its tags function threw (the tags are unknown).
75
+ */
76
+ tags: string[] | null;
77
+ }
78
+
79
+ /** Per-inner record kept while the capture runs. */
80
+ export interface NestedRecord {
81
+ options: PrebuiltComponentOptions;
82
+ tags: Set<string> | null;
36
83
  }
37
84
 
38
- /** Thrown by the wrapper when a capture renders its own component. */
85
+ /** Thrown by the wrapper when a capture renders its own entry. */
39
86
  export class PrebuiltCaptureCycleError extends Error {
40
87
  constructor(componentId: string) {
41
88
  super(
42
- `[timber] cache.component "${componentId}" renders itself (directly or through ` +
43
- `other components) — prerendering it would recurse forever. Remove the cycle ` +
44
- `or drop { prerender: true } on this component.`
89
+ `[timber] cache.component "${componentId}" renders itself with the same props ` +
90
+ `(directly or through other components) — capturing its payload would recurse ` +
91
+ `forever. Remove the cycle or stop caching this component with cache.component.`
45
92
  );
46
93
  this.name = 'PrebuiltCaptureCycleError';
47
94
  }
48
95
  }
49
96
 
50
- let active: { outerId: string; nested: Map<string, PrebuiltComponentOptions> } | null = null;
97
+ /** One capture's state, entered for the duration of its render. */
98
+ export interface CaptureScope {
99
+ /**
100
+ * Run `fn` inside this capture. Flight renders in the async context it
101
+ * was started (and pinged) from, so the render must be CREATED inside
102
+ * `run`; every wrapper it renders then sees this capture.
103
+ */
104
+ run<T>(fn: () => T): T;
105
+ /** Wrapped components that rendered inside this capture so far. */
106
+ nestedRenders(): NestedWrapperRender[];
107
+ }
51
108
 
52
109
  /**
53
- * Mark a capture as active. The builder calls this immediately before
54
- * rendering an entry and MUST pair it with `endCapture()` in a finally.
110
+ * The props half of a render's cache key, or null when unkeyable. Same
111
+ * inputs `tryRevivePayload` hashes: data props only for slot components,
112
+ * the framework-injected children outlet stripped.
55
113
  */
56
- export function beginCapture(outerId: string): void {
57
- active = { outerId, nested: new Map() };
114
+ function propsKey(
115
+ options: PrebuiltComponentOptions,
116
+ props: Record<string, unknown>
117
+ ): string | null {
118
+ let keyProps = props;
119
+ if (options.slots && options.slots.length > 0) {
120
+ const split = splitSlotProps(props, options.slots);
121
+ if (split === null) return null;
122
+ keyProps = split.dataProps;
123
+ }
124
+ return computeComponentCacheKey(withoutChildrenOutlet(keyProps), {});
58
125
  }
59
126
 
60
127
  /**
61
- * End the active capture and return the wrapped components that rendered
62
- * inside it (first options object wins per inner ID).
128
+ * Open a capture of component `outerId` rendered with `props`. Its state
129
+ * ends with the scope object.
63
130
  */
64
- export function endCapture(): NestedWrapperRender[] {
65
- const nested = active?.nested;
66
- active = null;
67
- if (!nested) return [];
68
- return Array.from(nested, ([innerId, options]) => ({ innerId, options }));
131
+ export function createCaptureScope(
132
+ outerId: string,
133
+ options: PrebuiltComponentOptions,
134
+ props: Record<string, unknown>
135
+ ): CaptureScope {
136
+ const store: PrebuiltCaptureStore = {
137
+ outerId,
138
+ outerPropsKey: propsKey(options, props),
139
+ nested: new Map(),
140
+ };
141
+ return {
142
+ run: (fn) => prebuiltCaptureAls.run(store, fn),
143
+ nestedRenders: () =>
144
+ Array.from(store.nested, ([innerId, record]) => ({
145
+ innerId,
146
+ options: record.options,
147
+ tags: record.tags && Array.from(record.tags),
148
+ })),
149
+ };
69
150
  }
70
151
 
71
- /** Whether a build-time capture is currently rendering. */
152
+ /** Whether the current render is inside a capture. */
72
153
  export function isCaptureActive(): boolean {
73
- return active !== null;
154
+ return prebuiltCaptureAls.getStore() !== undefined;
74
155
  }
75
156
 
76
157
  /**
77
- * Called by the `__prebuilt` wrapper on every render. No-op unless a
78
- * capture is active. Throws `PrebuiltCaptureCycleError` when the wrapper
79
- * belongs to the component currently being captured.
158
+ * Called by the `__prebuilt` wrapper on every render. No-op outside a
159
+ * capture. Throws `PrebuiltCaptureCycleError` when the render is the
160
+ * entry the enclosing capture is producing.
80
161
  */
81
- export function noteWrapperRender(innerId: string, options: PrebuiltComponentOptions): void {
82
- if (active === null) return;
83
- if (innerId === active.outerId) {
84
- throw new PrebuiltCaptureCycleError(innerId);
162
+ export function noteWrapperRender(
163
+ innerId: string,
164
+ options: PrebuiltComponentOptions,
165
+ props: Record<string, unknown>
166
+ ): void {
167
+ const capture = prebuiltCaptureAls.getStore();
168
+ if (capture === undefined) return;
169
+ if (innerId === capture.outerId && capture.outerPropsKey !== null) {
170
+ if (propsKey(options, props) === capture.outerPropsKey) {
171
+ throw new PrebuiltCaptureCycleError(innerId);
172
+ }
173
+ }
174
+ let record = capture.nested.get(innerId);
175
+ if (record === undefined) {
176
+ record = { options, tags: new Set() };
177
+ capture.nested.set(innerId, record);
85
178
  }
86
- if (!active.nested.has(innerId)) {
87
- active.nested.set(innerId, options);
179
+ if (record.tags !== null && options.tags) {
180
+ // A diagnostic must not change the capture. The tags function is user
181
+ // code, so it runs with the request context exited: a read of
182
+ // segment params, headers, or cookies inside it must not be charged
183
+ // to the OUTER entry (a build-time context violation, a lost
184
+ // param-independence proof, a key-discipline report). A tags function
185
+ // that throws — including because it needed that context — leaves the
186
+ // inner's tags unknown, which the clamp rule treats as not covered by
187
+ // the outer; the warning says so. The throw itself is not reported
188
+ // here: it belongs to the inner, which may never be cached on its own.
189
+ const tags = record.tags;
190
+ try {
191
+ for (const tag of requestContextAls.exit(() => resolveTags(options, props))) tags.add(tag);
192
+ } catch {
193
+ record.tags = null;
194
+ }
88
195
  }
89
196
  }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Lifetime declarations of a `cache.component` — `prerender`, `ttl`,
3
+ * `tags` (design/45-cache-lifetimes.md) — and the nesting clamp between
4
+ * two of them (§Nesting Semantics, TIM-1136).
5
+ *
6
+ * The clamp rule lives here once, for both places a capture can embed one
7
+ * wrapped component in another: the post-build capture pass
8
+ * (server/prebuilt-builder.ts) and request-time re-renders
9
+ * (`captureComponentPayload()` in server/prebuilt-runtime.ts, TIM-1545).
10
+ */
11
+
12
+ import { splitSlotProps } from './cache-key.ts';
13
+ import type { NestedWrapperRender } from './capture-state.ts';
14
+ import type { PrebuiltComponentOptions } from '../prebuilt-runtime.ts';
15
+
16
+ /** Whether the component has a runtime lifetime (ttl or tags). */
17
+ export function hasRuntimeLifetime(options: PrebuiltComponentOptions): boolean {
18
+ return options.ttl !== undefined || options.tags != null;
19
+ }
20
+
21
+ /**
22
+ * Resolve tags from options (may be static array or function of props).
23
+ * Function-form tags receive DATA props only — slot props are excluded so
24
+ * the tags fn never sees SlotOutlet placeholders (capture paths pass
25
+ * placeholder-substituted props) and tags stay deterministic per key.
26
+ */
27
+ export function resolveTags(
28
+ options: PrebuiltComponentOptions,
29
+ props: Record<string, unknown>
30
+ ): string[] {
31
+ if (!options.tags) return [];
32
+ if (Array.isArray(options.tags)) return options.tags;
33
+ const slots = options.slots;
34
+ // The split cannot fail here — capture paths pass framework-built shell
35
+ // props — but stay total: fall back to the props as given.
36
+ const fnProps =
37
+ slots && slots.length > 0 ? (splitSlotProps(props, slots)?.dataProps ?? props) : props;
38
+ return options.tags(fnProps);
39
+ }
40
+
41
+ // ─── Nesting clamp (design/45 §Nesting Semantics) ────────────────────────
42
+
43
+ /** The entry a capture is producing: its declaration and resolved tags. */
44
+ export interface CapturedLifetime {
45
+ id: string;
46
+ options: PrebuiltComponentOptions;
47
+ tags: readonly string[];
48
+ }
49
+
50
+ /**
51
+ * Why an embedded copy of `inner` goes stale inside `outer`, or null when
52
+ * the outer's refreshes cover every refresh channel the inner declares:
53
+ *
54
+ * - `shorterTtl`: the inner's ttl is shorter than the outer's effective
55
+ * lifetime (its ttl, or deploy-long without one).
56
+ * - `missingTags`: tags the inner resolved to that the outer lacks —
57
+ * `revalidateTag` on them refreshes the inner's own entries, never the
58
+ * copy. `null` inner tags (a tags function threw) cannot be proven a
59
+ * subset, so they count as missing.
60
+ *
61
+ * Declaring the inner's tags on the outer is the documented fix, and it
62
+ * silences the tag half by construction.
63
+ */
64
+ function clampReasons(
65
+ outer: CapturedLifetime,
66
+ inner: NestedWrapperRender
67
+ ): { shorterTtl: boolean; missingTags: string[] | null } | null {
68
+ const outerTtl = outer.options.ttl ?? Infinity;
69
+ const shorterTtl = inner.options.ttl !== undefined && inner.options.ttl < outerTtl;
70
+ const missingTags =
71
+ inner.tags === null ? null : inner.tags.filter((t) => !outer.tags.includes(t));
72
+ if (!shorterTtl && missingTags !== null && missingTags.length === 0) return null;
73
+ return { shorterTtl, missingTags };
74
+ }
75
+
76
+ /** Render a lifetime declaration for the clamp warning. */
77
+ function describeLifetime(
78
+ options: PrebuiltComponentOptions,
79
+ tags: readonly string[] | null
80
+ ): string {
81
+ const parts: string[] = [];
82
+ if (options.prerender) parts.push('prerender');
83
+ if (options.ttl !== undefined) parts.push(`ttl: ${options.ttl}`);
84
+ if (tags === null) parts.push('tags: fn');
85
+ else if (tags.length > 0) parts.push(`tags: ${JSON.stringify(tags)}`);
86
+ return parts.join(', ') || 'no lifetime';
87
+ }
88
+
89
+ /** When the outer entry — and so every copy embedded in it — refreshes. */
90
+ function describeRefresh(outer: CapturedLifetime): string {
91
+ const parts: string[] = [];
92
+ if (outer.options.ttl !== undefined) parts.push(`every ${outer.options.ttl}s`);
93
+ if (outer.tags.length > 0) parts.push(`on revalidateTag of its own tags`);
94
+ // Component keys are per-deploy, so every entry refreshes on redeploy.
95
+ parts.push('on redeploy');
96
+ return parts.join(', or ');
97
+ }
98
+
99
+ /**
100
+ * Warn for each wrapped component embedded in `outer`'s captured payload
101
+ * whose refresh channels the outer cannot honor. Once per (outer, inner)
102
+ * pair for the lifetime of `warnedPairs` — the builder passes one per
103
+ * build, the runtime one per process, since re-renders repeat. The key is
104
+ * the pair alone, not the reason: resolved tags vary with props, and a key
105
+ * that included them would grow with the data. So the first clamp found
106
+ * for a pair is the one reported. Returns the number of warnings emitted.
107
+ */
108
+ export function warnNestingClamps(
109
+ outer: CapturedLifetime,
110
+ nested: readonly NestedWrapperRender[],
111
+ warnedPairs: Set<string>,
112
+ log: (message: string) => void
113
+ ): number {
114
+ let count = 0;
115
+ for (const inner of nested) {
116
+ const reasons = clampReasons(outer, inner);
117
+ if (reasons === null) continue;
118
+ const pairKey = `${outer.id}\0${inner.innerId}`;
119
+ if (warnedPairs.has(pairKey)) continue;
120
+ warnedPairs.add(pairKey);
121
+ count++;
122
+ const outerLifetime = describeLifetime(outer.options, outer.tags);
123
+ const innerLifetime = describeLifetime(inner.options, inner.tags);
124
+ const consequences: string[] = [];
125
+ if (reasons.missingTags === null) {
126
+ consequences.push(
127
+ `${inner.innerId}'s tags could not be resolved during the capture (its tags function ` +
128
+ `threw or needed request context), so revalidating them may NOT update the embedded copy.`
129
+ );
130
+ } else if (reasons.missingTags.length > 0) {
131
+ const calls = reasons.missingTags.map((t) => `revalidateTag(${JSON.stringify(t)})`);
132
+ consequences.push(
133
+ `${calls.join(', ')} will NOT update the embedded copy; tag ${outer.id} itself if you ` +
134
+ `need that.`
135
+ );
136
+ }
137
+ if (reasons.shorterTtl) {
138
+ consequences.push(
139
+ `${inner.innerId}'s ttl: ${inner.options.ttl} does not apply to the embedded copy.`
140
+ );
141
+ }
142
+ log(
143
+ `[timber] ${inner.innerId} (${innerLifetime}) is embedded in ` +
144
+ `${outer.options.prerender ? 'prerendered' : 'cached'} ${outer.id} — the embedded ` +
145
+ `copy refreshes only when ${outer.id} does (${describeRefresh(outer)}). ` +
146
+ `${consequences.join(' ')} Chain: ${outer.id} (${outerLifetime}) → ${inner.innerId} ` +
147
+ `(${innerLifetime})`
148
+ );
149
+ }
150
+ return count;
151
+ }
@@ -19,6 +19,7 @@ import type { SlotValues } from '../../client/slot-context.ts';
19
19
  import { SlotOutlet } from '../../client/slot-outlet.tsx';
20
20
  import { SlotsProvider } from '../../client/slot-provider.tsx';
21
21
  import { splitSlotProps } from './cache-key.ts';
22
+ import { hasRuntimeLifetime } from './lifetime.ts';
22
23
  import type { PrebuiltComponentOptions } from '../prebuilt-runtime.ts';
23
24
 
24
25
  /**
@@ -65,6 +66,18 @@ export function isChildrenSlotOutletElement(value: unknown): boolean {
65
66
  }
66
67
  }
67
68
 
69
+ /**
70
+ * `props` without the framework-injected children outlet — the key props
71
+ * of a render. The outlet is the same client reference on every request,
72
+ * so it never varies the cache key; user-provided children stay (and
73
+ * leave the props unkeyable). See design/45 §Layout Propagation, TIM-1181.
74
+ */
75
+ export function withoutChildrenOutlet(props: Record<string, unknown>): Record<string, unknown> {
76
+ if (!isChildrenSlotOutletElement(props.children)) return props;
77
+ const { children: _children, ...rest } = props;
78
+ return rest;
79
+ }
80
+
68
81
  /**
69
82
  * Outcome of validating a `slots` declaration at registration time.
70
83
  *
@@ -122,8 +135,7 @@ export function resolveSlotNames(id: string, options: PrebuiltComponentOptions):
122
135
  return { kind: 'disabled' };
123
136
  }
124
137
  if (slots.length === 0) return { kind: 'none' };
125
- const hasRuntimeLifetime = options.ttl !== undefined || options.tags != null;
126
- if (!hasRuntimeLifetime) {
138
+ if (!hasRuntimeLifetime(options)) {
127
139
  console.warn(
128
140
  `[timber] cache.component "${id}": slots require a runtime lifetime ` +
129
141
  `(ttl and/or tags). Slot caching is disabled.`
@@ -89,6 +89,9 @@ export function createBuildTimeStore(
89
89
  segmentParamsRead: false,
90
90
  };
91
91
  const store: RequestContextStore = {
92
+ // No request at build time, so a stale-while-revalidate failure during
93
+ // capture is logged and not reported against a made-up one.
94
+ request: null,
92
95
  headers: new Headers(),
93
96
  originalHeaders: new Headers(),
94
97
  cookieHeader: '',