@timber-js/app 0.2.0-alpha.4 → 0.2.0-alpha.41

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 (336) 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-ECi_61pb.js +108 -0
  6. package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
  7. package/dist/_chunks/define-cookie-BmKbSyp0.js +93 -0
  8. package/dist/_chunks/define-cookie-BmKbSyp0.js.map +1 -0
  9. package/dist/_chunks/error-boundary-BAN3751q.js +211 -0
  10. package/dist/_chunks/error-boundary-BAN3751q.js.map +1 -0
  11. package/dist/_chunks/{format-CwdaB0_2.js → format-cX7wzEp2.js} +2 -2
  12. package/dist/_chunks/{format-CwdaB0_2.js.map → format-cX7wzEp2.js.map} +1 -1
  13. package/dist/_chunks/{interception-BOoWmLUA.js → interception-D2djYaIm.js} +112 -77
  14. package/dist/_chunks/interception-D2djYaIm.js.map +1 -0
  15. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-BU684ls2.js} +1 -1
  16. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-BU684ls2.js.map} +1 -1
  17. package/dist/_chunks/{request-context-CZJi4CuK.js → request-context-BxYIJM24.js} +93 -69
  18. package/dist/_chunks/request-context-BxYIJM24.js.map +1 -0
  19. package/dist/_chunks/segment-context-C6byCyZU.js +69 -0
  20. package/dist/_chunks/segment-context-C6byCyZU.js.map +1 -0
  21. package/dist/_chunks/stale-reload-C0ValzG7.js +47 -0
  22. package/dist/_chunks/stale-reload-C0ValzG7.js.map +1 -0
  23. package/dist/_chunks/{tracing-Cwn7697K.js → tracing-CuXiCP5p.js} +17 -3
  24. package/dist/_chunks/{tracing-Cwn7697K.js.map → tracing-CuXiCP5p.js.map} +1 -1
  25. package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-BvW0TKDn.js} +1 -1
  26. package/dist/_chunks/{use-query-states-D5KaffOK.js.map → use-query-states-BvW0TKDn.js.map} +1 -1
  27. package/dist/_chunks/wrappers-C6J0nNji.js +331 -0
  28. package/dist/_chunks/wrappers-C6J0nNji.js.map +1 -0
  29. package/dist/adapters/compress-module.d.ts.map +1 -1
  30. package/dist/adapters/nitro.d.ts +17 -1
  31. package/dist/adapters/nitro.d.ts.map +1 -1
  32. package/dist/adapters/nitro.js +56 -13
  33. package/dist/adapters/nitro.js.map +1 -1
  34. package/dist/cache/fast-hash.d.ts +22 -0
  35. package/dist/cache/fast-hash.d.ts.map +1 -0
  36. package/dist/cache/index.d.ts +5 -2
  37. package/dist/cache/index.d.ts.map +1 -1
  38. package/dist/cache/index.js +88 -18
  39. package/dist/cache/index.js.map +1 -1
  40. package/dist/cache/register-cached-function.d.ts.map +1 -1
  41. package/dist/cache/singleflight.d.ts +18 -1
  42. package/dist/cache/singleflight.d.ts.map +1 -1
  43. package/dist/cache/timber-cache.d.ts.map +1 -1
  44. package/dist/client/error-boundary.d.ts +10 -1
  45. package/dist/client/error-boundary.d.ts.map +1 -1
  46. package/dist/client/error-boundary.js +1 -125
  47. package/dist/client/index.d.ts +3 -2
  48. package/dist/client/index.d.ts.map +1 -1
  49. package/dist/client/index.js +213 -93
  50. package/dist/client/index.js.map +1 -1
  51. package/dist/client/link.d.ts +22 -8
  52. package/dist/client/link.d.ts.map +1 -1
  53. package/dist/client/navigation-context.d.ts +2 -2
  54. package/dist/client/router.d.ts +25 -3
  55. package/dist/client/router.d.ts.map +1 -1
  56. package/dist/client/rsc-fetch.d.ts +23 -2
  57. package/dist/client/rsc-fetch.d.ts.map +1 -1
  58. package/dist/client/segment-cache.d.ts +1 -1
  59. package/dist/client/segment-cache.d.ts.map +1 -1
  60. package/dist/client/segment-context.d.ts +1 -1
  61. package/dist/client/segment-context.d.ts.map +1 -1
  62. package/dist/client/segment-merger.d.ts.map +1 -1
  63. package/dist/client/stale-reload.d.ts +15 -0
  64. package/dist/client/stale-reload.d.ts.map +1 -1
  65. package/dist/client/top-loader.d.ts +1 -1
  66. package/dist/client/top-loader.d.ts.map +1 -1
  67. package/dist/client/transition-root.d.ts +1 -1
  68. package/dist/client/transition-root.d.ts.map +1 -1
  69. package/dist/client/use-params.d.ts +2 -2
  70. package/dist/client/use-params.d.ts.map +1 -1
  71. package/dist/client/use-query-states.d.ts +1 -1
  72. package/dist/codec.d.ts +21 -0
  73. package/dist/codec.d.ts.map +1 -0
  74. package/dist/cookies/define-cookie.d.ts +33 -12
  75. package/dist/cookies/define-cookie.d.ts.map +1 -1
  76. package/dist/cookies/index.js +1 -83
  77. package/dist/fonts/css.d.ts +1 -0
  78. package/dist/fonts/css.d.ts.map +1 -1
  79. package/dist/fonts/local.d.ts +4 -2
  80. package/dist/fonts/local.d.ts.map +1 -1
  81. package/dist/index.d.ts +112 -35
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +635 -233
  84. package/dist/index.js.map +1 -1
  85. package/dist/params/define.d.ts +76 -0
  86. package/dist/params/define.d.ts.map +1 -0
  87. package/dist/params/index.d.ts +8 -0
  88. package/dist/params/index.d.ts.map +1 -0
  89. package/dist/params/index.js +104 -0
  90. package/dist/params/index.js.map +1 -0
  91. package/dist/plugins/adapter-build.d.ts.map +1 -1
  92. package/dist/plugins/build-manifest.d.ts.map +1 -1
  93. package/dist/plugins/client-chunks.d.ts +32 -0
  94. package/dist/plugins/client-chunks.d.ts.map +1 -0
  95. package/dist/plugins/dev-error-overlay.d.ts +26 -1
  96. package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
  97. package/dist/plugins/entries.d.ts +7 -0
  98. package/dist/plugins/entries.d.ts.map +1 -1
  99. package/dist/plugins/fonts.d.ts +9 -1
  100. package/dist/plugins/fonts.d.ts.map +1 -1
  101. package/dist/plugins/mdx.d.ts +6 -0
  102. package/dist/plugins/mdx.d.ts.map +1 -1
  103. package/dist/plugins/routing.d.ts.map +1 -1
  104. package/dist/plugins/server-bundle.d.ts.map +1 -1
  105. package/dist/plugins/static-build.d.ts.map +1 -1
  106. package/dist/routing/codegen.d.ts +2 -2
  107. package/dist/routing/codegen.d.ts.map +1 -1
  108. package/dist/routing/index.js +1 -1
  109. package/dist/routing/scanner.d.ts.map +1 -1
  110. package/dist/routing/status-file-lint.d.ts +2 -1
  111. package/dist/routing/status-file-lint.d.ts.map +1 -1
  112. package/dist/routing/types.d.ts +6 -4
  113. package/dist/routing/types.d.ts.map +1 -1
  114. package/dist/rsc-runtime/rsc.d.ts +1 -1
  115. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  116. package/dist/rsc-runtime/ssr.d.ts +12 -0
  117. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  118. package/dist/search-params/codecs.d.ts +1 -1
  119. package/dist/search-params/define.d.ts +153 -0
  120. package/dist/search-params/define.d.ts.map +1 -0
  121. package/dist/search-params/index.d.ts +4 -5
  122. package/dist/search-params/index.d.ts.map +1 -1
  123. package/dist/search-params/index.js +3 -474
  124. package/dist/search-params/registry.d.ts +1 -1
  125. package/dist/search-params/wrappers.d.ts +53 -0
  126. package/dist/search-params/wrappers.d.ts.map +1 -0
  127. package/dist/server/access-gate.d.ts +4 -0
  128. package/dist/server/access-gate.d.ts.map +1 -1
  129. package/dist/server/action-client.d.ts.map +1 -1
  130. package/dist/server/action-encryption.d.ts +76 -0
  131. package/dist/server/action-encryption.d.ts.map +1 -0
  132. package/dist/server/action-handler.d.ts.map +1 -1
  133. package/dist/server/als-registry.d.ts +18 -4
  134. package/dist/server/als-registry.d.ts.map +1 -1
  135. package/dist/server/build-manifest.d.ts +2 -2
  136. package/dist/server/debug.d.ts +46 -15
  137. package/dist/server/debug.d.ts.map +1 -1
  138. package/dist/server/default-logger.d.ts +22 -0
  139. package/dist/server/default-logger.d.ts.map +1 -0
  140. package/dist/server/deny-renderer.d.ts.map +1 -1
  141. package/dist/server/early-hints.d.ts +13 -5
  142. package/dist/server/early-hints.d.ts.map +1 -1
  143. package/dist/server/error-boundary-wrapper.d.ts +4 -0
  144. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  145. package/dist/server/flight-injection-state.d.ts +78 -0
  146. package/dist/server/flight-injection-state.d.ts.map +1 -0
  147. package/dist/server/flight-scripts.d.ts +39 -0
  148. package/dist/server/flight-scripts.d.ts.map +1 -0
  149. package/dist/server/flush.d.ts.map +1 -1
  150. package/dist/server/form-data.d.ts +29 -0
  151. package/dist/server/form-data.d.ts.map +1 -1
  152. package/dist/server/html-injectors.d.ts +5 -11
  153. package/dist/server/html-injectors.d.ts.map +1 -1
  154. package/dist/server/index.d.ts +4 -2
  155. package/dist/server/index.d.ts.map +1 -1
  156. package/dist/server/index.js +1975 -1649
  157. package/dist/server/index.js.map +1 -1
  158. package/dist/server/logger.d.ts +24 -7
  159. package/dist/server/logger.d.ts.map +1 -1
  160. package/dist/server/node-stream-transforms.d.ts +77 -0
  161. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  162. package/dist/server/pipeline.d.ts +7 -4
  163. package/dist/server/pipeline.d.ts.map +1 -1
  164. package/dist/server/primitives.d.ts +30 -3
  165. package/dist/server/primitives.d.ts.map +1 -1
  166. package/dist/server/render-timeout.d.ts +51 -0
  167. package/dist/server/render-timeout.d.ts.map +1 -0
  168. package/dist/server/request-context.d.ts +65 -38
  169. package/dist/server/request-context.d.ts.map +1 -1
  170. package/dist/server/route-element-builder.d.ts +7 -0
  171. package/dist/server/route-element-builder.d.ts.map +1 -1
  172. package/dist/server/route-handler.d.ts.map +1 -1
  173. package/dist/server/route-matcher.d.ts +2 -2
  174. package/dist/server/route-matcher.d.ts.map +1 -1
  175. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  176. package/dist/server/rsc-entry/helpers.d.ts +46 -3
  177. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  178. package/dist/server/rsc-entry/index.d.ts +6 -1
  179. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  180. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  181. package/dist/server/rsc-entry/rsc-stream.d.ts +9 -0
  182. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  183. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  184. package/dist/server/slot-resolver.d.ts +1 -1
  185. package/dist/server/slot-resolver.d.ts.map +1 -1
  186. package/dist/server/ssr-entry.d.ts +22 -0
  187. package/dist/server/ssr-entry.d.ts.map +1 -1
  188. package/dist/server/ssr-render.d.ts +39 -21
  189. package/dist/server/ssr-render.d.ts.map +1 -1
  190. package/dist/server/tracing.d.ts +10 -0
  191. package/dist/server/tracing.d.ts.map +1 -1
  192. package/dist/server/tree-builder.d.ts +19 -12
  193. package/dist/server/tree-builder.d.ts.map +1 -1
  194. package/dist/server/types.d.ts +1 -3
  195. package/dist/server/types.d.ts.map +1 -1
  196. package/dist/server/version-skew.d.ts +61 -0
  197. package/dist/server/version-skew.d.ts.map +1 -0
  198. package/dist/server/waituntil-bridge.d.ts.map +1 -1
  199. package/dist/shared/merge-search-params.d.ts +22 -0
  200. package/dist/shared/merge-search-params.d.ts.map +1 -0
  201. package/dist/shims/navigation-client.d.ts +1 -1
  202. package/dist/shims/navigation-client.d.ts.map +1 -1
  203. package/dist/shims/navigation.d.ts +1 -1
  204. package/dist/shims/navigation.d.ts.map +1 -1
  205. package/dist/utils/state-machine.d.ts +80 -0
  206. package/dist/utils/state-machine.d.ts.map +1 -0
  207. package/package.json +17 -14
  208. package/src/adapters/compress-module.ts +24 -4
  209. package/src/adapters/nitro.ts +58 -9
  210. package/src/cache/fast-hash.ts +34 -0
  211. package/src/cache/index.ts +5 -2
  212. package/src/cache/register-cached-function.ts +7 -3
  213. package/src/cache/singleflight.ts +62 -4
  214. package/src/cache/timber-cache.ts +34 -26
  215. package/src/cli.ts +0 -0
  216. package/src/client/browser-entry.ts +94 -90
  217. package/src/client/error-boundary.tsx +18 -1
  218. package/src/client/index.ts +10 -1
  219. package/src/client/link.tsx +78 -19
  220. package/src/client/navigation-context.ts +2 -2
  221. package/src/client/router.ts +105 -60
  222. package/src/client/rsc-fetch.ts +63 -2
  223. package/src/client/segment-cache.ts +1 -1
  224. package/src/client/segment-context.ts +6 -1
  225. package/src/client/segment-merger.ts +2 -8
  226. package/src/client/stale-reload.ts +32 -6
  227. package/src/client/top-loader.tsx +10 -9
  228. package/src/client/transition-root.tsx +7 -1
  229. package/src/client/use-params.ts +3 -3
  230. package/src/client/use-query-states.ts +1 -1
  231. package/src/codec.ts +21 -0
  232. package/src/cookies/define-cookie.ts +69 -18
  233. package/src/fonts/css.ts +2 -1
  234. package/src/fonts/local.ts +7 -3
  235. package/src/index.ts +280 -85
  236. package/src/params/define.ts +260 -0
  237. package/src/params/index.ts +28 -0
  238. package/src/plugins/adapter-build.ts +6 -0
  239. package/src/plugins/build-manifest.ts +11 -0
  240. package/src/plugins/client-chunks.ts +65 -0
  241. package/src/plugins/dev-error-overlay.ts +70 -1
  242. package/src/plugins/dev-server.ts +38 -4
  243. package/src/plugins/entries.ts +12 -11
  244. package/src/plugins/fonts.ts +171 -19
  245. package/src/plugins/mdx.ts +9 -5
  246. package/src/plugins/routing.ts +40 -14
  247. package/src/plugins/server-bundle.ts +32 -1
  248. package/src/plugins/shims.ts +1 -1
  249. package/src/plugins/static-build.ts +8 -4
  250. package/src/routing/codegen.ts +109 -88
  251. package/src/routing/scanner.ts +55 -6
  252. package/src/routing/status-file-lint.ts +2 -1
  253. package/src/routing/types.ts +7 -4
  254. package/src/rsc-runtime/rsc.ts +2 -0
  255. package/src/rsc-runtime/ssr.ts +50 -0
  256. package/src/rsc-runtime/vendor-types.d.ts +7 -0
  257. package/src/search-params/codecs.ts +1 -1
  258. package/src/search-params/define.ts +504 -0
  259. package/src/search-params/index.ts +12 -18
  260. package/src/search-params/registry.ts +1 -1
  261. package/src/search-params/wrappers.ts +85 -0
  262. package/src/server/access-gate.tsx +40 -9
  263. package/src/server/action-client.ts +14 -5
  264. package/src/server/action-encryption.ts +144 -0
  265. package/src/server/action-handler.ts +19 -2
  266. package/src/server/als-registry.ts +18 -4
  267. package/src/server/build-manifest.ts +4 -4
  268. package/src/server/compress.ts +25 -7
  269. package/src/server/debug.ts +55 -17
  270. package/src/server/default-logger.ts +98 -0
  271. package/src/server/deny-renderer.ts +2 -1
  272. package/src/server/early-hints.ts +36 -15
  273. package/src/server/error-boundary-wrapper.ts +57 -14
  274. package/src/server/flight-injection-state.ts +152 -0
  275. package/src/server/flight-scripts.ts +59 -0
  276. package/src/server/flush.ts +2 -1
  277. package/src/server/form-data.ts +76 -0
  278. package/src/server/html-injectors.ts +103 -66
  279. package/src/server/index.ts +9 -4
  280. package/src/server/logger.ts +38 -35
  281. package/src/server/node-stream-transforms.ts +381 -0
  282. package/src/server/pipeline.ts +131 -39
  283. package/src/server/primitives.ts +47 -5
  284. package/src/server/render-timeout.ts +108 -0
  285. package/src/server/request-context.ts +112 -119
  286. package/src/server/route-element-builder.ts +106 -114
  287. package/src/server/route-handler.ts +2 -1
  288. package/src/server/route-matcher.ts +2 -2
  289. package/src/server/rsc-entry/error-renderer.ts +5 -3
  290. package/src/server/rsc-entry/helpers.ts +122 -3
  291. package/src/server/rsc-entry/index.ts +125 -49
  292. package/src/server/rsc-entry/rsc-payload.ts +52 -12
  293. package/src/server/rsc-entry/rsc-stream.ts +33 -8
  294. package/src/server/rsc-entry/ssr-renderer.ts +40 -13
  295. package/src/server/slot-resolver.ts +199 -210
  296. package/src/server/ssr-entry.ts +168 -22
  297. package/src/server/ssr-render.ts +289 -67
  298. package/src/server/tracing.ts +23 -0
  299. package/src/server/tree-builder.ts +91 -57
  300. package/src/server/types.ts +1 -3
  301. package/src/server/version-skew.ts +104 -0
  302. package/src/server/waituntil-bridge.ts +4 -1
  303. package/src/shared/merge-search-params.ts +48 -0
  304. package/src/shims/navigation-client.ts +1 -1
  305. package/src/shims/navigation.ts +1 -1
  306. package/src/utils/state-machine.ts +111 -0
  307. package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
  308. package/dist/_chunks/debug-B4WUeqJ-.js +0 -75
  309. package/dist/_chunks/debug-B4WUeqJ-.js.map +0 -1
  310. package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
  311. package/dist/_chunks/request-context-CZJi4CuK.js.map +0 -1
  312. package/dist/_chunks/ssr-data-MjmprTmO.js +0 -88
  313. package/dist/_chunks/ssr-data-MjmprTmO.js.map +0 -1
  314. package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
  315. package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
  316. package/dist/client/error-boundary.js.map +0 -1
  317. package/dist/cookies/index.js.map +0 -1
  318. package/dist/plugins/dynamic-transform.d.ts +0 -72
  319. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  320. package/dist/search-params/analyze.d.ts +0 -54
  321. package/dist/search-params/analyze.d.ts.map +0 -1
  322. package/dist/search-params/builtin-codecs.d.ts +0 -105
  323. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  324. package/dist/search-params/create.d.ts +0 -106
  325. package/dist/search-params/create.d.ts.map +0 -1
  326. package/dist/search-params/index.js.map +0 -1
  327. package/dist/server/prerender.d.ts +0 -77
  328. package/dist/server/prerender.d.ts.map +0 -1
  329. package/dist/server/response-cache.d.ts +0 -53
  330. package/dist/server/response-cache.d.ts.map +0 -1
  331. package/src/plugins/dynamic-transform.ts +0 -161
  332. package/src/search-params/analyze.ts +0 -192
  333. package/src/search-params/builtin-codecs.ts +0 -228
  334. package/src/search-params/create.ts +0 -321
  335. package/src/server/prerender.ts +0 -139
  336. package/src/server/response-cache.ts +0 -277
