@timber-js/app 0.2.0-alpha.207 → 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 (526) 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-BndF-3Td.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-DwQBrLBz.js → status-page-marker-gaihi0KZ.js} +140 -28
  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 +20 -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 +95 -108
  132. package/dist/client/internal.js.map +1 -1
  133. package/dist/client/navigation-commit.d.ts +20 -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 +3 -8
  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/segment-cache.d.ts +44 -4
  149. package/dist/client/segment-cache.d.ts.map +1 -1
  150. package/dist/client/ssr-data.d.ts +18 -64
  151. package/dist/client/ssr-data.d.ts.map +1 -1
  152. package/dist/client/state.d.ts +2 -5
  153. package/dist/client/state.d.ts.map +1 -1
  154. package/dist/client/use-pathname.d.ts +1 -1
  155. package/dist/config-types.d.ts +2 -1
  156. package/dist/config-types.d.ts.map +1 -1
  157. package/dist/config-validation.d.ts.map +1 -1
  158. package/dist/cookies/index.js +1 -1
  159. package/dist/dev-tools/dev-page-shell.d.ts +17 -0
  160. package/dist/dev-tools/dev-page-shell.d.ts.map +1 -1
  161. package/dist/dev-tools/index.d.ts +1 -1
  162. package/dist/dev-tools/index.d.ts.map +1 -1
  163. package/dist/dev-tools/instrumentation.d.ts +17 -2
  164. package/dist/dev-tools/instrumentation.d.ts.map +1 -1
  165. package/dist/dev-tools/overlay.d.ts +6 -27
  166. package/dist/dev-tools/overlay.d.ts.map +1 -1
  167. package/dist/index.d.ts.map +1 -1
  168. package/dist/index.js +632 -373
  169. package/dist/index.js.map +1 -1
  170. package/dist/plugin-context.d.ts +26 -40
  171. package/dist/plugin-context.d.ts.map +1 -1
  172. package/dist/plugins/build-manifest.d.ts.map +1 -1
  173. package/dist/plugins/build-report.d.ts +15 -2
  174. package/dist/plugins/build-report.d.ts.map +1 -1
  175. package/dist/plugins/dev-server.d.ts.map +1 -1
  176. package/dist/plugins/entries.d.ts.map +1 -1
  177. package/dist/plugins/fonts.d.ts +19 -1
  178. package/dist/plugins/fonts.d.ts.map +1 -1
  179. package/dist/plugins/post-build.d.ts +110 -0
  180. package/dist/plugins/post-build.d.ts.map +1 -0
  181. package/dist/plugins/prebuilt-capture.d.ts +11 -4
  182. package/dist/plugins/prebuilt-capture.d.ts.map +1 -1
  183. package/dist/plugins/prebuilt.d.ts +17 -1
  184. package/dist/plugins/prebuilt.d.ts.map +1 -1
  185. package/dist/plugins/prerender-sugar.d.ts.map +1 -1
  186. package/dist/plugins/react-resolve.d.ts +49 -0
  187. package/dist/plugins/react-resolve.d.ts.map +1 -0
  188. package/dist/plugins/rsc-assets-manifest.d.ts +33 -0
  189. package/dist/plugins/rsc-assets-manifest.d.ts.map +1 -0
  190. package/dist/plugins/shims.d.ts.map +1 -1
  191. package/dist/plugins/static-build.d.ts +32 -9
  192. package/dist/plugins/static-build.d.ts.map +1 -1
  193. package/dist/routing/codegen-write.d.ts +0 -9
  194. package/dist/routing/codegen-write.d.ts.map +1 -1
  195. package/dist/routing/index.js +2 -2
  196. package/dist/routing/segment-codegen.d.ts.map +1 -1
  197. package/dist/server/access-gate.d.ts.map +1 -1
  198. package/dist/server/action-handler.d.ts +5 -4
  199. package/dist/server/action-handler.d.ts.map +1 -1
  200. package/dist/server/actions.d.ts +46 -7
  201. package/dist/server/actions.d.ts.map +1 -1
  202. package/dist/server/als-registry.d.ts +58 -5
  203. package/dist/server/als-registry.d.ts.map +1 -1
  204. package/dist/server/children-interception.d.ts.map +1 -1
  205. package/dist/server/cookie-context.d.ts +2 -23
  206. package/dist/server/cookie-context.d.ts.map +1 -1
  207. package/dist/server/csp-nonce.d.ts +0 -9
  208. package/dist/server/csp-nonce.d.ts.map +1 -1
  209. package/dist/server/csrf.d.ts +27 -4
  210. package/dist/server/csrf.d.ts.map +1 -1
  211. package/dist/server/debug.d.ts +0 -1
  212. package/dist/server/debug.d.ts.map +1 -1
  213. package/dist/server/default-logger.d.ts +2 -1
  214. package/dist/server/default-logger.d.ts.map +1 -1
  215. package/dist/server/deny-boundary.d.ts +12 -6
  216. package/dist/server/deny-boundary.d.ts.map +1 -1
  217. package/dist/server/deny-renderer.d.ts +2 -2
  218. package/dist/server/deny-renderer.d.ts.map +1 -1
  219. package/dist/server/error-boundary-wrapper.d.ts +7 -3
  220. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  221. package/dist/server/fallback-error.d.ts +9 -2
  222. package/dist/server/fallback-error.d.ts.map +1 -1
  223. package/dist/server/head-response.d.ts +4 -4
  224. package/dist/server/html-injectors.d.ts.map +1 -1
  225. package/dist/server/index.d.ts +0 -1
  226. package/dist/server/index.d.ts.map +1 -1
  227. package/dist/server/index.js +3 -4
  228. package/dist/server/index.js.map +1 -1
  229. package/dist/server/instrumentation.d.ts +10 -3
  230. package/dist/server/instrumentation.d.ts.map +1 -1
  231. package/dist/server/internal.d.ts +1 -4
  232. package/dist/server/internal.d.ts.map +1 -1
  233. package/dist/server/internal.js +961 -581
  234. package/dist/server/internal.js.map +1 -1
  235. package/dist/server/json-status-response.d.ts +34 -0
  236. package/dist/server/json-status-response.d.ts.map +1 -0
  237. package/dist/server/logger.d.ts +26 -0
  238. package/dist/server/logger.d.ts.map +1 -1
  239. package/dist/server/param-coercion.d.ts +11 -6
  240. package/dist/server/param-coercion.d.ts.map +1 -1
  241. package/dist/server/pipeline-helpers.d.ts +95 -7
  242. package/dist/server/pipeline-helpers.d.ts.map +1 -1
  243. package/dist/server/pipeline-interception.d.ts +11 -0
  244. package/dist/server/pipeline-interception.d.ts.map +1 -1
  245. package/dist/server/pipeline-outcome.d.ts +11 -1
  246. package/dist/server/pipeline-outcome.d.ts.map +1 -1
  247. package/dist/server/pipeline-phases.d.ts +2 -2
  248. package/dist/server/pipeline-phases.d.ts.map +1 -1
  249. package/dist/server/pipeline.d.ts +23 -35
  250. package/dist/server/pipeline.d.ts.map +1 -1
  251. package/dist/server/prebuilt/capture-render.d.ts +25 -0
  252. package/dist/server/prebuilt/capture-render.d.ts.map +1 -0
  253. package/dist/server/prebuilt/capture-routes.d.ts +37 -0
  254. package/dist/server/prebuilt/capture-routes.d.ts.map +1 -0
  255. package/dist/server/prebuilt/capture-state.d.ts +79 -35
  256. package/dist/server/prebuilt/capture-state.d.ts.map +1 -1
  257. package/dist/server/prebuilt/lifetime.d.ts +38 -0
  258. package/dist/server/prebuilt/lifetime.d.ts.map +1 -0
  259. package/dist/server/prebuilt/slots.d.ts +7 -0
  260. package/dist/server/prebuilt/slots.d.ts.map +1 -1
  261. package/dist/server/prebuilt/synthetic-store.d.ts.map +1 -1
  262. package/dist/server/prebuilt-builder.d.ts.map +1 -1
  263. package/dist/server/prebuilt-runtime.d.ts.map +1 -1
  264. package/dist/server/primitives.d.ts +6 -81
  265. package/dist/server/primitives.d.ts.map +1 -1
  266. package/dist/server/react-cache-bridge.d.ts +59 -0
  267. package/dist/server/react-cache-bridge.d.ts.map +1 -0
  268. package/dist/server/react-cache-scope.d.ts +49 -0
  269. package/dist/server/react-cache-scope.d.ts.map +1 -0
  270. package/dist/server/render-timeout.d.ts +15 -0
  271. package/dist/server/render-timeout.d.ts.map +1 -1
  272. package/dist/server/render-utils.d.ts +9 -0
  273. package/dist/server/render-utils.d.ts.map +1 -1
  274. package/dist/server/request-context.d.ts +26 -5
  275. package/dist/server/request-context.d.ts.map +1 -1
  276. package/dist/server/route-element-builder.d.ts.map +1 -1
  277. package/dist/server/route-handler.d.ts.map +1 -1
  278. package/dist/server/route-matcher.d.ts +7 -0
  279. package/dist/server/route-matcher.d.ts.map +1 -1
  280. package/dist/server/rsc-entry/action-middleware-runner.d.ts +22 -22
  281. package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -1
  282. package/dist/server/rsc-entry/api-handler.d.ts +7 -0
  283. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  284. package/dist/server/rsc-entry/deny-fallback.d.ts +32 -6
  285. package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
  286. package/dist/server/rsc-entry/error-renderer.d.ts +11 -18
  287. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  288. package/dist/server/rsc-entry/helpers.d.ts +0 -1
  289. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  290. package/dist/server/rsc-entry/index.d.ts +5 -15
  291. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  292. package/dist/server/rsc-entry/render-route.d.ts +5 -6
  293. package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
  294. package/dist/server/rsc-entry/render-signals.d.ts +65 -0
  295. package/dist/server/rsc-entry/render-signals.d.ts.map +1 -0
  296. package/dist/server/rsc-entry/revalidate-renderer.d.ts +6 -16
  297. package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
  298. package/dist/server/rsc-entry/rsc-payload.d.ts +7 -3
  299. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  300. package/dist/server/rsc-entry/rsc-stream.d.ts +8 -53
  301. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  302. package/dist/server/rsc-entry/ssr-bridge.d.ts +2 -2
  303. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  304. package/dist/server/rsc-entry/ssr-renderer.d.ts +9 -4
  305. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  306. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +1 -1
  307. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -1
  308. package/dist/server/signal-identity.d.ts +43 -0
  309. package/dist/server/signal-identity.d.ts.map +1 -0
  310. package/dist/server/slot-resolver.d.ts +4 -3
  311. package/dist/server/slot-resolver.d.ts.map +1 -1
  312. package/dist/server/slot-subtree-contain.d.ts.map +1 -1
  313. package/dist/server/ssr-bridge-types.d.ts +91 -53
  314. package/dist/server/ssr-bridge-types.d.ts.map +1 -1
  315. package/dist/server/ssr-entry.d.ts +8 -5
  316. package/dist/server/ssr-entry.d.ts.map +1 -1
  317. package/dist/server/ssr-render.d.ts +26 -40
  318. package/dist/server/ssr-render.d.ts.map +1 -1
  319. package/dist/server/ssr-wrappers.d.ts +1 -1
  320. package/dist/server/static-generator.d.ts.map +1 -1
  321. package/dist/server/stream-utils.d.ts +12 -0
  322. package/dist/server/stream-utils.d.ts.map +1 -1
  323. package/dist/server/tracing.d.ts +12 -16
  324. package/dist/server/tracing.d.ts.map +1 -1
  325. package/dist/server/types.d.ts +1 -1
  326. package/dist/server/version-skew.d.ts +3 -3
  327. package/dist/shared/csrf-reject.d.ts +16 -0
  328. package/dist/shared/csrf-reject.d.ts.map +1 -0
  329. package/dist/shared/error-digest.d.ts +28 -0
  330. package/dist/shared/error-digest.d.ts.map +1 -0
  331. package/dist/shared/payload-root.d.ts +11 -10
  332. package/dist/shared/payload-root.d.ts.map +1 -1
  333. package/dist/shared/rsc-payload-path.d.ts +6 -0
  334. package/dist/shared/rsc-payload-path.d.ts.map +1 -1
  335. package/dist/utils/write-file-atomic.d.ts +17 -0
  336. package/dist/utils/write-file-atomic.d.ts.map +1 -0
  337. package/docs/api/30-api-server.mdx +17 -14
  338. package/docs/api/32-api-cache.mdx +51 -23
  339. package/docs/api/34-api-config.mdx +34 -6
  340. package/docs/api/36-cli.mdx +11 -1
  341. package/docs/learn/03-fetching-data.mdx +17 -1
  342. package/docs/learn/04-access-control.mdx +1 -1
  343. package/docs/learn/10-caching.mdx +29 -11
  344. package/docs/learn/11-middleware.mdx +8 -2
  345. package/docs/learn/12-error-handling.mdx +6 -1
  346. package/package.json +7 -3
  347. package/src/adapters/build-output-helper.ts +55 -53
  348. package/src/adapters/canonicalize-module.ts +29 -0
  349. package/src/adapters/cloudflare.ts +105 -63
  350. package/src/adapters/compress-module.ts +16 -5
  351. package/src/adapters/fs-identity.ts +2 -3
  352. package/src/adapters/nitro-presets.ts +0 -15
  353. package/src/adapters/nitro-preview.ts +272 -136
  354. package/src/adapters/nitro.ts +119 -82
  355. package/src/adapters/shared.ts +23 -14
  356. package/src/adapters/types.ts +110 -21
  357. package/src/analyze/graph-cache.ts +3 -4
  358. package/src/cache/json-lossy-check.ts +3 -9
  359. package/src/cache/singleflight.ts +5 -2
  360. package/src/cache/sizeof.ts +3 -1
  361. package/src/cache/tag-aware-handler.ts +43 -26
  362. package/src/cli-check.ts +8 -98
  363. package/src/cli-context.ts +119 -0
  364. package/src/cli.ts +19 -28
  365. package/src/client/browser-dev.ts +1 -1
  366. package/src/client/browser-entry/action-dispatch.ts +26 -4
  367. package/src/client/browser-entry/hydrate.ts +53 -58
  368. package/src/client/browser-entry/index.ts +16 -27
  369. package/src/client/browser-entry/post-hydration.ts +6 -40
  370. package/src/client/browser-entry/router-init.ts +66 -84
  371. package/src/client/error-boundary.tsx +9 -41
  372. package/src/client/error-reconstituter.tsx +10 -5
  373. package/src/client/history.ts +35 -21
  374. package/src/client/index.ts +0 -1
  375. package/src/client/internal.ts +2 -7
  376. package/src/client/navigation-commit.ts +41 -18
  377. package/src/client/navigation-context.ts +3 -39
  378. package/src/client/react-root.ts +3 -2
  379. package/src/client/router-pipeline.ts +96 -132
  380. package/src/client/router-types.ts +46 -44
  381. package/src/client/router-url.ts +32 -0
  382. package/src/client/router.ts +62 -21
  383. package/src/client/rsc-fetch.ts +117 -155
  384. package/src/client/segment-cache.ts +110 -11
  385. package/src/client/ssr-data.ts +19 -80
  386. package/src/client/state.ts +2 -9
  387. package/src/client/use-pathname.ts +1 -1
  388. package/src/config-types.ts +2 -1
  389. package/src/config-validation.ts +2 -1
  390. package/src/dev-tools/dev-page-shell.ts +18 -0
  391. package/src/dev-tools/index.ts +0 -2
  392. package/src/dev-tools/instrumentation.ts +50 -2
  393. package/src/dev-tools/overlay.ts +8 -238
  394. package/src/index.ts +26 -14
  395. package/src/plugin-context.ts +39 -40
  396. package/src/plugins/build-manifest.ts +4 -11
  397. package/src/plugins/build-report.ts +70 -70
  398. package/src/plugins/dev-server.ts +24 -44
  399. package/src/plugins/entries.ts +2 -1
  400. package/src/plugins/fonts.ts +35 -7
  401. package/src/plugins/post-build.ts +327 -0
  402. package/src/plugins/prebuilt-capture.ts +28 -32
  403. package/src/plugins/prebuilt.ts +54 -39
  404. package/src/plugins/prerender-sugar.ts +0 -4
  405. package/src/plugins/react-resolve.ts +149 -0
  406. package/src/plugins/{adapter-build.ts → rsc-assets-manifest.ts} +20 -109
  407. package/src/plugins/shims.ts +1 -0
  408. package/src/plugins/static-build.ts +42 -74
  409. package/src/routing/codegen-write.ts +25 -3
  410. package/src/routing/segment-codegen.ts +3 -2
  411. package/src/rsc-runtime/vendor-types.d.ts +8 -0
  412. package/src/server/access-gate.tsx +2 -1
  413. package/src/server/action-client.ts +1 -1
  414. package/src/server/action-handler.ts +253 -110
  415. package/src/server/actions.ts +73 -25
  416. package/src/server/als-registry.ts +73 -5
  417. package/src/server/chain-url-parts.ts +1 -1
  418. package/src/server/children-interception.ts +2 -1
  419. package/src/server/cookie-context.ts +18 -48
  420. package/src/server/csp-nonce.ts +0 -12
  421. package/src/server/csrf.ts +140 -8
  422. package/src/server/debug.ts +0 -1
  423. package/src/server/default-logger.ts +2 -1
  424. package/src/server/deny-boundary.ts +25 -13
  425. package/src/server/deny-renderer.ts +30 -97
  426. package/src/server/error-boundary-wrapper.ts +7 -3
  427. package/src/server/fallback-error.ts +26 -11
  428. package/src/server/flight-scripts.ts +1 -1
  429. package/src/server/head-response.ts +4 -4
  430. package/src/server/html-injector-core.ts +2 -2
  431. package/src/server/html-injectors.ts +2 -4
  432. package/src/server/index.ts +0 -4
  433. package/src/server/instrumentation.ts +10 -3
  434. package/src/server/internal.ts +1 -6
  435. package/src/server/json-status-response.ts +105 -0
  436. package/src/server/logger.ts +39 -3
  437. package/src/server/param-coercion.ts +15 -12
  438. package/src/server/pipeline-helpers.ts +257 -12
  439. package/src/server/pipeline-interception.ts +133 -0
  440. package/src/server/pipeline-outcome.ts +103 -31
  441. package/src/server/pipeline-phases.ts +127 -237
  442. package/src/server/pipeline.ts +204 -207
  443. package/src/server/prebuilt/capture-render.ts +118 -0
  444. package/src/server/prebuilt/capture-routes.ts +104 -0
  445. package/src/server/prebuilt/capture-state.ts +155 -48
  446. package/src/server/prebuilt/lifetime.ts +151 -0
  447. package/src/server/prebuilt/slots.ts +14 -2
  448. package/src/server/prebuilt/synthetic-store.ts +3 -0
  449. package/src/server/prebuilt-builder.ts +30 -320
  450. package/src/server/prebuilt-runtime.ts +125 -129
  451. package/src/server/primitives.ts +8 -168
  452. package/src/server/react-cache-bridge.ts +124 -0
  453. package/src/server/react-cache-scope.ts +104 -0
  454. package/src/server/render-timeout.ts +20 -0
  455. package/src/server/render-utils.ts +11 -1
  456. package/src/server/request-context.ts +36 -9
  457. package/src/server/route-element-builder.ts +11 -6
  458. package/src/server/route-handler.ts +36 -23
  459. package/src/server/route-matcher.ts +15 -1
  460. package/src/server/rsc-entry/action-middleware-runner.ts +79 -123
  461. package/src/server/rsc-entry/api-handler.ts +27 -103
  462. package/src/server/rsc-entry/deny-fallback.ts +93 -26
  463. package/src/server/rsc-entry/error-renderer.ts +39 -91
  464. package/src/server/rsc-entry/helpers.ts +2 -4
  465. package/src/server/rsc-entry/index.ts +64 -58
  466. package/src/server/rsc-entry/render-route.ts +15 -80
  467. package/src/server/rsc-entry/render-signals.ts +108 -0
  468. package/src/server/rsc-entry/revalidate-renderer.ts +56 -57
  469. package/src/server/rsc-entry/rsc-payload.ts +28 -61
  470. package/src/server/rsc-entry/rsc-stream.ts +113 -213
  471. package/src/server/rsc-entry/ssr-bridge.ts +2 -2
  472. package/src/server/rsc-entry/ssr-renderer.ts +182 -263
  473. package/src/server/rsc-entry/wrap-action-dispatch.ts +12 -14
  474. package/src/server/signal-identity.ts +112 -0
  475. package/src/server/slot-resolver.ts +18 -18
  476. package/src/server/slot-subtree-contain.ts +2 -1
  477. package/src/server/ssr-bridge-types.ts +92 -56
  478. package/src/server/ssr-entry.ts +87 -111
  479. package/src/server/ssr-render.ts +55 -64
  480. package/src/server/ssr-wrappers.tsx +2 -2
  481. package/src/server/static-generator.ts +7 -42
  482. package/src/server/static-not-found.ts +3 -3
  483. package/src/server/stream-utils.ts +51 -0
  484. package/src/server/tracing.ts +58 -75
  485. package/src/server/types.ts +1 -1
  486. package/src/server/version-skew.ts +5 -5
  487. package/src/shared/csrf-reject.ts +15 -0
  488. package/src/shared/error-digest.ts +46 -0
  489. package/src/shared/payload-root.ts +11 -10
  490. package/src/shared/rsc-payload-path.ts +8 -1
  491. package/src/utils/write-file-atomic.ts +32 -0
  492. package/dist/_chunks/actions-jNrXdzgs.js +0 -346
  493. package/dist/_chunks/actions-jNrXdzgs.js.map +0 -1
  494. package/dist/_chunks/als-registry-C6kcfprT.js.map +0 -1
  495. package/dist/_chunks/build-manifest-DTmSGLRz.js.map +0 -1
  496. package/dist/_chunks/build-output-helper-9dqCv1pZ.js.map +0 -1
  497. package/dist/_chunks/cache-api-CUD9Ezaq.js.map +0 -1
  498. package/dist/_chunks/cli-check-G8o30ldg.js.map +0 -1
  499. package/dist/_chunks/convention-lint-5KzoMg_A.js.map +0 -1
  500. package/dist/_chunks/dev-server-BzBxgYAV.js.map +0 -1
  501. package/dist/_chunks/error-boundary-BndF-3Td.js.map +0 -1
  502. package/dist/_chunks/fs-identity-D7vb6GdI.js.map +0 -1
  503. package/dist/_chunks/graph-cache-CP4GEmf9.js.map +0 -1
  504. package/dist/_chunks/json-lossy-check-ClNvBM_3.js.map +0 -1
  505. package/dist/_chunks/logger-k2DQ4EUf.js.map +0 -1
  506. package/dist/_chunks/navigation-context-D0TU0Jog.js.map +0 -1
  507. package/dist/_chunks/plugin-context-8idfR3UZ.js.map +0 -1
  508. package/dist/_chunks/primitives-DLAnvsrk.js.map +0 -1
  509. package/dist/_chunks/segment-context-D9_89u34.js +0 -34
  510. package/dist/_chunks/segment-context-D9_89u34.js.map +0 -1
  511. package/dist/_chunks/sizeof-lXffQ1Vr.js.map +0 -1
  512. package/dist/_chunks/ssr-data-D6T6Y3ef.js +0 -60
  513. package/dist/_chunks/ssr-data-D6T6Y3ef.js.map +0 -1
  514. package/dist/_chunks/state-FippDgxN.js.map +0 -1
  515. package/dist/_chunks/status-page-marker-DwQBrLBz.js.map +0 -1
  516. package/dist/client/types.d.ts +0 -14
  517. package/dist/client/types.d.ts.map +0 -1
  518. package/dist/plugins/adapter-build.d.ts +0 -38
  519. package/dist/plugins/adapter-build.d.ts.map +0 -1
  520. package/dist/server/asset-headers.d.ts +0 -32
  521. package/dist/server/asset-headers.d.ts.map +0 -1
  522. package/dist/server/dev-source-map.d.ts +0 -22
  523. package/dist/server/dev-source-map.d.ts.map +0 -1
  524. package/src/client/types.ts +0 -21
  525. package/src/server/asset-headers.ts +0 -59
  526. package/src/server/dev-source-map.ts +0 -31
