@timber-js/app 0.2.0-alpha.6 → 0.2.0-alpha.61

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 (406) hide show
  1. package/LICENSE +8 -0
  2. package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-Ba7URUIn.js} +1 -1
  3. package/dist/_chunks/als-registry-Ba7URUIn.js.map +1 -0
  4. package/dist/_chunks/chunk-DYhsFzuS.js +33 -0
  5. package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
  6. package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
  7. package/dist/_chunks/define-CT98cU9c.js +121 -0
  8. package/dist/_chunks/define-CT98cU9c.js.map +1 -0
  9. package/dist/_chunks/define-TK8C1M3x.js +279 -0
  10. package/dist/_chunks/define-TK8C1M3x.js.map +1 -0
  11. package/dist/_chunks/define-cookie-BWr_52kY.js +93 -0
  12. package/dist/_chunks/define-cookie-BWr_52kY.js.map +1 -0
  13. package/dist/_chunks/error-boundary-DpZJBCqh.js +211 -0
  14. package/dist/_chunks/error-boundary-DpZJBCqh.js.map +1 -0
  15. package/dist/_chunks/{format-DviM89f0.js → format-cX7wzEp2.js} +2 -2
  16. package/dist/_chunks/{format-DviM89f0.js.map → format-cX7wzEp2.js.map} +1 -1
  17. package/dist/_chunks/{interception-BOoWmLUA.js → interception-Cey5DCGr.js} +129 -77
  18. package/dist/_chunks/interception-Cey5DCGr.js.map +1 -0
  19. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-BU684ls2.js} +1 -1
  20. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-BU684ls2.js.map} +1 -1
  21. package/dist/_chunks/{request-context-DIkVh_jG.js → request-context-rju2rbga.js} +97 -69
  22. package/dist/_chunks/request-context-rju2rbga.js.map +1 -0
  23. package/dist/_chunks/segment-context-CyaM1mrD.js +72 -0
  24. package/dist/_chunks/segment-context-CyaM1mrD.js.map +1 -0
  25. package/dist/_chunks/stale-reload-BSSym1MJ.js +64 -0
  26. package/dist/_chunks/stale-reload-BSSym1MJ.js.map +1 -0
  27. package/dist/_chunks/{tracing-Cwn7697K.js → tracing-VYETCQsg.js} +17 -3
  28. package/dist/_chunks/{tracing-Cwn7697K.js.map → tracing-VYETCQsg.js.map} +1 -1
  29. package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-wEXY2JQB.js} +1 -1
  30. package/dist/_chunks/use-query-states-wEXY2JQB.js.map +1 -0
  31. package/dist/_chunks/wrappers-BaG1bnM3.js +63 -0
  32. package/dist/_chunks/wrappers-BaG1bnM3.js.map +1 -0
  33. package/dist/adapters/compress-module.d.ts.map +1 -1
  34. package/dist/adapters/nitro.d.ts +17 -1
  35. package/dist/adapters/nitro.d.ts.map +1 -1
  36. package/dist/adapters/nitro.js +56 -13
  37. package/dist/adapters/nitro.js.map +1 -1
  38. package/dist/cache/fast-hash.d.ts +22 -0
  39. package/dist/cache/fast-hash.d.ts.map +1 -0
  40. package/dist/cache/index.d.ts +5 -2
  41. package/dist/cache/index.d.ts.map +1 -1
  42. package/dist/cache/index.js +90 -20
  43. package/dist/cache/index.js.map +1 -1
  44. package/dist/cache/register-cached-function.d.ts.map +1 -1
  45. package/dist/cache/singleflight.d.ts +18 -1
  46. package/dist/cache/singleflight.d.ts.map +1 -1
  47. package/dist/cache/timber-cache.d.ts +1 -1
  48. package/dist/cache/timber-cache.d.ts.map +1 -1
  49. package/dist/client/error-boundary.d.ts +10 -1
  50. package/dist/client/error-boundary.d.ts.map +1 -1
  51. package/dist/client/error-boundary.js +1 -125
  52. package/dist/client/error-reconstituter.d.ts +54 -0
  53. package/dist/client/error-reconstituter.d.ts.map +1 -0
  54. package/dist/client/form.d.ts +2 -2
  55. package/dist/client/form.d.ts.map +1 -1
  56. package/dist/client/index.d.ts +3 -2
  57. package/dist/client/index.d.ts.map +1 -1
  58. package/dist/client/index.js +433 -252
  59. package/dist/client/index.js.map +1 -1
  60. package/dist/client/link-pending-store.d.ts +78 -0
  61. package/dist/client/link-pending-store.d.ts.map +1 -0
  62. package/dist/client/link.d.ts +23 -9
  63. package/dist/client/link.d.ts.map +1 -1
  64. package/dist/client/navigation-context.d.ts +2 -2
  65. package/dist/client/navigation-context.d.ts.map +1 -1
  66. package/dist/client/router.d.ts +25 -3
  67. package/dist/client/router.d.ts.map +1 -1
  68. package/dist/client/rsc-fetch.d.ts +36 -2
  69. package/dist/client/rsc-fetch.d.ts.map +1 -1
  70. package/dist/client/segment-cache.d.ts +1 -1
  71. package/dist/client/segment-cache.d.ts.map +1 -1
  72. package/dist/client/segment-context.d.ts +1 -1
  73. package/dist/client/segment-context.d.ts.map +1 -1
  74. package/dist/client/segment-merger.d.ts.map +1 -1
  75. package/dist/client/segment-outlet.d.ts +63 -0
  76. package/dist/client/segment-outlet.d.ts.map +1 -0
  77. package/dist/client/stale-reload.d.ts +15 -0
  78. package/dist/client/stale-reload.d.ts.map +1 -1
  79. package/dist/client/top-loader.d.ts +1 -1
  80. package/dist/client/top-loader.d.ts.map +1 -1
  81. package/dist/client/transition-root.d.ts +1 -1
  82. package/dist/client/transition-root.d.ts.map +1 -1
  83. package/dist/client/use-params.d.ts +3 -3
  84. package/dist/client/use-params.d.ts.map +1 -1
  85. package/dist/client/use-query-states.d.ts +1 -1
  86. package/dist/client/use-query-states.d.ts.map +1 -1
  87. package/dist/codec.d.ts +21 -0
  88. package/dist/codec.d.ts.map +1 -0
  89. package/dist/cookies/define-cookie.d.ts +34 -13
  90. package/dist/cookies/define-cookie.d.ts.map +1 -1
  91. package/dist/cookies/index.js +1 -83
  92. package/dist/fonts/css.d.ts +1 -0
  93. package/dist/fonts/css.d.ts.map +1 -1
  94. package/dist/index.d.ts +127 -35
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +665 -242
  97. package/dist/index.js.map +1 -1
  98. package/dist/params/define.d.ts +100 -0
  99. package/dist/params/define.d.ts.map +1 -0
  100. package/dist/params/index.d.ts +8 -0
  101. package/dist/params/index.d.ts.map +1 -0
  102. package/dist/params/index.js +4 -0
  103. package/dist/plugins/adapter-build.d.ts +1 -1
  104. package/dist/plugins/adapter-build.d.ts.map +1 -1
  105. package/dist/plugins/build-manifest.d.ts +2 -2
  106. package/dist/plugins/build-manifest.d.ts.map +1 -1
  107. package/dist/plugins/build-report.d.ts +3 -3
  108. package/dist/plugins/build-report.d.ts.map +1 -1
  109. package/dist/plugins/client-chunks.d.ts +32 -0
  110. package/dist/plugins/client-chunks.d.ts.map +1 -0
  111. package/dist/plugins/content.d.ts +1 -1
  112. package/dist/plugins/content.d.ts.map +1 -1
  113. package/dist/plugins/dev-browser-logs.d.ts +84 -0
  114. package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
  115. package/dist/plugins/dev-error-overlay.d.ts +26 -1
  116. package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
  117. package/dist/plugins/dev-logs.d.ts +1 -1
  118. package/dist/plugins/dev-logs.d.ts.map +1 -1
  119. package/dist/plugins/dev-server.d.ts +1 -1
  120. package/dist/plugins/dev-server.d.ts.map +1 -1
  121. package/dist/plugins/entries.d.ts +1 -1
  122. package/dist/plugins/entries.d.ts.map +1 -1
  123. package/dist/plugins/fonts.d.ts +9 -2
  124. package/dist/plugins/fonts.d.ts.map +1 -1
  125. package/dist/plugins/mdx.d.ts +1 -1
  126. package/dist/plugins/mdx.d.ts.map +1 -1
  127. package/dist/plugins/routing.d.ts +1 -1
  128. package/dist/plugins/routing.d.ts.map +1 -1
  129. package/dist/plugins/server-bundle.d.ts.map +1 -1
  130. package/dist/plugins/shims.d.ts +6 -5
  131. package/dist/plugins/shims.d.ts.map +1 -1
  132. package/dist/plugins/static-build.d.ts +1 -1
  133. package/dist/plugins/static-build.d.ts.map +1 -1
  134. package/dist/routing/codegen.d.ts +2 -2
  135. package/dist/routing/codegen.d.ts.map +1 -1
  136. package/dist/routing/index.js +1 -1
  137. package/dist/routing/scanner.d.ts.map +1 -1
  138. package/dist/routing/status-file-lint.d.ts +2 -1
  139. package/dist/routing/status-file-lint.d.ts.map +1 -1
  140. package/dist/routing/types.d.ts +16 -4
  141. package/dist/routing/types.d.ts.map +1 -1
  142. package/dist/rsc-runtime/rsc.d.ts +1 -1
  143. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  144. package/dist/rsc-runtime/ssr.d.ts +12 -0
  145. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  146. package/dist/search-params/codecs.d.ts +1 -1
  147. package/dist/search-params/define.d.ts +159 -0
  148. package/dist/search-params/define.d.ts.map +1 -0
  149. package/dist/search-params/index.d.ts +4 -5
  150. package/dist/search-params/index.d.ts.map +1 -1
  151. package/dist/search-params/index.js +4 -474
  152. package/dist/search-params/registry.d.ts +1 -1
  153. package/dist/search-params/wrappers.d.ts +53 -0
  154. package/dist/search-params/wrappers.d.ts.map +1 -0
  155. package/dist/server/access-gate.d.ts +4 -0
  156. package/dist/server/access-gate.d.ts.map +1 -1
  157. package/dist/server/action-client.d.ts.map +1 -1
  158. package/dist/server/action-encryption.d.ts +76 -0
  159. package/dist/server/action-encryption.d.ts.map +1 -0
  160. package/dist/server/action-handler.d.ts.map +1 -1
  161. package/dist/server/actions.d.ts +1 -1
  162. package/dist/server/actions.d.ts.map +1 -1
  163. package/dist/server/als-registry.d.ts +25 -4
  164. package/dist/server/als-registry.d.ts.map +1 -1
  165. package/dist/server/build-manifest.d.ts +2 -2
  166. package/dist/server/build-manifest.d.ts.map +1 -1
  167. package/dist/server/debug.d.ts +1 -1
  168. package/dist/server/default-logger.d.ts +22 -0
  169. package/dist/server/default-logger.d.ts.map +1 -0
  170. package/dist/server/deny-renderer.d.ts.map +1 -1
  171. package/dist/server/early-hints.d.ts +13 -5
  172. package/dist/server/early-hints.d.ts.map +1 -1
  173. package/dist/server/error-boundary-wrapper.d.ts +4 -0
  174. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  175. package/dist/server/fallback-error.d.ts +4 -3
  176. package/dist/server/fallback-error.d.ts.map +1 -1
  177. package/dist/server/flight-injection-state.d.ts +66 -0
  178. package/dist/server/flight-injection-state.d.ts.map +1 -0
  179. package/dist/server/flight-scripts.d.ts +42 -0
  180. package/dist/server/flight-scripts.d.ts.map +1 -0
  181. package/dist/server/flush.d.ts.map +1 -1
  182. package/dist/server/form-data.d.ts +29 -0
  183. package/dist/server/form-data.d.ts.map +1 -1
  184. package/dist/server/html-injectors.d.ts +51 -11
  185. package/dist/server/html-injectors.d.ts.map +1 -1
  186. package/dist/server/index.d.ts +4 -2
  187. package/dist/server/index.d.ts.map +1 -1
  188. package/dist/server/index.js +1977 -1648
  189. package/dist/server/index.js.map +1 -1
  190. package/dist/server/logger.d.ts +25 -7
  191. package/dist/server/logger.d.ts.map +1 -1
  192. package/dist/server/node-stream-transforms.d.ts +113 -0
  193. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  194. package/dist/server/pipeline-interception.d.ts +1 -1
  195. package/dist/server/pipeline-interception.d.ts.map +1 -1
  196. package/dist/server/pipeline.d.ts +20 -6
  197. package/dist/server/pipeline.d.ts.map +1 -1
  198. package/dist/server/primitives.d.ts +30 -3
  199. package/dist/server/primitives.d.ts.map +1 -1
  200. package/dist/server/render-timeout.d.ts +51 -0
  201. package/dist/server/render-timeout.d.ts.map +1 -0
  202. package/dist/server/request-context.d.ts +65 -38
  203. package/dist/server/request-context.d.ts.map +1 -1
  204. package/dist/server/route-element-builder.d.ts +7 -0
  205. package/dist/server/route-element-builder.d.ts.map +1 -1
  206. package/dist/server/route-handler.d.ts.map +1 -1
  207. package/dist/server/route-matcher.d.ts +9 -2
  208. package/dist/server/route-matcher.d.ts.map +1 -1
  209. package/dist/server/rsc-entry/api-handler.d.ts +2 -2
  210. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  211. package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
  212. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  213. package/dist/server/rsc-entry/helpers.d.ts +48 -5
  214. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  215. package/dist/server/rsc-entry/index.d.ts +8 -3
  216. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  217. package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
  218. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  219. package/dist/server/rsc-entry/rsc-stream.d.ts +10 -1
  220. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  221. package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
  222. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  223. package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
  224. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  225. package/dist/server/slot-resolver.d.ts +1 -1
  226. package/dist/server/slot-resolver.d.ts.map +1 -1
  227. package/dist/server/ssr-entry.d.ts +22 -0
  228. package/dist/server/ssr-entry.d.ts.map +1 -1
  229. package/dist/server/ssr-render.d.ts +39 -21
  230. package/dist/server/ssr-render.d.ts.map +1 -1
  231. package/dist/server/ssr-wrappers.d.ts +50 -0
  232. package/dist/server/ssr-wrappers.d.ts.map +1 -0
  233. package/dist/server/status-code-resolver.d.ts +1 -1
  234. package/dist/server/status-code-resolver.d.ts.map +1 -1
  235. package/dist/server/stream-utils.d.ts +36 -0
  236. package/dist/server/stream-utils.d.ts.map +1 -0
  237. package/dist/server/tracing.d.ts +10 -0
  238. package/dist/server/tracing.d.ts.map +1 -1
  239. package/dist/server/tree-builder.d.ts +20 -13
  240. package/dist/server/tree-builder.d.ts.map +1 -1
  241. package/dist/server/types.d.ts +1 -3
  242. package/dist/server/types.d.ts.map +1 -1
  243. package/dist/server/version-skew.d.ts +61 -0
  244. package/dist/server/version-skew.d.ts.map +1 -0
  245. package/dist/server/waituntil-bridge.d.ts.map +1 -1
  246. package/dist/shared/merge-search-params.d.ts +22 -0
  247. package/dist/shared/merge-search-params.d.ts.map +1 -0
  248. package/dist/shims/font-google.d.ts +1 -1
  249. package/dist/shims/font-google.d.ts.map +1 -1
  250. package/dist/shims/navigation-client.d.ts +1 -1
  251. package/dist/shims/navigation-client.d.ts.map +1 -1
  252. package/dist/shims/navigation.d.ts +1 -1
  253. package/dist/shims/navigation.d.ts.map +1 -1
  254. package/dist/utils/state-machine.d.ts +80 -0
  255. package/dist/utils/state-machine.d.ts.map +1 -0
  256. package/package.json +17 -17
  257. package/src/adapters/compress-module.ts +24 -4
  258. package/src/adapters/nitro.ts +58 -9
  259. package/src/cache/fast-hash.ts +34 -0
  260. package/src/cache/index.ts +5 -2
  261. package/src/cache/register-cached-function.ts +7 -3
  262. package/src/cache/singleflight.ts +62 -4
  263. package/src/cache/timber-cache.ts +40 -29
  264. package/src/cli.ts +0 -0
  265. package/src/client/browser-entry.ts +151 -99
  266. package/src/client/error-boundary.tsx +18 -1
  267. package/src/client/error-reconstituter.tsx +65 -0
  268. package/src/client/form.tsx +2 -2
  269. package/src/client/index.ts +10 -1
  270. package/src/client/link-pending-store.ts +136 -0
  271. package/src/client/link.tsx +137 -22
  272. package/src/client/navigation-context.ts +6 -5
  273. package/src/client/router.ts +117 -60
  274. package/src/client/rsc-fetch.ts +90 -2
  275. package/src/client/segment-cache.ts +1 -1
  276. package/src/client/segment-context.ts +6 -1
  277. package/src/client/segment-merger.ts +2 -8
  278. package/src/client/segment-outlet.tsx +86 -0
  279. package/src/client/stale-reload.ts +73 -6
  280. package/src/client/top-loader.tsx +10 -9
  281. package/src/client/transition-root.tsx +20 -2
  282. package/src/client/use-params.ts +4 -4
  283. package/src/client/use-query-states.ts +2 -2
  284. package/src/codec.ts +21 -0
  285. package/src/cookies/define-cookie.ts +71 -20
  286. package/src/fonts/css.ts +2 -1
  287. package/src/index.ts +297 -85
  288. package/src/params/define.ts +327 -0
  289. package/src/params/index.ts +28 -0
  290. package/src/plugins/adapter-build.ts +8 -2
  291. package/src/plugins/build-manifest.ts +13 -2
  292. package/src/plugins/build-report.ts +3 -3
  293. package/src/plugins/cache-transform.ts +1 -1
  294. package/src/plugins/client-chunks.ts +65 -0
  295. package/src/plugins/content.ts +1 -1
  296. package/src/plugins/dev-browser-logs.ts +284 -0
  297. package/src/plugins/dev-error-overlay.ts +70 -1
  298. package/src/plugins/dev-logs.ts +1 -1
  299. package/src/plugins/dev-server.ts +41 -7
  300. package/src/plugins/entries.ts +6 -8
  301. package/src/plugins/fonts.ts +102 -55
  302. package/src/plugins/mdx.ts +1 -1
  303. package/src/plugins/routing.ts +57 -17
  304. package/src/plugins/server-action-exports.ts +1 -1
  305. package/src/plugins/server-bundle.ts +32 -1
  306. package/src/plugins/shims.ts +69 -31
  307. package/src/plugins/static-build.ts +10 -6
  308. package/src/routing/codegen.ts +109 -88
  309. package/src/routing/scanner.ts +86 -7
  310. package/src/routing/status-file-lint.ts +3 -2
  311. package/src/routing/types.ts +17 -4
  312. package/src/rsc-runtime/rsc.ts +2 -0
  313. package/src/rsc-runtime/ssr.ts +50 -0
  314. package/src/rsc-runtime/vendor-types.d.ts +7 -0
  315. package/src/search-params/codecs.ts +1 -1
  316. package/src/search-params/define.ts +518 -0
  317. package/src/search-params/index.ts +12 -18
  318. package/src/search-params/registry.ts +1 -1
  319. package/src/search-params/wrappers.ts +85 -0
  320. package/src/server/access-gate.tsx +40 -9
  321. package/src/server/action-client.ts +8 -2
  322. package/src/server/action-encryption.ts +144 -0
  323. package/src/server/action-handler.ts +20 -3
  324. package/src/server/actions.ts +1 -1
  325. package/src/server/als-registry.ts +25 -4
  326. package/src/server/build-manifest.ts +10 -4
  327. package/src/server/compress.ts +25 -7
  328. package/src/server/debug.ts +1 -1
  329. package/src/server/default-logger.ts +99 -0
  330. package/src/server/deny-renderer.ts +5 -3
  331. package/src/server/early-hints.ts +36 -15
  332. package/src/server/error-boundary-wrapper.ts +58 -15
  333. package/src/server/fallback-error.ts +29 -14
  334. package/src/server/flight-injection-state.ts +113 -0
  335. package/src/server/flight-scripts.ts +62 -0
  336. package/src/server/flush.ts +2 -1
  337. package/src/server/form-data.ts +76 -0
  338. package/src/server/html-injectors.ts +277 -117
  339. package/src/server/index.ts +9 -4
  340. package/src/server/logger.ts +44 -36
  341. package/src/server/node-stream-transforms.ts +509 -0
  342. package/src/server/pipeline-interception.ts +1 -1
  343. package/src/server/pipeline.ts +148 -41
  344. package/src/server/primitives.ts +47 -5
  345. package/src/server/render-timeout.ts +108 -0
  346. package/src/server/request-context.ts +125 -119
  347. package/src/server/route-element-builder.ts +107 -115
  348. package/src/server/route-handler.ts +2 -1
  349. package/src/server/route-matcher.ts +9 -2
  350. package/src/server/rsc-entry/api-handler.ts +8 -8
  351. package/src/server/rsc-entry/error-renderer.ts +286 -81
  352. package/src/server/rsc-entry/helpers.ts +134 -5
  353. package/src/server/rsc-entry/index.ts +177 -76
  354. package/src/server/rsc-entry/rsc-payload.ts +91 -18
  355. package/src/server/rsc-entry/rsc-stream.ts +74 -18
  356. package/src/server/rsc-entry/ssr-bridge.ts +2 -2
  357. package/src/server/rsc-entry/ssr-renderer.ts +152 -34
  358. package/src/server/slot-resolver.ts +231 -220
  359. package/src/server/ssr-entry.ts +211 -32
  360. package/src/server/ssr-render.ts +289 -67
  361. package/src/server/ssr-wrappers.tsx +139 -0
  362. package/src/server/status-code-resolver.ts +1 -1
  363. package/src/server/stream-utils.ts +213 -0
  364. package/src/server/tracing.ts +23 -0
  365. package/src/server/tree-builder.ts +92 -58
  366. package/src/server/types.ts +1 -3
  367. package/src/server/version-skew.ts +104 -0
  368. package/src/server/waituntil-bridge.ts +4 -1
  369. package/src/shared/merge-search-params.ts +55 -0
  370. package/src/shims/font-google.ts +1 -1
  371. package/src/shims/navigation-client.ts +1 -1
  372. package/src/shims/navigation.ts +2 -1
  373. package/src/utils/state-machine.ts +111 -0
  374. package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
  375. package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
  376. package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
  377. package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
  378. package/dist/_chunks/ssr-data-MjmprTmO.js +0 -88
  379. package/dist/_chunks/ssr-data-MjmprTmO.js.map +0 -1
  380. package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
  381. package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
  382. package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
  383. package/dist/client/error-boundary.js.map +0 -1
  384. package/dist/client/link-status-provider.d.ts +0 -11
  385. package/dist/client/link-status-provider.d.ts.map +0 -1
  386. package/dist/cookies/index.js.map +0 -1
  387. package/dist/plugins/dynamic-transform.d.ts +0 -72
  388. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  389. package/dist/search-params/analyze.d.ts +0 -54
  390. package/dist/search-params/analyze.d.ts.map +0 -1
  391. package/dist/search-params/builtin-codecs.d.ts +0 -105
  392. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  393. package/dist/search-params/create.d.ts +0 -106
  394. package/dist/search-params/create.d.ts.map +0 -1
  395. package/dist/search-params/index.js.map +0 -1
  396. package/dist/server/prerender.d.ts +0 -77
  397. package/dist/server/prerender.d.ts.map +0 -1
  398. package/dist/server/response-cache.d.ts +0 -53
  399. package/dist/server/response-cache.d.ts.map +0 -1
  400. package/src/client/link-status-provider.tsx +0 -30
  401. package/src/plugins/dynamic-transform.ts +0 -161
  402. package/src/search-params/analyze.ts +0 -192
  403. package/src/search-params/builtin-codecs.ts +0 -228
  404. package/src/search-params/create.ts +0 -321
  405. package/src/server/prerender.ts +0 -139
  406. package/src/server/response-cache.ts +0 -277