@@ -14,11 +14,21 @@
14
14
 
15
15
  // @ts-expect-error — virtual module provided by timber-entries plugin
16
16
  import config from 'virtual:timber-config';
17
- import { createFromReadableStream } from '#/rsc-runtime/ssr.js';
17
+ import {
18
+ createFromReadableStream,
19
+ createFromNodeStream,
20
+ hasNodeStreamDecode,
21
+ } from '#/rsc-runtime/ssr.js';
18
22
  import { AsyncLocalStorage } from 'node:async_hooks';
19
23
 
20
- import { renderSsrStream, buildSsrResponse } from './ssr-render.js';
21
- import { formatSsrError } from './error-formatter.js';
24
+ import {
25
+ renderSsrStream,
26
+ renderSsrNodeStream,
27
+ nodeReadableToWeb,
28
+ useNodeStreams,
29
+ buildSsrResponse,
30
+ } from './ssr-render.js';
31
+ import { logRenderError } from './logger.js';
22
32
  import { SsrStreamError } from './primitives.js';
23
33
  import { injectHead, injectRscPayload } from './html-injectors.js';
24
34
  import { withNuqsSsrAdapter } from './nuqs-ssr-provider.js';
@@ -26,6 +36,41 @@ import { withSpan } from './tracing.js';
26
36
  import { setCurrentParams } from '#/client/use-params.js';