@@ -14,29 +14,30 @@
14
14
 
15
15
  import type { ClientBootstrapConfig } from '../html-injectors.ts';
16
16
  import { flightInitScript } from '../flight-scripts.ts';
17
- import { getCspNonce, nonceAttr } from '../csp-nonce.ts';
17
+ import { getCspNonce } from '../csp-nonce.ts';
18
+ import { nonceAttr } from '../render-utils.ts';
18
19
  import { appVisibleSearch } from '../../shared/rsc-cache-key.ts';
19
- import { getSlotParamsForClient } from '../request-context.ts';
20
20
  import type { LayoutEntry } from '../deny-renderer.ts';
21
- import { renderDenyPage } from '../deny-renderer.ts';
22
21
  import type { RouteMatch } from '../pipeline.ts';
23
- import { isSsrStreamError } from '../primitives.ts';
22
+ import { isSsrStreamError } from '../signal-identity.ts';
24
23
  import type { LayoutComponentEntry } from '../route-element-builder.ts';
25
24
  import type { ManifestSegmentNode } from '../route-matcher.ts';
26
25
  import type { SlotSkipEntry } from '../slot-resolver.ts';
27
- import type { NavContext } from '../ssr-bridge-types.ts';
26
+ import type { NavContext, SsrRenderResult } from '../ssr-bridge-types.ts';
28
27
 