@@ -24,36 +24,38 @@ import buildManifest from 'virtual:timber-build-manifest';
24
24
  // @ts-expect-error — virtual module provided by timber-entries plugin
25
25
  import loadUserInstrumentation from 'virtual:timber-instrumentation';
26
26
 
27
- import type { FormRerender } from '#/server/action-handler.js';
28
- import { handleActionRequest, isActionRequest } from '#/server/action-handler.js';
29
- import type { BodyLimitsConfig } from '#/server/body-limits.js';
30
- import type { BuildManifest } from '#/server/build-manifest.js';
27
+ import type { FormRerender } from '../action-handler.js';
28
+ import { handleActionRequest, isActionRequest } from '../action-handler.js';
29
+ import type { BodyLimitsConfig } from '../body-limits.js';
30
+ import type { BuildManifest } from '../build-manifest.js';
31
31
  import {
32
- buildCssLinkTags,
33
32
  buildFontPreloadTags,
34
33
  buildModulepreloadTags,
35
- collectRouteCss,
36
34
  collectRouteFonts,
37
35
  collectRouteModulepreloads,
38
- } from '#/server/build-manifest.js';
39
- import type { LayoutEntry } from '#/server/deny-renderer.js';
40
- import { renderDenyPage, renderDenyPageAsRsc } from '#/server/deny-renderer.js';
41
- import { resolveLogMode } from '#/server/dev-logger.js';
42
- import { sendEarlyHints103 } from '#/server/early-hints-sender.js';
43
- import { collectEarlyHintHeaders } from '#/server/early-hints.js';
44
- import { runWithFormFlash } from '#/server/form-flash.js';
45
- import type { ClientBootstrapConfig } from '#/server/html-injectors.js';
46
- import { buildClientScripts } from '#/server/html-injectors.js';
47
- import type { InterceptionContext, PipelineConfig, RouteMatch } from '#/server/pipeline.js';
48
- import { createPipeline } from '#/server/pipeline.js';
49
- import { DenySignal, RedirectSignal } from '#/server/primitives.js';
50
- import { buildRouteElement, RouteSignalWithContext } from '#/server/route-element-builder.js';
51
- import type { ManifestSegmentNode } from '#/server/route-matcher.js';
52
- import { createMetadataRouteMatcher, createRouteMatcher } from '#/server/route-matcher.js';
53
- import { initDevTracing } from '#/server/tracing.js';
54
-
55
- import { renderFallbackError as renderFallback } from '#/server/fallback-error.js';
56
- import { loadInstrumentation } from '#/server/instrumentation.js';
36
+ } from '../build-manifest.js';
37
+ import type { LayoutEntry } from '../deny-renderer.js';
38
+ import { renderDenyPage, renderDenyPageAsRsc } from '../deny-renderer.js';
39
+ import { resolveLogMode } from '../dev-logger.js';
40
+ import { sendEarlyHints103 } from '../early-hints-sender.js';
41
+ import { collectEarlyHintHeaders } from '../early-hints.js';
42
+ import { runWithFormFlash } from '../form-flash.js';
43
+ import type { ClientBootstrapConfig } from '../html-injectors.js';
44
+ import { buildClientScripts } from '../html-injectors.js';
45
+ import type { InterceptionContext, PipelineConfig, RouteMatch } from '../pipeline.js';
46
+ import { createPipeline, coerceSegmentParams } from '../pipeline.js';
47
+ import { DenySignal, RedirectSignal } from '../primitives.js';
48
+ import {
49
+ buildRouteElement,
50
+ RouteSignalWithContext,
51
+ ParamCoercionError,
52
+ } from '../route-element-builder.js';
53
+ import type { ManifestSegmentNode } from '../route-matcher.js';
54
+ import { createMetadataRouteMatcher, createRouteMatcher } from '../route-matcher.js';
55
+ import { initDevTracing } from '../tracing.js';
56
+
57
+ import { renderFallbackError as renderFallback } from '../fallback-error.js';
58
+ import { loadInstrumentation } from '../instrumentation.js';
57
59
  import { handleApiRoute } from './api-handler.js';