27
37
  import { registerSsrDataProvider, type SsrData } from '#/client/ssr-data.js';
28
38
 
39
+ // Pre-import Node.js stream modules at module load time — not per-request.
40
+ // Dynamic imports of node-stream-transforms and node:stream/promises were
41
+ // costing 3-17ms per request due to module resolution overhead.
42
+ let _nodeStreamImports: {
43
+ createNodeHeadInjector: typeof import('./node-stream-transforms.js').createNodeHeadInjector;
44
+ createNodeFlightInjector: typeof import('./node-stream-transforms.js').createNodeFlightInjector;
45
+ createNodeErrorHandler: typeof import('./node-stream-transforms.js').createNodeErrorHandler;
46
+ pipeline: typeof import('node:stream/promises').pipeline;
47
+ PassThrough: typeof import('node:stream').PassThrough;
48
+ ReadableFromWeb: (
49
+ webStream: import('stream/web').ReadableStream
50
+ ) => import('node:stream').Readable;
51
+ } | null = null;
52
+
53
+ if (useNodeStreams) {
54
+ try {
55
+ const [transforms, streamPromises, stream] = await Promise.all([
56
+ import('./node-stream-transforms.js'),
57
+ import('node:stream/promises'),
58
+ import('node:stream'),
59
+ ]);
60
+ _nodeStreamImports = {
61
+ createNodeHeadInjector: transforms.createNodeHeadInjector,
62
+ createNodeFlightInjector: transforms.createNodeFlightInjector,
63
+ createNodeErrorHandler: transforms.createNodeErrorHandler,
64
+ pipeline: streamPromises.pipeline,
65
+ PassThrough: stream.PassThrough,
66
+ ReadableFromWeb: (webStream: import('stream/web').ReadableStream) =>
67
+ stream.Readable.fromWeb(webStream) as import('node:stream').Readable,
68
+ };
69
+ } catch {
70
+ // Fall back to Web Streams path
71
+ }
72
+ }
73
+
29
74
  // ─── SSR Data ALS ─────────────────────────────────────────────────────────