29
28
  import { htmlEscapeJsonString } from '../flight-scripts.ts';
30
- import { buildRedirectResponse, buildSegmentInfo, isAbortError } from './helpers.ts';
29
+ import { buildSegmentInfo, isAbortError } from './helpers.ts';
31
30
  import { getCookiesForSsr } from '../cookie-context.ts';
32
31
  import { getDenyStatus, getFirstDeniedSegmentIndex } from '../deny-boundary.ts';
33
32
  import { renderErrorPage, type GlobalErrorFile } from './error-renderer.ts';
34
33
  import { callSsr } from './ssr-bridge.ts';
35
- import type { RenderSignals } from './rsc-stream.ts';
34
+ import type { RenderSignals } from './render-signals.ts';
35
+ import type { DenySignal, RedirectSignal } from '../primitives.ts';
36
36
  import { recordTiming } from '../server-timing.ts';
37
37
  import { teeWithErrorPropagation } from '../stream-utils.ts';
38
38
  import { addSpanEventSync } from '../tracing.ts';
39
39
  import { isDevMode } from '../debug.ts';
40
+ import { swallow } from '../logger.ts';
40
41
 
41
42
  /**
42
43
  * Maximum number of queueMicrotask yields during signal promotion.
@@ -75,7 +76,7 @@ export const __test_only_signalPromotionDepth: { value: number } = { value: 0 };
75
76
  * Test-only observable: true when the promotion loop hit the cap without
76
77
  * capturing a signal (the silent-miss path — state 3 in TIM-970). False
77
78
  * when the loop captured a signal at any depth, when it was skipped via
78
- * `_fizzAllReadyResolved`, or when no signal was ever expected at a depth
79
+ * `fizzAllReadyResolved`, or when no signal was ever expected at a depth
79
80
  * shallower than the cap.
80
81
  *
81
82
  * Pairs with `__test_only_signalPromotionDepth`: depth alone cannot
@@ -112,13 +113,18 @@ interface SsrRenderOptions {
112
113
  * SSR will attempt to render the element tree progressively. Two outcomes:
113
114
  *
114
115
  * 1. deny() outside Suspense: the error appears in the RSC shell. SSR's
115
- * renderToReadableStream fails (rejects). We catch the failure, check
116
- * denySignal, and render the deny page with the correct status code.
116
+ * renderToReadableStream fails (rejects). We catch the failure, find
117
+ * the captured denySignal, and rethrow it to the pipeline.
117
118
  *
118
119
  * 2. deny() inside Suspense: the SSR shell succeeds (200 committed). The
119
120
  * error streams into the connection as a React error boundary. The
120
121
  * status is already committed — per design/05-streaming.md this is the
121
122
  * expected degraded behavior for deny inside Suspense.
123
+ *
124
+ * @throws the captured `DenySignal` or `RedirectSignal` when one decides the
125
+ * response. `runRenderPhase()` turns it into a `deny` / `redirect` outcome,
126
+ * and the pipeline renders the deny page or builds the redirect, exactly as
127
+ * for a signal thrown out of render (design/49 §"C").
122
128
  */