58
60
  import { renderErrorPage, renderNoMatchPage } from './error-renderer.js';
59
61
  import {
@@ -61,33 +63,61 @@ import {
61
63
  createDebugChannelSink,
62
64
  escapeHtml,
63
65
  isRscPayloadRequest,
66
+ type DebugComponentEntry,
64
67
  } from './helpers.js';
65
- import { parseClientStateTree } from '#/server/state-tree-diff.js';
66
- import {
67
- createResponseCache,
68
- resolveResponseCacheConfig,
69
- type ResponseCache,
70
- } from '#/server/response-cache.js';
68
+ import { parseClientStateTree } from '../state-tree-diff.js';
71
69
  import { buildRscPayloadResponse } from './rsc-payload.js';
72
70
  import { renderRscStream } from './rsc-stream.js';
73
71
  import { renderSsrResponse } from './ssr-renderer.js';
74
72
  import { callSsr } from './ssr-bridge.js';
75
- import { isDebug, isDevMode, setDebugFromConfig } from '#/server/debug.js';
73
+ import { isDebug, isDevMode, setDebugFromConfig } from '../debug.js';
74
+ import { recordTiming } from '../server-timing.js';
75
+ import { requestContextAls } from '../als-registry.js';
76
+
77
+ /**
78
+ * Resolve the Server-Timing mode from timber.config.ts.
79
+ *
80
+ * If the user set `serverTiming` explicitly, use that value.
81
+ * Otherwise: `'detailed'` in dev, `'total'` in production.
82
+ */
83
+ function resolveServerTimingMode(
84
+ config: Record<string, unknown>,
85
+ isDev: boolean
86
+ ): 'detailed' | 'total' | false {
87
+ const userValue = config.serverTiming as 'detailed' | 'total' | false | undefined;
88
+ if (userValue !== undefined) return userValue;
89
+ return isDev ? 'detailed' : 'total';
90
+ }
76
91
 
77
92
  // Dev-only pipeline error handler, set by the dev server after import.
78
93
  // In production this is always undefined — no overhead.
79
- let _devPipelineErrorHandler: ((error: Error, phase: string) => void) | undefined;
94
+ // The third argument provides RSC debug component data (from the Flight
95
+ // debug channel) when available — used by the error overlay to show the
96
+ // server component tree context for render errors.
97
+ let _devPipelineErrorHandler:
98
+ | ((error: Error, phase: string, debugComponents?: DebugComponentEntry[]) => void)
99
+ | undefined;
80
100
 
81
101
  /**
82
102
  * Set the dev pipeline error handler.
83
103
  *
84
104
  * Called by the dev server after importing this module to wire pipeline
85
105
  * errors into the Vite browser error overlay. No-op in production.
106
+ *
107
+ * The handler receives an optional third argument with RSC debug component
108
+ * info — component names, environments, and stack frames from the Flight
109
+ * debug channel. This is only populated for render-phase errors.
86
110
  */
87
- export function setDevPipelineErrorHandler(handler: (error: Error, phase: string) => void): void {
111
+ export function setDevPipelineErrorHandler(
112
+ handler: (error: Error, phase: string, debugComponents?: DebugComponentEntry[]) => void
113
+ ): void {
88
114
  _devPipelineErrorHandler = handler;
89
115
  }
90
116
 
117
+ // Dev-only: debug components getter is stored per-request in ALS
118
+ // (RequestContextStore.debugComponentsGetter) to avoid cross-request
119
+ // race conditions. See TIM-557.
120
+
91
121
  /**
92
122
  * Create the RSC request handler from the route manifest.
93
123
  *
@@ -101,13 +131,15 @@ async function createRequestHandler(manifest: typeof routeManifest, runtimeConfi
101
131
  // See design/17-logging.md §"register() — Server Startup"
102
132
  await loadInstrumentation(loadUserInstrumentation);
103
133
 
104
- // Initialize cookie signing secrets from config (design/29-cookies.md §"Signed Cookies")
105
- const cookieSecrets = (runtimeConfig as Record<string, unknown>).cookieSecrets as
106
- | string[]
134
+ // Initialize deployment ID for version skew detection (TIM-446).
135
+ // The manifest init module sets globalThis.__TIMBER_DEPLOYMENT_ID__ at startup.
136
+ // In dev mode this is undefined — skew checks are skipped.
137
+ const deploymentId = (globalThis as Record<string, unknown>).__TIMBER_DEPLOYMENT_ID__ as
138
+ | string
107
139
  | undefined;
108
- if (cookieSecrets?.length) {
109
- const { setCookieSecrets } = await import('#/server/request-context.js');
110
- setCookieSecrets(cookieSecrets);
140
+ if (deploymentId) {
141
+ const { setDeploymentId } = await import('../version-skew.js');
142
+ setDeploymentId(deploymentId);
111
143
  }
112
144
 
113
145
  const matchRoute = createRouteMatcher(manifest);
@@ -164,17 +196,6 @@ async function createRequestHandler(manifest: typeof routeManifest, runtimeConfi
164
196
 
165
197
  const typedBuildManifest = buildManifest as BuildManifest;
166
198
 
167
- // Initialize response-level caching and singleflight deduplication.
168
- // See design/31-benchmarking.md for performance motivation.
169
- const responseCacheRaw = (runtimeConfig as Record<string, unknown>).responseCache as
170
- | { maxSize?: number; ttlMs?: number; publicOnly?: boolean }
171
- | false
172
- | undefined;
173
- const responseCacheConfig = resolveResponseCacheConfig(responseCacheRaw);
174
- const responseCache: ResponseCache | null = responseCacheConfig
175
- ? createResponseCache(responseCacheConfig)
176
- : null;
177
-
178
199
  const pipelineConfig: PipelineConfig = {
179
200
  proxyLoader: manifest.proxy?.load,
180
201
  matchRoute,
@@ -205,17 +226,16 @@ async function createRequestHandler(manifest: typeof routeManifest, runtimeConfi
205
226
  _requestHeaderOverlay: Headers,
206
227
  interception?: InterceptionContext
207
228
  ) => {
208
- const doRender = () =>
209
- renderRoute(req, match, responseHeaders, clientBootstrap, clientJsDisabled, interception);
210
-
211
- // Response cache wraps the render with singleflight + LRU.
212
- // Interception requests (modals) are excluded — they depend on
213
- // X-Timber-URL which makes caching semantics ambiguous.
214
- if (responseCache && !interception) {
215
- const isRsc = (req.headers.get('Accept') ?? '').includes('text/x-component');
216
- return responseCache.getOrRender(req, isRsc, doRender);
217
- }
218
- return doRender();
229
+ return renderRoute(
230
+ req,
231
+ match,
232
+ responseHeaders,
233
+ clientBootstrap,
234
+ clientJsDisabled,
235
+ interception,
236
+ manifest.root,
237
+ manifest.globalError
238
+ );
219
239
  },
220
240
  renderNoMatch: async (req: Request, responseHeaders: Headers) => {
221
241
  return renderNoMatchPage(req, manifest.root, responseHeaders, clientBootstrap);
@@ -224,14 +244,31 @@ async function createRequestHandler(manifest: typeof routeManifest, runtimeConfi
224
244
  // Slow request threshold from timber.config.ts. Default 3000ms, 0 to disable.
225
245
  // See design/17-logging.md §"slowRequestMs"
226
246
  slowRequestMs: (runtimeConfig as Record<string, unknown>).slowRequestMs as number | undefined,
227
- enableServerTiming: isDev,
247
+ serverTiming: resolveServerTimingMode(runtimeConfig, isDev),
228
248
  onPipelineError: isDev
229
249
  ? (error: Error, phase: string) => {
230
- if (_devPipelineErrorHandler) _devPipelineErrorHandler(error, phase);
250
+ if (_devPipelineErrorHandler) {
251
+ // For render-phase errors, include RSC debug component data
252
+ // from the Flight debug channel (if available from the current request).
253
+ const store = requestContextAls.getStore();
254
+ const debugComponents =
255
+ phase === 'render' && store?.debugComponentsGetter
256
+ ? store.debugComponentsGetter()
257
+ : undefined;
258
+ _devPipelineErrorHandler(error, phase, debugComponents);
259
+ }
231
260
  }
232
261
  : undefined,
233
262
  renderFallbackError: (error, req, responseHeaders) =>
234
- renderFallback(error, req, responseHeaders, isDev, manifest.root, clientBootstrap),
263
+ renderFallback(
264
+ error,
265
+ req,
266
+ responseHeaders,
267
+ isDev,
268
+ manifest.root,
269
+ clientBootstrap,
270
+ manifest.globalError
271
+ ),
235
272
  };
236
273
 
237
274
  const pipeline = createPipeline(pipelineConfig);
@@ -267,6 +304,9 @@ async function createRequestHandler(manifest: typeof routeManifest, runtimeConfi
267
304
  if (!revalidateMatch) {
268
305
  throw new Error(`revalidatePath('${path}') — no matching route`);
269
306
  }
307
+ // Coerce segment params (params.ts) before building the element tree.
308
+ // Without this, components receive raw strings instead of typed values.
309
+ await coerceSegmentParams(revalidateMatch);
270
310
  const routeResult = await buildRouteElement(revalidateReq, revalidateMatch);
271
311
  return {
272
312
  element: routeResult.element,
@@ -307,7 +347,9 @@ async function renderRoute(
307
347
  responseHeaders: Headers,
308
348
  clientBootstrap: ClientBootstrapConfig,
309
349
  clientJsDisabled: boolean,
310
- interception?: InterceptionContext
350
+ interception?: InterceptionContext,
351
+ rootSegment?: ManifestSegmentNode,
352
+ globalError?: { load: () => Promise<unknown>; filePath: string }
311
353
  ): Promise<Response> {
312
354
  const segments = match.segments as unknown as ManifestSegmentNode[];
313
355
  const leaf = segments[segments.length - 1];
@@ -329,6 +371,7 @@ async function renderRoute(
329
371
  // Build the React element tree — loads modules, runs access checks,
330
372
  // resolves metadata. DenySignal/RedirectSignal propagate for HTTP handling.
331
373
  let routeResult;
374
+ const _buildStart = performance.now();
332
375
  try {
333
376
  routeResult = await buildRouteElement(_req, match, interception, clientStateTree);
334
377
  } catch (error) {
@@ -361,14 +404,29 @@ async function renderRoute(
361
404
  return buildRedirectResponse(_req, signal, responseHeaders);
362
405
  }
363
406
  }
364
- // No PageComponent found
407
+ // Param coercion failed — render the custom 404 page (status files / not-found).
408
+ // Previously returned a bare Response(null, { status: 404 }) which bypassed
409
+ // custom not-found pages. Now routes through renderNoMatchPage so apps with
410
+ // 404.tsx / not-found status files render their custom page.
411
+ if (error instanceof ParamCoercionError) {
412
+ return renderNoMatchPage(_req, rootSegment!, responseHeaders, clientBootstrap);
413
+ }
414
+ // No PageComponent found — same treatment as param coercion: render custom 404.
365
415
  if (error instanceof Error && error.message.startsWith('No page component')) {
366
- return new Response(null, { status: 404 });
416
+ return renderNoMatchPage(_req, rootSegment!, responseHeaders, clientBootstrap);
367
417
  }
368
418
  throw error;
369
419
  }
370
420
 
371
- const { element, headElements, layoutComponents, deferSuspenseFor, skippedSegments } = routeResult;
421
+ const _buildEnd = performance.now();
422
+ recordTiming({
423
+ name: 'build',
424
+ dur: Math.round(_buildEnd - _buildStart),
425
+ desc: 'build element tree',
426
+ });
427
+
428
+ const { element, headElements, layoutComponents, deferSuspenseFor, skippedSegments } =
429
+ routeResult;
372
430
 
373
431
  // Build head HTML for injection into the SSR output.
374
432
  // Collects CSS, fonts, and modulepreload from the build manifest for matched segments.
@@ -380,9 +438,24 @@ async function renderRoute(
380
438
  const typedManifest = buildManifest as BuildManifest;
381
439
  let headHtml = '';
382
440
 
383
- const cssUrls = collectRouteCss(segments, typedManifest);
384
- if (cssUrls.length > 0) {
385
- headHtml += buildCssLinkTags(cssUrls);
441
+ // CSS is handled by the RSC plugin via ReactDOM.preinit() with
442
+ // data-precedence attributes. This injects <link rel="stylesheet">
443
+ // tags during the RSC render phase — before our headHtml injection.
444
+ // We do NOT emit additional <link rel="stylesheet"> tags here because:
445
+ // 1. React's Float system deduplicates them, making ours redundant
446
+ // 2. The duplicate reference confuses React's client-side preload
447
+ // deduplication, causing "preload ignored" browser warnings
448
+ //
449
+ // CSS URLs are still collected for Early Hints (Link headers) in
450
+ // buildEarlyHintsHeaders() — those are HTTP headers, not DOM elements,
451
+ // so they don't conflict with Float.
452
+
453
+ // Inline font CSS as a <style> tag — @font-face rules and scoped classes.
454
+ // The font CSS is set on globalThis by the transformed font file's
455
+ // side-effect import of virtual:timber-font-css-register.
456
+ const fontCss = (globalThis as Record<string, unknown>).__timber_font_css as string | undefined;
457
+ if (fontCss) {
458
+ headHtml += `<style data-timber-fonts>${fontCss}</style>`;
386
459
  }
387
460
 
388
461
  const fontEntries = collectRouteFonts(segments, typedManifest);
@@ -410,8 +483,34 @@ async function renderRoute(
410
483
  }
411
484
  }
412
485
 
486
+ // In dev mode, inject the browser log forwarding script so console
487
+ // errors/warnings from the browser appear in the server terminal.
488
+ // Set by timber-dev-browser-logs plugin via globalThis (TIM-575).
489
+ if (isDevMode()) {
490
+ const devLogScript = (globalThis as Record<string, unknown>).__timber_dev_browser_log_script as
491
+ | string
492
+ | undefined;
493
+ if (devLogScript) {
494
+ headHtml += devLogScript;
495
+ }
496
+ }
497
+
413
498
  // Render to RSC Flight stream with signal tracking.
414
- const { rscStream, signals } = renderRscStream(element, _req);
499
+ const _rscStart = performance.now();
500
+ const { rscStream, signals, getDebugComponents } = renderRscStream(element, _req);
501
+
502
+ // Store the debug components getter in ALS so onPipelineError can
503
+ // include component tree context for render-phase errors (dev mode only).
504
+ // Per-request via ALS — no cross-request race. See TIM-557.
505
+ const alsStore = requestContextAls.getStore();
506
+ if (alsStore) {
507
+ alsStore.debugComponentsGetter = getDebugComponents;
508
+ }
509
+ recordTiming({
510
+ name: 'rsc-init',
511
+ dur: Math.round(performance.now() - _rscStart),
512
+ desc: 'RSC stream init',
513
+ });
415
514
 
416
515
  // Synchronous redirect — redirect() in access.ts or a non-async component
417
516
  // throws during renderToReadableStream creation. Return HTTP redirect.
@@ -456,7 +555,8 @@ async function renderRoute(
456
555
  _req,
457
556
  match,
458
557
  responseHeaders,
459
- clientBootstrap
558
+ clientBootstrap,
559
+ globalError
460
560
  );
461
561
  }
462
562
 
@@ -490,15 +590,16 @@ async function renderRoute(
490
590
  clientJsDisabled,
491
591
  headHtml,
492
592
  deferSuspenseFor,
593
+ globalError,
493
594
  });
494
595
  }
495
596
 
496
597
  // Re-export for generated entry points (e.g., Nitro node-server/bun) to wrap
497
598
  // the handler with per-request 103 Early Hints sender via ALS.
498
- export { runWithEarlyHintsSender } from '#/server/early-hints-sender.js';
599
+ export { runWithEarlyHintsSender } from '../early-hints-sender.js';
499
600
 
500
601
  // Re-export for generated entry points to wrap the handler with per-request
501
602
  // waitUntil support via ALS. See design/11-platform.md §"waitUntil()".
502
- export { runWithWaitUntil } from '#/server/waituntil-bridge.js';
603
+ export { runWithWaitUntil } from '../waituntil-bridge.js';
503
604
 
504
605
  export default await createRequestHandler(routeManifest, config);
@@ -9,12 +9,12 @@
9
9
  * 16-metadata.md §"Head Elements"
10
10
  */
11
11
 
12
- import type { LayoutEntry } from '#/server/deny-renderer.js';
13
- import { renderDenyPageAsRsc } from '#/server/deny-renderer.js';
14
- import type { RouteMatch } from '#/server/pipeline.js';
15
- import type { RedirectSignal } from '#/server/primitives.js';
16
- import type { HeadElement, LayoutComponentEntry } from '#/server/route-element-builder.js';
17
- import type { ManifestSegmentNode } from '#/server/route-matcher.js';
12
+ import type { LayoutEntry } from '../deny-renderer.js';
13
+ import { renderDenyPageAsRsc } from '../deny-renderer.js';
14
+ import type { RouteMatch } from '../pipeline.js';
15
+ import type { RedirectSignal } from '../primitives.js';
16
+ import type { HeadElement, LayoutComponentEntry } from '../route-element-builder.js';
17
+ import type { ManifestSegmentNode } from '../route-matcher.js';
18
18
 
19
19
  import {
20
20
  buildRedirectResponse,
@@ -45,18 +45,60 @@ export async function buildRscPayloadResponse(
45
45
  skippedSegments?: string[]
46
46
  ): Promise<Response> {
47
47
  // Read the first chunk from the RSC stream before committing headers.
48
+ // Race the first read against signal detection — if an async component
49
+ // throws a RedirectSignal or DenySignal, the onError callback fires
50
+ // signals.onSignal() and we can react immediately without waiting for
51
+ // the full macrotask queue.
52
+ //
53
+ // The rejection chain for an async-wrapped page component:
54
+ // 1. PageComponent throws RedirectSignal
55
+ // 2. withSpan catches and re-throws (microtask 1)
56
+ // 3. TracedPage promise rejects (microtask 2)
57
+ // 4. React Flight rejection handler → onError (microtask 3+)
58
+ //
59
+ // Promise.race reacts the instant onError fires, eliminating the
60
+ // per-request setTimeout(0) macrotask delay for the common case
61
+ // (no signal). A 50ms ceiling timeout guards against edge cases
62
+ // where onError never fires.
48
63
  const reader = rscStream.getReader();
49
- const firstRead = await reader.read();
64
+ const signalDetected = new Promise<void>((resolve) => {
65
+ signals.onSignal = resolve;
66
+ });
50
67
 
51
- // Yield to the microtask queue so that async component rejections
52
- // (e.g. an async-wrapped page component that throws redirect())
53
- // propagate to the onError callback before we check the signals.
54
- // The rejected Promise from an async component resolves in the next
55
- // microtask after read(), so we need at least one tick.
56
- //
57
- // Uses queueMicrotask instead of setTimeout(0) to stay within the
58
- // same tick no full event loop round-trip needed.
59
- await new Promise<void>((r) => queueMicrotask(r));
68
+ type RaceResult =
69
+ | { type: 'data'; chunk: ReadableStreamReadResult<Uint8Array> }
70
+ | { type: 'signal' };
71
+
72
+ let first: RaceResult;
73
+ try {
74
+ first = await Promise.race([
75
+ reader.read().then((chunk) => ({ type: 'data' as const, chunk })),
76
+ signalDetected.then(() => ({ type: 'signal' as const })),
77
+ ]);
78
+ } catch (_readError) {
79
+ // RSC stream failed on first read — unhandled error in the page component.
80
+ // Return an error response so the client can hard-navigate for the
81
+ // SSR-rendered error page. See design/10-error-handling.md.
82
+ reader.cancel().catch(() => {});
83
+ signals.onSignal = undefined;
84
+ responseHeaders.set('X-Timber-Error', '1');
85
+ responseHeaders.set('content-type', 'application/json; charset=utf-8');
86
+ return new Response(JSON.stringify({ error: true, status: 500 }), {
87
+ status: 500,
88
+ headers: responseHeaders,
89
+ });
90
+ }
91
+
92
+ // If data arrived first, still check signals — they may have fired
93
+ // concurrently. Also do a final ceiling timeout check for edge cases
94
+ // where the signal fires just after the first read resolves.
95
+ if (first.type === 'data' && !signals.redirectSignal && !signals.denySignal) {
96
+ // Brief yield to let any in-flight microtask rejections complete.
97
+ await new Promise<void>((r) => setTimeout(r, 0));
98
+ }
99
+
100
+ // Detach the callback — no longer needed after this point.
101
+ signals.onSignal = undefined;
60
102
 
61
103
  // Check for redirect/deny signals detected during initial rendering
62
104
  const trackedRedirect = signals.redirectSignal as RedirectSignal | null;
@@ -75,6 +117,37 @@ export async function buildRscPayloadResponse(
75
117
  );
76
118
  }
77
119
 
120
+ // Check for unhandled errors (RenderError or plain Error).
121
+ // These aren't redirect/deny signals but the RSC stream will be broken.
122
+ // Return an error response so the client can hard-navigate for the
123
+ // SSR-rendered error page. See design/10-error-handling.md
124
+ // §"Error Page Rendering for Client Navigation".
125
+ if (signals.renderError) {
126
+ reader.cancel().catch(() => {});
127
+ responseHeaders.set('X-Timber-Error', '1');
128
+ responseHeaders.set('content-type', 'application/json; charset=utf-8');
129
+ return new Response(
130
+ JSON.stringify({
131
+ error: true,
132
+ status: signals.renderError.status,
133
+ }),
134
+ { status: signals.renderError.status, headers: responseHeaders }
135
+ );
136
+ }
137
+
138
+ // Extract the first chunk from the race result.
139
+ // If the signal won the race but neither redirect nor deny was detected
140
+ // (edge case), cancel the reader immediately rather than issuing a bare
141
+ // read() that could hang forever if the RSC stream has stalled.
142
+ // See TIM-519.
143
+ let firstRead: ReadableStreamReadResult<Uint8Array>;
144
+ if (first.type === 'data') {
145
+ firstRead = first.chunk;
146
+ } else {
147
+ await reader.cancel();
148
+ firstRead = { done: true, value: undefined };
149
+ }
150
+
78
151
  // Reconstruct the stream: prepend the buffered first chunk,
79
152
  // then continue piping from the original reader.
80
153
  const patchedStream = new ReadableStream<Uint8Array>({
@@ -123,8 +196,8 @@ export async function buildRscPayloadResponse(
123
196
  responseHeaders.set('X-Timber-Skipped-Segments', JSON.stringify(skippedSegments));
124
197
  }
125
198
 
126
- // Send route params so the client can populate useParams() after
127
- // SPA navigation. Without this, useParams() returns {}.
199
+ // Send route params so the client can populate useSegmentParams() after
200
+ // SPA navigation. Without this, useSegmentParams() returns {}.
128
201
  if (Object.keys(match.params).length > 0) {
129
202
  responseHeaders.set('X-Timber-Params', JSON.stringify(match.params));
130
203
  }