30
75
  //
31
76
  // Per-request SSR data stored in AsyncLocalStorage, ensuring correct
@@ -81,6 +126,29 @@ export interface NavContext {
81
126
  * to a page-level deny. See LOCAL-298.
82
127
  */
83
128
  _denyHandledByBoundary?: boolean;
129
+
130
+ /**
131
+ * Mutable: SSR timing data populated by handleSsr().
132
+ * Read by the RSC entry to record sub-phase Server-Timing entries
133
+ * when `serverTiming: 'detailed'` is configured.
134
+ *
135
+ * This bridges the RSC→SSR environment boundary: the SSR entry populates
136
+ * these fields, the RSC entry reads them after callSsr() returns.
137
+ */
138
+ _ssrTimings?: {
139
+ /** Time to decode RSC stream (createFromReadableStream/createFromNodeStream) */
140
+ decodeMs: number;
141
+ /** Time for Fizz to render the shell (onShellReady) */
142
+ shellMs: number;
143
+ /** Time for pipe() to flush shell bytes to the output stream */
144
+ pipeMs: number;
145
+ /** Time to set up Node.js Transform pipeline / Web Stream transforms */
146
+ pipelineMs: number;
147
+ /** Total SSR time (decode → response ready) */
148
+ totalMs: number;
149
+ /** Whether the Node.js native stream path was used */
150
+ nodeStreams: boolean;
151
+ };
84
152
  }