123
129
  export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Response> {
124
130
  const {
@@ -154,27 +160,12 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
154
160
  [ssrStream, inlineStream] = teeWithErrorPropagation(rscStream);
155
161
  }
156
162
 
157
- // Wire an AbortController so the Flight injector stops writing <script>
158
- // tags when an unhandled RSC error is detected. Without this, React's
159
- // Flight encoder may write model data for a chunk that already received
160
- // an error row, causing the client's Flight decoder to crash with
161
- // "enqueueModel is not a function". See TIM-938.
162
- const errorAbort = new AbortController();
163
- signals.onUnhandledError = () => errorAbort.abort();
164
-
165
163
  // Segment metadata for initial hydration: deferred to shell-flush time.
166
164
  // The SSR entry invokes this thunk AFTER renderSsrNodeStream /
167
165
  // renderSsrStream returns (shell ready ⇒ AccessGates settled), so
168
166
  // getFirstDeniedSegmentIndex() returns the authoritative ALS value
169
167
  // rather than the pre-render Infinity. See TIM-1365, TIM-1359.
170
168
 
171
- // Params reach the browser inside the payload — a field on the root row of
172
- // the same Flight stream that is inlined for hydration. SSR itself renders
173
- // only the tree, and the client components it renders read params from the
174
- // ALS context seeded below, which is also where server components answer
175
- // `getSegmentParams(slotPath)` from.
176
- const slotParams = getSlotParamsForClient();
177
-
178
169
  // Middleware has already run; if it read `ctx.nonce` for its CSP header,
179
170
  // that is the value every inline script must wear.
180
171
  const nonce = getCspNonce();
@@ -183,8 +174,6 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
183
174
  const navContext: NavContext = {
184
175
  pathname: reqUrl.pathname,
185
176
  search: appVisibleSearch(reqUrl).search,
186
- segmentParams: match.segmentParams,
187
- slotParams,
188
177
  statusCode: 200,
189
178
  responseHeaders,
190
179
  headHtml:
@@ -204,256 +193,71 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
204
193
  deferSuspenseFor: deferSuspenseFor > 0 ? deferSuspenseFor : undefined,
205
194
  signal: req.signal,
206
195
  cookies: getCookiesForSsr(),
207
- _errorSignal: errorAbort.signal,
196
+ // Stops the Flight injector writing <script> tags once an unhandled RSC
197
+ // error is captured. Without this, React's Flight encoder may write model
198
+ // data for a chunk that already received an error row, causing the
199
+ // client's Flight decoder to crash with "enqueueModel is not a
200
+ // function". See TIM-938.
201
+ _errorSignal: signals.unhandledError,
208
202
  };
209
203
 
210
- // Helper: check if render-phase signals were captured and return the
211
- // appropriate HTTP response. Used after both successful SSR (signal
212
- // promotion from Suspense) and failed SSR (signal outside Suspense).
204
+ // The signal a render captured, if any. Used after both successful SSR
205
+ // (signal promotion from Suspense) and failed SSR (signal outside Suspense).
206
+ // A captured deny or redirect is reported, not rendered: callers cancel the
207
+ // streams this render holds and rethrow it, and runRenderPhase() turns it
208
+ // into the same `deny` / `redirect` outcome a thrown signal becomes, so
209
+ // the pipeline's deny fallback and redirect builder answer it (design/49
210
+ // §"C"). Redirect wins over deny, as it always has.
213
211
  //
214
- // When `skipHandledDeny` is true (SSR success path), skip DenySignal
215
- // re-render if the denial was already handled by a TimberErrorBoundary.
216
- // The boundary renders the deny page as its fallback AND sets the correct
217
- // HTTP status code on navContext — no redundant renderDenyPage() needed.
218
- // See TIM-664, LOCAL-298.
219
- // Read the denied segment index from ALS — set by AccessGate during render
220
- // (setFirstDeniedSegmentIndex). See TIM-1358, TIM-1365.
221
- function resolvedDeniedIndex(): number {
222
- return getFirstDeniedSegmentIndex();
223
- }
224
-
225
- function checkCapturedSignals(skipHandledDeny = false): Response | Promise<Response> | null {
226
- if (signals.redirectSignal) {
227
- return buildRedirectResponse(signals.redirectSignal, req, responseHeaders);
228
- }
229
- if (signals.denySignal && !(skipHandledDeny && navContext._denyHandledByBoundary)) {
230
- // Deny was not handled by an in-tree error boundary.
231
- // Fall back to renderDenyPage (separate React.cache scope).
232
- // For single-render behavior, add a 'use client' status-code file
233
- // (e.g., 4xx.tsx) — the error boundary handles it in-tree.
234
- return renderDenyPage(
235
- signals.denySignal,
236
- segments,
237
- layoutComponents as LayoutEntry[],
238
- req,
239
- match,
240
- responseHeaders,
241
- clientBootstrap,
242
- callSsr,
243
- undefined,
244
- resolvedDeniedIndex()
245
- );
246
- }
247
- if (signals.renderError) {
248
- return renderErrorPage(
249
- signals.renderError.error,
250
- signals.renderError.status,
251
- segments,
252
- layoutComponents as LayoutEntry[],
253
- req,
254
- match,
255
- responseHeaders,
256
- clientBootstrap,
257
- globalError,
258
- resolvedDeniedIndex()
259
- );
260
- }
261
- return null;
212
+ // A signal the detection phase below saw arrive past the promotion cap is
213
+ // discarded rather than promoted; this flag records that without writing
214
+ // into the producer's signals.
215
+ let detectionConfirmedLateSignal = false;
216
+ function capturedSignal(): RedirectSignal | DenySignal | null {
217
+ if (detectionConfirmedLateSignal) return null;
218
+ return signals.redirectSignal ?? signals.denySignal;
262
219
  }
263
220
 
221
+ // Only the SSR call is guarded: everything after it runs on a document
222
+ // SSR produced, and a captured signal rethrown there must reach
223
+ // runRenderPhase() rather than this renderer's own failure handling.
224
+ let ssr: SsrRenderResult;
264
225
  try {
265
- const ssrResponse = await callSsr(ssrStream, navContext);
266
-
267
- // Record SSR sub-phase timings for Server-Timing header (detailed mode).
268
- // These are populated by handleSsr() in the SSR environment and passed
269
- // back via navContext._ssrTimings across the RSC→SSR boundary.
270
- if (navContext._ssrTimings) {
271
- const t = navContext._ssrTimings;
272
- recordTiming({ name: 'ssr-decode', dur: t.decodeMs, desc: 'RSC Flight decode' });
273
- recordTiming({ name: 'ssr-shell', dur: t.shellMs, desc: 'Fizz onShellReady' });
274
- recordTiming({ name: 'ssr-pipeline', dur: t.pipelineMs, desc: 'stream transforms' });
275
- recordTiming({
276
- name: 'ssr-total',
277
- dur: t.totalMs,
278
- desc: t.nodeStreams ? 'SSR (Node streams)' : 'SSR (Web Streams)',
279
- });
280
- }
281
-
282
- // Signal promotion: check if any signals were captured during rendering
283
- // inside Suspense boundaries. If no signals are present yet, we may
284
- // need to yield microtasks so async component rejections propagate
285
- // through the full rejection chain to the RSC onError callback before
286
- // we commit the response.
287
- //
288
- // Option 1 short-circuit: when Fizz's `stream.allReady` settled before
289
- // the `deferSuspenseFor` hold ended (navContext._fizzAllReadyResolved),
290
- // Flight has closed its stream, every `onError` already fired, and the
291
- // signals object is fully populated. The retry loop would be a no-op.
292
- // See design/spike-signal-promotion-protocol.md §"Option 1".
293
- //
294
- // Fallback path (hold timed out, no hold window, or shell-only return):
295
- // the known rejection chain depth for a withSpan-wrapped page is 3+
296
- // microtasks —
297
- // 1. PageComponent throws DenySignal/RedirectSignal
298
- // 2. withSpan catches and re-throws (microtask 1)
299
- // 3. TracedPage promise rejects (microtask 2)
300
- // 4. React Flight rejection handler → onError (microtask 3+)
301
- // so a bounded retry loop (max 5) is required to catch signals whose
302
- // propagation is still in-flight when callSsr returns. The loop exits
303
- // early as soon as a signal is detected. Uses queueMicrotask instead
304
- // of setTimeout(0) to avoid yielding to the full event loop.
305
- // See design/05-streaming.md §"deferSuspenseFor and the Hold Window"
306
- if (!signals.redirectSignal && !signals.denySignal && !signals.renderError) {
307
- let yieldsConsumed = 0;
308
- let detectionConfirmedLateSignal = false;
309
- if (!navContext._fizzAllReadyResolved) {
310
- // Promotion phase: bounded cap of SIGNAL_PROMOTION_MAX_YIELDS.
311
- // Signals captured here are honored by checkCapturedSignals and
312
- // become the response (redirect/deny/error page).
313
- for (let i = 0; i < SIGNAL_PROMOTION_MAX_YIELDS; i++) {
314
- await new Promise<void>((r) => queueMicrotask(r));
315
- yieldsConsumed++;
316
- if (signals.redirectSignal || signals.denySignal || signals.renderError) break;
317
- }
318
-
319
- // Detection phase (TIM-970): if the promotion cap was hit without
320
- // capturing a signal, yield a few more times to disambiguate state 2
321
- // ("no signal was ever coming" — the common legitimate-200 case) from
322
- // state 3 ("signal arrived one microtask past the cap" — the silent
323
- // miss). Telemetry-only: if a late signal is observed it triggers
324
- // the warning and span event but is NOT promoted. Promoting it would
325
- // effectively raise the cap to MAX_YIELDS + DETECTION_EXTRA_YIELDS,
326
- // which the ticket defers to the E.2 investigation. The signals are
327
- // cleared so checkCapturedSignals does not pick them up.
328
- if (
329
- yieldsConsumed === SIGNAL_PROMOTION_MAX_YIELDS &&
330
- !signals.redirectSignal &&
331
- !signals.denySignal &&
332
- !signals.renderError
333
- ) {
334
- for (let i = 0; i < SIGNAL_PROMOTION_DETECTION_EXTRA_YIELDS; i++) {
335
- await new Promise<void>((r) => queueMicrotask(r));
336
- if (signals.redirectSignal || signals.denySignal || signals.renderError) {
337
- detectionConfirmedLateSignal = true;
338
- signals.redirectSignal = null;
339
- signals.denySignal = null;
340
- signals.renderError = null;
341
- break;
342
- }
343
- }
344
- }
345
- }
346
- __test_only_signalPromotionDepth.value = yieldsConsumed;
347
- __test_only_signalPromotionCapHit.value = detectionConfirmedLateSignal;
348
-
349
- if (detectionConfirmedLateSignal) {
350
- if (isDevMode()) {
351
- console.warn(
352
- `[timber] Signal promotion cap reached (${SIGNAL_PROMOTION_MAX_YIELDS} microtask yields) — a deny()/redirect()/renderError signal arrived just past the cap and was discarded. ` +
353
- `Likely cause: a page using deny()/redirect() inside a deeply-wrapped async component (custom withSpan, decorators, etc.). ` +
354
- `Simplify the async chain or reduce withSpan/wrapper depth. ` +
355
- `See design/05-streaming.md §"Signal Promotion".`
356
- );
357
- }
358
- addSpanEventSync('timber.ssr.signal_promotion_cap_reached', {
359
- depth: SIGNAL_PROMOTION_MAX_YIELDS,
360
- signal_types_checked: 'redirect,deny,renderError',
361
- });
362
- }
363
- }
364
-
365
- const promoted = checkCapturedSignals(/* skipHandledDeny */ true);
366
- if (promoted) {
367
- ssrResponse.body?.cancel();
368
- return promoted;
369
- }
370
-
371
- // Check if a DenySignal was caught in-tree by AccessGate or
372
- // PageDenyBoundary. The deny page was rendered as a normal element
373
- // (no error in the Flight stream), so SSR succeeded with status 200.
374
- // Override the status code from the ALS-stored deny status. See TIM-666.
375
- const denyStatus = getDenyStatus();
376
- if (denyStatus) {
377
- return new Response(ssrResponse.body, {
378
- status: denyStatus,
379
- headers: ssrResponse.headers,
380
- });
381
- }
382
-
383
- return ssrResponse;
226
+ ssr = await callSsr(ssrStream, navContext);
384
227
  } catch (ssrError) {
228
+ // SSR failed, so nothing will read the teed inline stream: every answer
229
+ // below renders its own streams or none. Without explicit cancellation
230
+ // the orphaned tee branch keeps the RSC source stream alive, preventing
231
+ // garbage collection — so release it before anything returns or throws.
232
+ inlineStream
233
+ ?.cancel()
234
+ .catch((err: unknown) => swallow(err, 'orphaned RSC inline stream did not cancel'));
235
+
385
236
  // Connection abort — the client disconnected (page refresh, navigation
386
237
  // away). No response needed; return empty 499 (client closed request).
387
238
  if (isAbortError(ssrError) || req.signal?.aborted) {
388
- inlineStream?.cancel().catch(() => {});
389
239
  return new Response(null, { status: 499 });
390
240
  }
391
241
 
392
- // SsrStreamError: SSR's renderToReadableStream failed because the RSC
393
- // stream contained an uncontained error (e.g., slot without error boundary).
394
- //
395
- // Error pages now use SSR-only rendering (Fizz directly, no RSC Flight),
396
- // which imports layouts in the SSR environment where ALS is active. This
397
- // means we CAN include layouts — they'll call getHeaders()/getCookies() correctly.
242
+ // A captured signal explains the failure, whichever shape it took: the
243
+ // signal was in the shell, outside any Suspense boundary.
244
+ const signal = capturedSignal();
245
+ if (signal) throw signal;
246
+
247
+ // SsrStreamError with no captured signal: SSR's renderToReadableStream
248
+ // failed because the RSC stream contained an uncontained error (e.g., a
249
+ // slot without an error boundary).
398
250
  //
399
- // Deny pages still go through RSC → SSR (plain props), so they pass empty
400
- // layouts to avoid re-executing server components in the RSC environment's
401
- // stale ALS scope. See LOCAL-293.
402
251
  // SsrStreamError is thrown in the SSR environment but caught here in
403
252
  // RSC — separate Vite module graphs, so `instanceof` can never match.
404
253
  // isSsrStreamError() checks the Symbol.for brand instead. See
405
254
  // design/18-build-system.md §"Dev Mode: Signal Identity Across Program Reloads".
406
255
  if (isSsrStreamError(ssrError)) {
407
- // Cancel the teed inline stream — SSR failed so this response will
408
- // be replaced by renderErrorPage which creates its own clean streams.
409
- // Without explicit cancellation the orphaned tee branch keeps the
410
- // RSC source stream alive, preventing garbage collection.
411
- inlineStream?.cancel().catch(() => {});
412
-
413
- if (signals.redirectSignal) {
414
- return buildRedirectResponse(signals.redirectSignal, req, responseHeaders);
415
- }
416
- if (signals.denySignal) {
417
- // SSR failed (SsrStreamError) — the deny was in the shell and
418
- // the error boundary didn't catch it during Fizz rendering.
419
- // Fall back to renderDenyPage (separate render). See TIM-664.
420
- return renderDenyPage(
421
- signals.denySignal,
422
- segments,
423
- layoutComponents as LayoutEntry[],
424
- req,
425
- match,
426
- responseHeaders,
427
- clientBootstrap,
428
- callSsr,
429
- undefined,
430
- resolvedDeniedIndex()
431
- );
432
- }
433
- if (signals.renderError) {
434
- // RenderError: TSX error pages use SSR-only path (layouts OK),
435
- // MDX error pages use RSC path (plain props, no Error object).
436
- return renderErrorPage(
437
- signals.renderError.error,
438
- signals.renderError.status,
439
- segments,
440
- layoutComponents as LayoutEntry[],
441
- req,
442
- match,
443
- responseHeaders,
444
- clientBootstrap,
445
- globalError,
446
- resolvedDeniedIndex()
447
- );
448
- }
449
- // No captured signal — unhandled error in the RSC stream.
450
- // Use the lastUnhandledError from RSC onError if available (more
451
- // reliable than extracting SsrStreamError.cause). Falls back to
452
- // cause extraction for backward compatibility.
453
- const originalError =
454
- signals.lastUnhandledError ?? (ssrError as { cause?: unknown }).cause ?? ssrError;
256
+ // The cause is the error Flight relayed for the row that failed the
257
+ // shell — not the last error the RSC render reported, which may be one
258
+ // a Suspense boundary contained (TIM-1552).
455
259
  return renderErrorPage(
456
- originalError,
260
+ ssrError.cause ?? ssrError,
457
261
  500,
458
262
  segments,
459
263
  layoutComponents as LayoutEntry[],
@@ -462,16 +266,131 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
462
266
  responseHeaders,
463
267
  clientBootstrap,
464
268
  globalError,
465
- resolvedDeniedIndex()
269
+ getFirstDeniedSegmentIndex()
466
270
  );
467
271
  }
468
272
 
469
- // SSR shell rendering failed — the error was outside Suspense.
470
- // Check captured signals (redirect, deny, render error).
471
- const signalResponse = checkCapturedSignals();
472
- if (signalResponse) return signalResponse;
473
-
474
273
  // No tracked error — rethrow (infrastructure failure)
475
274
  throw ssrError;
476
275
  }
276
+
277
+ const { response: ssrResponse, timings: t, fizzAllReadyResolved } = ssr;
278
+
279
+ // Record SSR sub-phase timings for the Server-Timing header. recordTiming
280
+ // is a no-op outside a detailed-mode timing collector.
281
+ recordTiming({ name: 'ssr-decode', dur: t.decodeMs, desc: 'RSC Flight decode' });
282
+ recordTiming({ name: 'ssr-shell', dur: t.shellMs, desc: 'Fizz onShellReady' });
283
+ recordTiming({ name: 'ssr-pipeline', dur: t.pipelineMs, desc: 'stream transforms' });
284
+ recordTiming({
285
+ name: 'ssr-total',
286
+ dur: t.totalMs,
287
+ desc: t.nodeStreams ? 'SSR (Node streams)' : 'SSR (Web Streams)',
288
+ });
289
+
290
+ // Signal promotion: check if any signals were captured during rendering
291
+ // inside Suspense boundaries. If no signals are present yet, we may
292
+ // need to yield microtasks so async component rejections propagate
293
+ // through the full rejection chain to the RSC onError callback before
294
+ // we commit the response.
295
+ //
296
+ // Option 1 short-circuit: when Fizz's `stream.allReady` settled before
297
+ // the `deferSuspenseFor` hold ended (`fizzAllReadyResolved`),
298
+ // Flight has closed its stream, every `onError` already fired, and the
299
+ // signals object is fully populated. The retry loop would be a no-op.
300
+ // See design/spike-signal-promotion-protocol.md §"Option 1".
301
+ //
302
+ // Fallback path (hold timed out, no hold window, or shell-only return):
303
+ // the known rejection chain depth for a withSpan-wrapped page is 3+
304
+ // microtasks —
305
+ // 1. PageComponent throws DenySignal/RedirectSignal
306
+ // 2. withSpan catches and re-throws (microtask 1)
307
+ // 3. TracedPage promise rejects (microtask 2)
308
+ // 4. React Flight rejection handler → onError (microtask 3+)
309
+ // so a bounded retry loop (max 5) is required to catch signals whose
310
+ // propagation is still in-flight when callSsr returns. The loop exits
311
+ // early as soon as a signal is detected. Uses queueMicrotask instead
312
+ // of setTimeout(0) to avoid yielding to the full event loop.
313
+ // See design/05-streaming.md §"deferSuspenseFor and the Hold Window"
314
+ if (!capturedSignal()) {
315
+ let yieldsConsumed = 0;
316
+ if (!fizzAllReadyResolved) {
317
+ // Promotion phase: bounded cap of SIGNAL_PROMOTION_MAX_YIELDS.
318
+ // A signal captured here is rethrown below and becomes the
319
+ // response (redirect or deny page).
320
+ for (let i = 0; i < SIGNAL_PROMOTION_MAX_YIELDS; i++) {
321
+ await new Promise<void>((r) => queueMicrotask(r));
322
+ yieldsConsumed++;
323
+ if (capturedSignal()) break;
324
+ }
325
+
326
+ // Detection phase (TIM-970): if the promotion cap was hit without
327
+ // capturing a signal, yield a few more times to disambiguate state 2
328
+ // ("no signal was ever coming" — the common legitimate-200 case) from
329
+ // state 3 ("signal arrived one microtask past the cap" — the silent
330
+ // miss). Telemetry-only: if a late signal is observed it triggers
331
+ // the warning and span event but is NOT promoted. Promoting it would
332
+ // effectively raise the cap to MAX_YIELDS + DETECTION_EXTRA_YIELDS,
333
+ // which the ticket defers to the E.2 investigation. Setting
334
+ // detectionConfirmedLateSignal keeps capturedSignal() from picking
335
+ // them up.
336
+ //
337
+ // The signal is discarded, but a late deny's status still applies: an
338
+ // in-tree catch site that hoisted it recorded the status before
339
+ // rethrowing (handleCaughtDeny), so the getDenyStatus() override below
340
+ // serves this document with the deny's 4xx. A late deny that no status
341
+ // file matched recorded nothing and stays a 200, as does any deny that
342
+ // lands after this window — the override is read once, below.
343
+ if (yieldsConsumed === SIGNAL_PROMOTION_MAX_YIELDS && !capturedSignal()) {
344
+ for (let i = 0; i < SIGNAL_PROMOTION_DETECTION_EXTRA_YIELDS; i++) {
345
+ await new Promise<void>((r) => queueMicrotask(r));
346
+ if (capturedSignal()) {
347
+ detectionConfirmedLateSignal = true;
348
+ break;
349
+ }
350
+ }
351
+ }
352
+ }
353
+ __test_only_signalPromotionDepth.value = yieldsConsumed;
354
+ __test_only_signalPromotionCapHit.value = detectionConfirmedLateSignal;
355
+
356
+ if (detectionConfirmedLateSignal) {
357
+ if (isDevMode()) {
358
+ console.warn(
359
+ `[timber] Signal promotion cap reached (${SIGNAL_PROMOTION_MAX_YIELDS} microtask yields) — a deny()/redirect() signal arrived just past the cap and was discarded. ` +
360
+ `Likely cause: a page using deny()/redirect() inside a deeply-wrapped async component (custom withSpan, decorators, etc.). ` +
361
+ `Simplify the async chain or reduce withSpan/wrapper depth. ` +
362
+ `See design/05-streaming.md §"Signal Promotion".`
363
+ );
364
+ }
365
+ addSpanEventSync('timber.ssr.signal_promotion_cap_reached', {
366
+ depth: SIGNAL_PROMOTION_MAX_YIELDS,
367
+ signal_types_checked: 'redirect,deny',
368
+ });
369
+ }
370
+ }
371
+
372
+ // A captured signal replaces this document, so its body is never read.
373
+ const promoted = capturedSignal();
374
+ if (promoted) {
375
+ ssrResponse.body
376
+ ?.cancel()
377
+ .catch((err: unknown) => swallow(err, 'discarded SSR document body did not cancel'));
378
+ throw promoted;
379
+ }
380
+
381
+ // Check if a DenySignal was caught in-tree by AccessGate or
382
+ // PageDenyBoundary. The deny page was rendered as a normal element
383
+ // (no error in the Flight stream), so SSR succeeded with status 200.
384
+ // Override the status code from the ALS-stored deny status. See TIM-666.
385
+ // A hoisted deny whose signal arrived past the promotion cap lands here
386
+ // too, with the status its catch site recorded (see the detection phase).
387
+ const denyStatus = getDenyStatus();
388
+ if (denyStatus) {
389
+ return new Response(ssrResponse.body, {
390
+ status: denyStatus,
391
+ headers: ssrResponse.headers,
392
+ });
393
+ }
394
+
395
+ return ssrResponse;
477
396
  }
@@ -30,10 +30,10 @@
30
30
  import type { FormRerender } from '../action-handler.ts';
31
31
  import { handleActionRequest, isActionRequest } from '../action-handler.ts';
32
32
  import type { BodyLimitsConfig } from '../body-limits.ts';
33
- import { validateCsrf, type CsrfConfig } from '../csrf.ts';
33
+ import { validateCsrf, csrfRejectionResponse, type CsrfConfig } from '../csrf.ts';
34
34
  import { runWithFormFlash } from '../form-flash.ts';
35
- import { seedRequestCookies } from '../cookie-context.ts';
36
35
  import type { RouteMatcher } from '../pipeline.ts';
36
+ import { isApiRouteChain } from '../route-matcher.ts';
37
37
  import type { SensitiveFieldsOption } from '../sensitive-fields.ts';
38
38
  import type { RevalidateRenderer } from '../actions.ts';
39
39
 
@@ -95,7 +95,7 @@ export function wrapPipelineWithActionDispatch(
95
95
  // Runs on EVERY unsafe-method request, before any dispatch decision.
96
96
  const csrfResult = validateCsrf(req, deps.csrfConfig);
97
97
  if (!csrfResult.ok) {
98
- return new Response(null, { status: csrfResult.status });
98
+ return csrfRejectionResponse(req, csrfResult);
99
99
  }
100
100
 
101
101
  return pipeline(req);
@@ -120,12 +120,12 @@ export function buildActionDispatcher(
120
120
  ): (
121
121
  req: Request,
122
122
  canonicalPath: string,
123
- reenter: (req: Request) => Promise<Response>
123
+ reenter: (req: Request, cookies: Map<string, string>) => Promise<Response>
124
124
  ) => Promise<Response | null> {
125
125
  return async (
126
126
  req: Request,
127
127
  canonicalPath: string,
128
- reenter: (req: Request) => Promise<Response>
128
+ reenter: (req: Request, cookies: Map<string, string>) => Promise<Response>
129
129
  ): Promise<Response | null> => {
130
130
  if (!isActionRequest(req)) return null;
131
131
 
@@ -138,11 +138,8 @@ export function buildActionDispatcher(
138
138
  // which re-encodes the path. The matcher expects the decoded canonical form.
139
139
  if (deps.matchRoute) {
140
140
  const match = deps.matchRoute(canonicalPath);
141
- if (match) {
142
- const leaf = match.segments[match.segments.length - 1];
143
- if (leaf?.route) {
144
- return null;
145
- }
141
+ if (match && isApiRouteChain(match.segments)) {
142
+ return null;
146
143
  }
147
144
  }
148
145
 
@@ -161,8 +158,8 @@ export function buildActionDispatcher(
161
158
  // Build a synthetic GET request for the rerender pipeline:
162
159
  // - Same URL (so route matching lands on the same page)
163
160
  // - Cookie header DROPPED entirely. The post-action RYW state
164
- // is threaded into the rerender request context as a parsed
165
- // `Map<string, string>` via `seedRequestCookies` below.
161
+ // is handed to `reenter` as a parsed `Map<string, string>`,
162
+ // which becomes the rerender request context's cookies.
166
163
  // - Method GET because the rerender is conceptually a page render.
167
164
  const rerenderHeaders = new Headers(req.headers);
168
165
  rerenderHeaders.delete('cookie');
@@ -170,8 +167,9 @@ export function buildActionDispatcher(
170
167
  method: 'GET',
171
168
  headers: rerenderHeaders,
172
169
  });
173
- seedRequestCookies(rerenderReq, formRerender.cookies);
174
- const response = await runWithFormFlash(formRerender.rerender, () => reenter(rerenderReq));
170
+ const response = await runWithFormFlash(formRerender.rerender, () =>
171
+ reenter(rerenderReq, formRerender.cookies)
172
+ );
175
173
  // Apply Set-Cookie headers snapshotted from the action's ALS scope.
176
174
  for (const value of formRerender.setCookieHeaders) {
177
175
  response.headers.append('Set-Cookie', value);