85
153
 
86
154
  /**
@@ -127,7 +195,7 @@ export async function handleSsr(
127
195
  // Client hooks read from getSsrData() which delegates to this
128
196
  // ALS store via the registered provider.
129
197
  return ssrDataAls.run(ssrData, async () => {
130
- // Also set the module-level currentParams for useParams().
198
+ // Also set the module-level currentParams for useSegmentParams().
131
199
  // useParams reads from getSsrData() during SSR (ALS-backed),
132
200
  // but setCurrentParams is kept for the client-side path where
133
201
  // the segment router updates params on navigation.
@@ -137,47 +205,125 @@ export async function handleSsr(
137
205
  // createFromReadableStream resolves client component references
138
206
  // (from "use client" modules) using the SSR environment's module
139
207
  // map, importing the actual components for server-side rendering.
140
- const element = createFromReadableStream(rscStream) as React.ReactNode;
208
+ const _ssrStart = performance.now();
209
+
210
+ // Decode the RSC stream into a React element tree.
211
+ // On Node.js: convert Web ReadableStream → Node Readable → createFromNodeStream
212
+ // (eliminates Promise-per-chunk overhead from Web Streams reader)
213
+ // On Workers: createFromReadableStream (Web Streams are V8-native C++ there)
214
+ let element: React.ReactNode;
215
+ if (hasNodeStreamDecode && _nodeStreamImports) {
216
+ const nodeRscStream = _nodeStreamImports.ReadableFromWeb(
217
+ rscStream as import('stream/web').ReadableStream
218
+ );
219
+ element = createFromNodeStream(nodeRscStream) as React.ReactNode;
220
+ } else {
221
+ element = createFromReadableStream(rscStream) as React.ReactNode;
222
+ }
223
+ const _decodeEnd = performance.now();
141
224
 
142
225
  // Wrap with a server-safe nuqs adapter so that 'use client' components
143
226
  // that call nuqs hooks (useQueryStates, useQueryState) can SSR correctly.
144
- // The client-side TimberNuqsAdapter (injected by browser-entry.ts) takes
145
- // over after hydration. This provider supplies the request's search params
146
- // as a static snapshot so nuqs renders the right initial values on the server.
147
227
  const wrappedElement = withNuqsSsrAdapter(navContext.searchParams, element);
148
228
 
149
229
  // Render to HTML stream (waits for onShellReady).
150
- // Pass bootstrapScriptContent so React injects a non-deferred <script>
151
- // in the shell HTML. This executes immediately during parsing — even
152
- // while Suspense boundaries are still streaming triggering module
153
- // loading via dynamic import() so hydration can start early.
230
+ //
231
+ // Two paths based on platform:
232
+ // - Node.js: renderToPipeableStream Node Transform pipeline Readable.toWeb() → Response
233
+ // Entire pipeline stays in C++ native streams until the Response boundary.
234
+ // - Workers: renderToReadableStream → Web TransformStream pipeline → Response
235
+ // Web Streams are V8-native C++ built-ins on Workers.
236
+ if (_nodeStreamImports) {
237
+ // Node.js fast path: full pipeline in native streams
238
+ const {
239
+ createNodeHeadInjector,
240
+ createNodeFlightInjector,
241
+ createNodeErrorHandler,
242
+ pipeline,
243
+ PassThrough,
244
+ } = _nodeStreamImports;
245
+
246
+ const renderTimeoutMs = _runtimeConfig.renderTimeoutMs ?? undefined;
247
+
248
+ let nodeHtmlStream: import('node:stream').Readable;
249
+ try {
250
+ nodeHtmlStream = await renderSsrNodeStream(wrappedElement, {
251
+ bootstrapScriptContent: navContext.bootstrapScriptContent || undefined,
252
+ deferSuspenseFor: navContext.deferSuspenseFor,
253
+ signal: navContext.signal,
254
+ renderTimeoutMs,
255
+ });
256
+ } catch (renderError) {
257
+ logRenderError({ method: '', path: '', error: renderError });
258
+ throw new SsrStreamError(
259
+ 'SSR renderToReadableStream failed due to RSC stream error',
260
+ renderError
261
+ );
262
+ }
263
+ const _renderEnd = performance.now();
264
+
265
+ // React 19.3+ emits <!DOCTYPE html> automatically when the root
266
+ // element is <html>, so no framework-level doctype prepend needed.
267
+ const errorHandler = createNodeErrorHandler(navContext.signal);
268
+ const headInjector = createNodeHeadInjector(navContext.headHtml);
269
+ const flightInjector = createNodeFlightInjector(navContext.rscStream, {
270
+ renderTimeoutMs,
271
+ });
272
+
273
+ const output = new PassThrough();
274
+ pipeline(nodeHtmlStream, errorHandler, headInjector, flightInjector, output).catch(() => {
275
+ // Pipeline errors are handled by errorHandler transform
276
+ });
277
+ const _pipelineEnd = performance.now();
278
+
279
+ // Record SSR sub-timings for Server-Timing header (detailed mode).
280
+ navContext._ssrTimings = {
281
+ decodeMs: Math.round(_decodeEnd - _ssrStart),
282
+ shellMs: Math.round(_renderEnd - _decodeEnd),
283
+ pipeMs: 0, // pipe() timing is inside renderSsrNodeStream
284
+ pipelineMs: Math.round(_pipelineEnd - _renderEnd),
285
+ totalMs: Math.round(_pipelineEnd - _ssrStart),
286
+ nodeStreams: true,
287
+ };
288
+
289
+ const webStream = nodeReadableToWeb(output);
290
+ return buildSsrResponse(webStream, navContext.statusCode, navContext.responseHeaders);
291
+ }
292
+
293
+ // Web Streams path (CF Workers / fallback)
294
+ const renderTimeoutMs = _runtimeConfig.renderTimeoutMs ?? undefined;
154
295
  let htmlStream: ReadableStream<Uint8Array>;
155
296
  try {
156
297
  htmlStream = await renderSsrStream(wrappedElement, {
157
298
  bootstrapScriptContent: navContext.bootstrapScriptContent || undefined,
158
299
  deferSuspenseFor: navContext.deferSuspenseFor,
159
300
  signal: navContext.signal,
301
+ renderTimeoutMs,
160
302
  });
161
303
  } catch (renderError) {
162
- // SSR shell rendering failed the RSC stream contained an error
163
- // that wasn't caught by any error boundary in the decoded tree.
164
- // Wrap in SsrStreamError so the RSC entry can handle it without
165
- // re-executing server components via renderDenyPage.
166
- // See LOCAL-293.
167
- console.error(
168
- '[timber] SSR shell failed from RSC stream error:',
169
- formatSsrError(renderError)
170
- );
304
+ logRenderError({ method: '', path: '', error: renderError });
171
305
  throw new SsrStreamError(
172
306
  'SSR renderToReadableStream failed due to RSC stream error',
173
307
  renderError
174
308
  );
175
309
  }
176
310
 
311
+ const _renderEnd = performance.now();
312
+
177
313
  // Inject metadata into <head>, then interleave RSC payload chunks
178
314
  // into the body as they arrive from the tee'd RSC stream.
179
315
  let outputStream = injectHead(htmlStream, navContext.headHtml);
180
- outputStream = injectRscPayload(outputStream, navContext.rscStream);
316
+ outputStream = injectRscPayload(outputStream, navContext.rscStream, renderTimeoutMs);
317
+ const _pipelineEnd = performance.now();
318
+
319
+ navContext._ssrTimings = {
320
+ decodeMs: Math.round(_decodeEnd - _ssrStart),
321
+ shellMs: Math.round(_renderEnd - _decodeEnd),
322
+ pipeMs: 0,
323
+ pipelineMs: Math.round(_pipelineEnd - _renderEnd),
324
+ totalMs: Math.round(_pipelineEnd - _ssrStart),
325
+ nodeStreams: false,
326
+ };
181
327
 
182
328
  // Build and return the Response.
183
329
  return buildSsrResponse(outputStream, navContext.statusCode, navContext.responseHeaders);