@timber-js/app 0.2.0-alpha.9 → 0.2.0-alpha.90

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 (610) hide show
  1. package/dist/_chunks/actions-DLnUaR65.js +421 -0
  2. package/dist/_chunks/actions-DLnUaR65.js.map +1 -0
  3. package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-HS0LGUl2.js} +1 -1
  4. package/dist/_chunks/als-registry-HS0LGUl2.js.map +1 -0
  5. package/dist/_chunks/chunk-BYIpzuS7.js +39 -0
  6. package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
  7. package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
  8. package/dist/_chunks/define-C77ScO0m.js +106 -0
  9. package/dist/_chunks/define-C77ScO0m.js.map +1 -0
  10. package/dist/_chunks/define-Itxvcd7F.js +199 -0
  11. package/dist/_chunks/define-Itxvcd7F.js.map +1 -0
  12. package/dist/_chunks/define-cookie-BowvzoP0.js +94 -0
  13. package/dist/_chunks/define-cookie-BowvzoP0.js.map +1 -0
  14. package/dist/_chunks/{format-DviM89f0.js → dev-warnings-DpGRGoDi.js} +5 -44
  15. package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +1 -0
  16. package/dist/_chunks/format-CYBGxKtc.js +14 -0
  17. package/dist/_chunks/format-CYBGxKtc.js.map +1 -0
  18. package/dist/_chunks/{interception-BOoWmLUA.js → interception-DRlhJWbu.js} +219 -97
  19. package/dist/_chunks/interception-DRlhJWbu.js.map +1 -0
  20. package/dist/_chunks/merge-search-params-Cm_KIWDX.js +41 -0
  21. package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +1 -0
  22. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DS3eKNmf.js} +1 -1
  23. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
  24. package/dist/_chunks/request-context-CK5tZqIP.js +478 -0
  25. package/dist/_chunks/request-context-CK5tZqIP.js.map +1 -0
  26. package/dist/_chunks/schema-bridge-C3xl_vfb.js +86 -0
  27. package/dist/_chunks/schema-bridge-C3xl_vfb.js.map +1 -0
  28. package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
  29. package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
  30. package/dist/_chunks/segment-context-fHFLF1PE.js +34 -0
  31. package/dist/_chunks/segment-context-fHFLF1PE.js.map +1 -0
  32. package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-DzuI0bIV.js} +1 -1
  33. package/dist/_chunks/{ssr-data-MjmprTmO.js.map → ssr-data-DzuI0bIV.js.map} +1 -1
  34. package/dist/_chunks/stale-reload-BX5gL1r-.js +64 -0
  35. package/dist/_chunks/stale-reload-BX5gL1r-.js.map +1 -0
  36. package/dist/_chunks/{tracing-CemImE6h.js → tracing-CCYbKn5n.js} +60 -9
  37. package/dist/_chunks/tracing-CCYbKn5n.js.map +1 -0
  38. package/dist/_chunks/use-params-Br9YSUFV.js +295 -0
  39. package/dist/_chunks/use-params-Br9YSUFV.js.map +1 -0
  40. package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-BiV5GJgm.js} +7 -4
  41. package/dist/_chunks/use-query-states-BiV5GJgm.js.map +1 -0
  42. package/dist/adapters/cloudflare-dev.d.ts +109 -0
  43. package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
  44. package/dist/adapters/cloudflare-dev.js +73 -0
  45. package/dist/adapters/cloudflare-dev.js.map +1 -0
  46. package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
  47. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
  48. package/dist/adapters/cloudflare-kv-cache.js +95 -0
  49. package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
  50. package/dist/adapters/cloudflare.d.ts +148 -12
  51. package/dist/adapters/cloudflare.d.ts.map +1 -1
  52. package/dist/adapters/cloudflare.js +135 -11
  53. package/dist/adapters/cloudflare.js.map +1 -1
  54. package/dist/adapters/compress-module.d.ts.map +1 -1
  55. package/dist/adapters/nitro.d.ts +17 -1
  56. package/dist/adapters/nitro.d.ts.map +1 -1
  57. package/dist/adapters/nitro.js +56 -13
  58. package/dist/adapters/nitro.js.map +1 -1
  59. package/dist/cache/cache-api.d.ts +24 -0
  60. package/dist/cache/cache-api.d.ts.map +1 -0
  61. package/dist/cache/handler-store.d.ts +31 -0
  62. package/dist/cache/handler-store.d.ts.map +1 -0
  63. package/dist/cache/index.d.ts +23 -7
  64. package/dist/cache/index.d.ts.map +1 -1
  65. package/dist/cache/index.js +142 -80
  66. package/dist/cache/index.js.map +1 -1
  67. package/dist/cache/singleflight.d.ts +18 -1
  68. package/dist/cache/singleflight.d.ts.map +1 -1
  69. package/dist/cache/sizeof.d.ts +22 -0
  70. package/dist/cache/sizeof.d.ts.map +1 -0
  71. package/dist/cache/timber-cache.d.ts +1 -1
  72. package/dist/cache/timber-cache.d.ts.map +1 -1
  73. package/dist/cli.d.ts +6 -1
  74. package/dist/cli.d.ts.map +1 -1
  75. package/dist/cli.js +8 -3
  76. package/dist/cli.js.map +1 -1
  77. package/dist/client/browser-dev.d.ts +27 -1
  78. package/dist/client/browser-dev.d.ts.map +1 -1
  79. package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
  80. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
  81. package/dist/client/browser-entry/hmr.d.ts +21 -0
  82. package/dist/client/browser-entry/hmr.d.ts.map +1 -0
  83. package/dist/client/browser-entry/hydrate.d.ts +46 -0
  84. package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
  85. package/dist/client/browser-entry/index.d.ts +30 -0
  86. package/dist/client/browser-entry/index.d.ts.map +1 -0
  87. package/dist/client/browser-entry/post-hydration.d.ts +26 -0
  88. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
  89. package/dist/client/browser-entry/router-init.d.ts +23 -0
  90. package/dist/client/browser-entry/router-init.d.ts.map +1 -0
  91. package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
  92. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
  93. package/dist/client/browser-entry/scroll.d.ts +19 -0
  94. package/dist/client/browser-entry/scroll.d.ts.map +1 -0
  95. package/dist/client/error-boundary.d.ts +12 -5
  96. package/dist/client/error-boundary.d.ts.map +1 -1
  97. package/dist/client/error-boundary.js +10 -4
  98. package/dist/client/error-boundary.js.map +1 -1
  99. package/dist/client/error-reconstituter.d.ts +54 -0
  100. package/dist/client/error-reconstituter.d.ts.map +1 -0
  101. package/dist/client/form.d.ts +6 -3
  102. package/dist/client/form.d.ts.map +1 -1
  103. package/dist/client/history.d.ts +19 -4
  104. package/dist/client/history.d.ts.map +1 -1
  105. package/dist/client/index.d.ts +9 -21
  106. package/dist/client/index.d.ts.map +1 -1
  107. package/dist/client/index.js +229 -1018
  108. package/dist/client/index.js.map +1 -1
  109. package/dist/client/internal.d.ts +18 -0
  110. package/dist/client/internal.d.ts.map +1 -0
  111. package/dist/client/internal.js +890 -0
  112. package/dist/client/internal.js.map +1 -0
  113. package/dist/client/link-pending-store.d.ts +63 -0
  114. package/dist/client/link-pending-store.d.ts.map +1 -0
  115. package/dist/client/link.d.ts +62 -55
  116. package/dist/client/link.d.ts.map +1 -1
  117. package/dist/client/nav-link-store.d.ts +36 -0
  118. package/dist/client/nav-link-store.d.ts.map +1 -0
  119. package/dist/client/navigation-api-types.d.ts +90 -0
  120. package/dist/client/navigation-api-types.d.ts.map +1 -0
  121. package/dist/client/navigation-api.d.ts +115 -0
  122. package/dist/client/navigation-api.d.ts.map +1 -0
  123. package/dist/client/navigation-context.d.ts +13 -2
  124. package/dist/client/navigation-context.d.ts.map +1 -1
  125. package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +42 -8
  126. package/dist/client/navigation-root.d.ts.map +1 -0
  127. package/dist/client/nuqs-adapter.d.ts.map +1 -1
  128. package/dist/client/router-ref.d.ts +1 -1
  129. package/dist/client/router.d.ts +70 -4
  130. package/dist/client/router.d.ts.map +1 -1
  131. package/dist/client/rsc-fetch.d.ts +38 -3
  132. package/dist/client/rsc-fetch.d.ts.map +1 -1
  133. package/dist/client/segment-cache.d.ts +1 -1
  134. package/dist/client/segment-cache.d.ts.map +1 -1
  135. package/dist/client/segment-outlet.d.ts +63 -0
  136. package/dist/client/segment-outlet.d.ts.map +1 -0
  137. package/dist/client/ssr-data.d.ts +13 -4
  138. package/dist/client/ssr-data.d.ts.map +1 -1
  139. package/dist/client/stale-reload.d.ts +15 -0
  140. package/dist/client/stale-reload.d.ts.map +1 -1
  141. package/dist/client/top-loader.d.ts +5 -5
  142. package/dist/client/top-loader.d.ts.map +1 -1
  143. package/dist/client/use-link-status.d.ts +5 -5
  144. package/dist/client/use-link-status.d.ts.map +1 -1
  145. package/dist/client/use-params.d.ts +6 -4
  146. package/dist/client/use-params.d.ts.map +1 -1
  147. package/dist/client/{use-navigation-pending.d.ts → use-pending-navigation.d.ts} +4 -4
  148. package/dist/client/use-pending-navigation.d.ts.map +1 -0
  149. package/dist/client/use-query-states.d.ts +1 -1
  150. package/dist/client/use-query-states.d.ts.map +1 -1
  151. package/dist/client/use-router.d.ts +1 -1
  152. package/dist/codec.d.ts +33 -0
  153. package/dist/codec.d.ts.map +1 -0
  154. package/dist/codec.js +2 -0
  155. package/dist/config-types.d.ts +266 -0
  156. package/dist/config-types.d.ts.map +1 -0
  157. package/dist/config-validation.d.ts +51 -0
  158. package/dist/config-validation.d.ts.map +1 -0
  159. package/dist/content/index.d.ts +1 -10
  160. package/dist/content/index.d.ts.map +1 -1
  161. package/dist/content/index.js +0 -2
  162. package/dist/cookies/define-cookie.d.ts +35 -14
  163. package/dist/cookies/define-cookie.d.ts.map +1 -1
  164. package/dist/cookies/index.js +1 -83
  165. package/dist/fonts/bundle.d.ts +48 -0
  166. package/dist/fonts/bundle.d.ts.map +1 -0
  167. package/dist/fonts/css.d.ts +1 -0
  168. package/dist/fonts/css.d.ts.map +1 -1
  169. package/dist/fonts/dev-middleware.d.ts +22 -0
  170. package/dist/fonts/dev-middleware.d.ts.map +1 -0
  171. package/dist/fonts/pipeline.d.ts +138 -0
  172. package/dist/fonts/pipeline.d.ts.map +1 -0
  173. package/dist/fonts/transform.d.ts +72 -0
  174. package/dist/fonts/transform.d.ts.map +1 -0
  175. package/dist/fonts/types.d.ts +45 -1
  176. package/dist/fonts/types.d.ts.map +1 -1
  177. package/dist/fonts/virtual-modules.d.ts +59 -0
  178. package/dist/fonts/virtual-modules.d.ts.map +1 -0
  179. package/dist/index.d.ts +45 -190
  180. package/dist/index.d.ts.map +1 -1
  181. package/dist/index.js +4294 -2453
  182. package/dist/index.js.map +1 -1
  183. package/dist/plugin-context.d.ts +107 -0
  184. package/dist/plugin-context.d.ts.map +1 -0
  185. package/dist/plugins/adapter-build.d.ts +1 -1
  186. package/dist/plugins/adapter-build.d.ts.map +1 -1
  187. package/dist/plugins/build-manifest.d.ts +2 -2
  188. package/dist/plugins/build-manifest.d.ts.map +1 -1
  189. package/dist/plugins/build-report.d.ts +3 -3
  190. package/dist/plugins/build-report.d.ts.map +1 -1
  191. package/dist/plugins/client-chunks.d.ts +32 -0
  192. package/dist/plugins/client-chunks.d.ts.map +1 -0
  193. package/dist/plugins/content.d.ts +1 -1
  194. package/dist/plugins/content.d.ts.map +1 -1
  195. package/dist/plugins/dev-404-page.d.ts +56 -0
  196. package/dist/plugins/dev-404-page.d.ts.map +1 -0
  197. package/dist/plugins/dev-browser-logs.d.ts +84 -0
  198. package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
  199. package/dist/plugins/dev-error-overlay.d.ts +49 -9
  200. package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
  201. package/dist/plugins/dev-error-page.d.ts +58 -0
  202. package/dist/plugins/dev-error-page.d.ts.map +1 -0
  203. package/dist/plugins/dev-logs.d.ts +1 -1
  204. package/dist/plugins/dev-logs.d.ts.map +1 -1
  205. package/dist/plugins/dev-server.d.ts +1 -1
  206. package/dist/plugins/dev-server.d.ts.map +1 -1
  207. package/dist/plugins/dev-terminal-error.d.ts +28 -0
  208. package/dist/plugins/dev-terminal-error.d.ts.map +1 -0
  209. package/dist/plugins/entries.d.ts +1 -1
  210. package/dist/plugins/entries.d.ts.map +1 -1
  211. package/dist/plugins/fonts.d.ts +17 -73
  212. package/dist/plugins/fonts.d.ts.map +1 -1
  213. package/dist/plugins/mdx.d.ts +1 -1
  214. package/dist/plugins/mdx.d.ts.map +1 -1
  215. package/dist/plugins/routing.d.ts +1 -1
  216. package/dist/plugins/routing.d.ts.map +1 -1
  217. package/dist/plugins/server-bundle.d.ts.map +1 -1
  218. package/dist/plugins/shims.d.ts +6 -5
  219. package/dist/plugins/shims.d.ts.map +1 -1
  220. package/dist/plugins/static-build.d.ts +4 -4
  221. package/dist/plugins/static-build.d.ts.map +1 -1
  222. package/dist/routing/codegen.d.ts +2 -2
  223. package/dist/routing/codegen.d.ts.map +1 -1
  224. package/dist/routing/convention-lint.d.ts +41 -0
  225. package/dist/routing/convention-lint.d.ts.map +1 -0
  226. package/dist/routing/index.d.ts +2 -0
  227. package/dist/routing/index.d.ts.map +1 -1
  228. package/dist/routing/index.js +3 -2
  229. package/dist/routing/scanner.d.ts.map +1 -1
  230. package/dist/routing/segment-classify.d.ts +46 -0
  231. package/dist/routing/segment-classify.d.ts.map +1 -0
  232. package/dist/routing/status-file-lint.d.ts +2 -1
  233. package/dist/routing/status-file-lint.d.ts.map +1 -1
  234. package/dist/routing/types.d.ts +16 -4
  235. package/dist/routing/types.d.ts.map +1 -1
  236. package/dist/rsc-runtime/rsc.d.ts +1 -1
  237. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  238. package/dist/rsc-runtime/ssr.d.ts +12 -0
  239. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  240. package/dist/schema-bridge.d.ts +76 -0
  241. package/dist/schema-bridge.d.ts.map +1 -0
  242. package/dist/search-params/define.d.ts +139 -0
  243. package/dist/search-params/define.d.ts.map +1 -0
  244. package/dist/search-params/index.d.ts +4 -7
  245. package/dist/search-params/index.d.ts.map +1 -1
  246. package/dist/search-params/index.js +32 -441
  247. package/dist/search-params/index.js.map +1 -1
  248. package/dist/search-params/registry.d.ts +2 -2
  249. package/dist/search-params/registry.d.ts.map +1 -1
  250. package/dist/search-params/wrappers.d.ts +53 -0
  251. package/dist/search-params/wrappers.d.ts.map +1 -0
  252. package/dist/segment-params/define.d.ts +78 -0
  253. package/dist/segment-params/define.d.ts.map +1 -0
  254. package/dist/segment-params/index.d.ts +3 -0
  255. package/dist/segment-params/index.d.ts.map +1 -0
  256. package/dist/segment-params/index.js +2 -0
  257. package/dist/server/access-gate.d.ts +4 -0
  258. package/dist/server/access-gate.d.ts.map +1 -1
  259. package/dist/server/action-client.d.ts +41 -6
  260. package/dist/server/action-client.d.ts.map +1 -1
  261. package/dist/server/action-encryption.d.ts +76 -0
  262. package/dist/server/action-encryption.d.ts.map +1 -0
  263. package/dist/server/action-handler.d.ts +7 -0
  264. package/dist/server/action-handler.d.ts.map +1 -1
  265. package/dist/server/actions.d.ts +3 -6
  266. package/dist/server/actions.d.ts.map +1 -1
  267. package/dist/server/als-registry.d.ts +32 -4
  268. package/dist/server/als-registry.d.ts.map +1 -1
  269. package/dist/server/build-manifest.d.ts +2 -2
  270. package/dist/server/build-manifest.d.ts.map +1 -1
  271. package/dist/server/debug.d.ts +1 -1
  272. package/dist/server/default-logger.d.ts +22 -0
  273. package/dist/server/default-logger.d.ts.map +1 -0
  274. package/dist/server/deny-page-resolver.d.ts +52 -0
  275. package/dist/server/deny-page-resolver.d.ts.map +1 -0
  276. package/dist/server/deny-renderer.d.ts.map +1 -1
  277. package/dist/server/dev-holding-server.d.ts +52 -0
  278. package/dist/server/dev-holding-server.d.ts.map +1 -0
  279. package/dist/server/dev-source-map.d.ts +22 -0
  280. package/dist/server/dev-source-map.d.ts.map +1 -0
  281. package/dist/server/dev-warnings.d.ts +1 -21
  282. package/dist/server/dev-warnings.d.ts.map +1 -1
  283. package/dist/server/early-hints.d.ts +13 -5
  284. package/dist/server/early-hints.d.ts.map +1 -1
  285. package/dist/server/error-boundary-wrapper.d.ts +7 -1
  286. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  287. package/dist/server/fallback-error.d.ts +12 -7
  288. package/dist/server/fallback-error.d.ts.map +1 -1
  289. package/dist/server/flight-injection-state.d.ts +66 -0
  290. package/dist/server/flight-injection-state.d.ts.map +1 -0
  291. package/dist/server/flight-scripts.d.ts +42 -0
  292. package/dist/server/flight-scripts.d.ts.map +1 -0
  293. package/dist/server/flush.d.ts.map +1 -1
  294. package/dist/server/form-data.d.ts +29 -0
  295. package/dist/server/form-data.d.ts.map +1 -1
  296. package/dist/server/html-injectors.d.ts +51 -11
  297. package/dist/server/html-injectors.d.ts.map +1 -1
  298. package/dist/server/index.d.ts +5 -43
  299. package/dist/server/index.d.ts.map +1 -1
  300. package/dist/server/index.js +195 -2800
  301. package/dist/server/index.js.map +1 -1
  302. package/dist/server/internal.d.ts +46 -0
  303. package/dist/server/internal.d.ts.map +1 -0
  304. package/dist/server/internal.js +2900 -0
  305. package/dist/server/internal.js.map +1 -0
  306. package/dist/server/logger.d.ts +25 -7
  307. package/dist/server/logger.d.ts.map +1 -1
  308. package/dist/server/middleware-runner.d.ts +19 -4
  309. package/dist/server/middleware-runner.d.ts.map +1 -1
  310. package/dist/server/node-stream-transforms.d.ts +113 -0
  311. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  312. package/dist/server/page-deny-boundary.d.ts +31 -0
  313. package/dist/server/page-deny-boundary.d.ts.map +1 -0
  314. package/dist/server/pipeline-interception.d.ts +1 -1
  315. package/dist/server/pipeline-interception.d.ts.map +1 -1
  316. package/dist/server/pipeline-metadata.d.ts +6 -0
  317. package/dist/server/pipeline-metadata.d.ts.map +1 -1
  318. package/dist/server/pipeline.d.ts +52 -10
  319. package/dist/server/pipeline.d.ts.map +1 -1
  320. package/dist/server/primitives.d.ts +69 -18
  321. package/dist/server/primitives.d.ts.map +1 -1
  322. package/dist/server/render-timeout.d.ts +51 -0
  323. package/dist/server/render-timeout.d.ts.map +1 -0
  324. package/dist/server/request-context.d.ts +112 -43
  325. package/dist/server/request-context.d.ts.map +1 -1
  326. package/dist/server/route-element-builder.d.ts +27 -1
  327. package/dist/server/route-element-builder.d.ts.map +1 -1
  328. package/dist/server/route-handler.d.ts.map +1 -1
  329. package/dist/server/route-matcher.d.ts +16 -2
  330. package/dist/server/route-matcher.d.ts.map +1 -1
  331. package/dist/server/rsc-entry/api-handler.d.ts +2 -2
  332. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  333. package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
  334. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  335. package/dist/server/rsc-entry/helpers.d.ts +48 -5
  336. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  337. package/dist/server/rsc-entry/index.d.ts +20 -3
  338. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  339. package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
  340. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  341. package/dist/server/rsc-entry/rsc-stream.d.ts +14 -1
  342. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  343. package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
  344. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  345. package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
  346. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  347. package/dist/server/safe-load.d.ts +46 -0
  348. package/dist/server/safe-load.d.ts.map +1 -0
  349. package/dist/server/sensitive-fields.d.ts +74 -0
  350. package/dist/server/sensitive-fields.d.ts.map +1 -0
  351. package/dist/server/sitemap-generator.d.ts +129 -0
  352. package/dist/server/sitemap-generator.d.ts.map +1 -0
  353. package/dist/server/sitemap-handler.d.ts +22 -0
  354. package/dist/server/sitemap-handler.d.ts.map +1 -0
  355. package/dist/server/slot-resolver.d.ts +1 -1
  356. package/dist/server/slot-resolver.d.ts.map +1 -1
  357. package/dist/server/ssr-entry.d.ts +23 -0
  358. package/dist/server/ssr-entry.d.ts.map +1 -1
  359. package/dist/server/ssr-render.d.ts +39 -21
  360. package/dist/server/ssr-render.d.ts.map +1 -1
  361. package/dist/server/ssr-wrappers.d.ts +50 -0
  362. package/dist/server/ssr-wrappers.d.ts.map +1 -0
  363. package/dist/server/status-code-resolver.d.ts +1 -1
  364. package/dist/server/status-code-resolver.d.ts.map +1 -1
  365. package/dist/server/stream-utils.d.ts +36 -0
  366. package/dist/server/stream-utils.d.ts.map +1 -0
  367. package/dist/server/tracing.d.ts +4 -4
  368. package/dist/server/tracing.d.ts.map +1 -1
  369. package/dist/server/tree-builder.d.ts +22 -19
  370. package/dist/server/tree-builder.d.ts.map +1 -1
  371. package/dist/server/types.d.ts +1 -4
  372. package/dist/server/types.d.ts.map +1 -1
  373. package/dist/server/version-skew.d.ts +61 -0
  374. package/dist/server/version-skew.d.ts.map +1 -0
  375. package/dist/shared/merge-search-params.d.ts +22 -0
  376. package/dist/shared/merge-search-params.d.ts.map +1 -0
  377. package/dist/shims/font-google.d.ts +1 -1
  378. package/dist/shims/font-google.d.ts.map +1 -1
  379. package/dist/shims/font-google.js +42 -0
  380. package/dist/shims/font-google.js.map +1 -0
  381. package/dist/shims/font-local.d.ts +26 -0
  382. package/dist/shims/font-local.d.ts.map +1 -0
  383. package/dist/shims/font-local.js +20 -0
  384. package/dist/shims/font-local.js.map +1 -0
  385. package/dist/shims/headers.d.ts +2 -1
  386. package/dist/shims/headers.d.ts.map +1 -1
  387. package/dist/shims/navigation-client.d.ts +1 -1
  388. package/dist/shims/navigation-client.d.ts.map +1 -1
  389. package/dist/shims/navigation.d.ts +3 -2
  390. package/dist/shims/navigation.d.ts.map +1 -1
  391. package/dist/utils/directive-parser.d.ts +5 -2
  392. package/dist/utils/directive-parser.d.ts.map +1 -1
  393. package/dist/utils/state-machine.d.ts +80 -0
  394. package/dist/utils/state-machine.d.ts.map +1 -0
  395. package/package.json +51 -16
  396. package/src/adapters/cloudflare-dev.ts +177 -0
  397. package/src/adapters/cloudflare-kv-cache.ts +142 -0
  398. package/src/adapters/cloudflare.ts +342 -28
  399. package/src/adapters/compress-module.ts +24 -4
  400. package/src/adapters/nitro.ts +52 -8
  401. package/src/adapters/wrangler.d.ts +7 -0
  402. package/src/cache/cache-api.ts +38 -0
  403. package/src/cache/handler-store.ts +68 -0
  404. package/src/cache/index.ts +81 -18
  405. package/src/cache/singleflight.ts +62 -4
  406. package/src/cache/sizeof.ts +31 -0
  407. package/src/cache/timber-cache.ts +24 -20
  408. package/src/cli.ts +16 -6
  409. package/src/client/browser-dev.ts +128 -1
  410. package/src/client/browser-entry/action-dispatch.ts +116 -0
  411. package/src/client/browser-entry/hmr.ts +81 -0
  412. package/src/client/browser-entry/hydrate.ts +145 -0
  413. package/src/client/browser-entry/index.ts +143 -0
  414. package/src/client/browser-entry/post-hydration.ts +119 -0
  415. package/src/client/browser-entry/router-init.ts +193 -0
  416. package/src/client/browser-entry/rsc-stream.ts +157 -0
  417. package/src/client/browser-entry/scroll.ts +27 -0
  418. package/src/client/error-boundary.tsx +48 -16
  419. package/src/client/error-reconstituter.tsx +65 -0
  420. package/src/client/form.tsx +14 -7
  421. package/src/client/history.ts +26 -4
  422. package/src/client/index.ts +65 -38
  423. package/src/client/internal.ts +57 -0
  424. package/src/client/link-pending-store.ts +111 -0
  425. package/src/client/link.tsx +342 -113
  426. package/src/client/nav-link-store.ts +47 -0
  427. package/src/client/navigation-api-types.ts +112 -0
  428. package/src/client/navigation-api.ts +332 -0
  429. package/src/client/navigation-context.ts +31 -6
  430. package/src/client/navigation-root.tsx +342 -0
  431. package/src/client/nuqs-adapter.tsx +16 -3
  432. package/src/client/router-ref.ts +1 -1
  433. package/src/client/router.ts +299 -72
  434. package/src/client/rsc-fetch.ts +97 -8
  435. package/src/client/segment-cache.ts +1 -1
  436. package/src/client/segment-outlet.tsx +86 -0
  437. package/src/client/ssr-data.ts +13 -5
  438. package/src/client/stale-reload.ts +72 -3
  439. package/src/client/top-loader.tsx +18 -6
  440. package/src/client/use-link-status.ts +7 -7
  441. package/src/client/use-params.ts +7 -5
  442. package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
  443. package/src/client/use-query-states.ts +9 -3
  444. package/src/client/use-router.ts +1 -1
  445. package/src/codec.ts +49 -0
  446. package/src/config-types.ts +264 -0
  447. package/src/config-validation.ts +303 -0
  448. package/src/content/index.ts +5 -13
  449. package/src/cookies/define-cookie.ts +78 -25
  450. package/src/cookies/index.ts +8 -0
  451. package/src/fonts/bundle.ts +142 -0
  452. package/src/fonts/css.ts +2 -1
  453. package/src/fonts/dev-middleware.ts +74 -0
  454. package/src/fonts/pipeline.ts +275 -0
  455. package/src/fonts/transform.ts +353 -0
  456. package/src/fonts/types.ts +50 -1
  457. package/src/fonts/virtual-modules.ts +159 -0
  458. package/src/index.ts +314 -355
  459. package/src/plugin-context.ts +240 -0
  460. package/src/plugins/adapter-build.ts +9 -3
  461. package/src/plugins/build-manifest.ts +13 -2
  462. package/src/plugins/build-report.ts +3 -3
  463. package/src/plugins/client-chunks.ts +65 -0
  464. package/src/plugins/content.ts +1 -1
  465. package/src/plugins/dev-404-page.ts +418 -0
  466. package/src/plugins/dev-browser-logs.ts +288 -0
  467. package/src/plugins/dev-error-overlay.ts +286 -42
  468. package/src/plugins/dev-error-page.ts +536 -0
  469. package/src/plugins/dev-logs.ts +1 -1
  470. package/src/plugins/dev-server.ts +146 -19
  471. package/src/plugins/dev-terminal-error.ts +217 -0
  472. package/src/plugins/entries.ts +111 -10
  473. package/src/plugins/fonts.ts +133 -638
  474. package/src/plugins/mdx.ts +1 -1
  475. package/src/plugins/routing.ts +213 -31
  476. package/src/plugins/server-action-exports.ts +1 -1
  477. package/src/plugins/server-bundle.ts +32 -1
  478. package/src/plugins/shims.ts +136 -35
  479. package/src/plugins/static-build.ts +17 -11
  480. package/src/routing/codegen.ts +273 -105
  481. package/src/routing/convention-lint.ts +356 -0
  482. package/src/routing/index.ts +2 -0
  483. package/src/routing/scanner.ts +93 -23
  484. package/src/routing/segment-classify.ts +89 -0
  485. package/src/routing/status-file-lint.ts +3 -2
  486. package/src/routing/types.ts +17 -4
  487. package/src/rsc-runtime/rsc.ts +2 -0
  488. package/src/rsc-runtime/ssr.ts +50 -0
  489. package/src/rsc-runtime/vendor-types.d.ts +7 -0
  490. package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
  491. package/src/search-params/define.ts +482 -0
  492. package/src/search-params/index.ts +14 -20
  493. package/src/search-params/registry.ts +2 -2
  494. package/src/search-params/wrappers.ts +85 -0
  495. package/src/segment-params/define.ts +279 -0
  496. package/src/segment-params/index.ts +9 -0
  497. package/src/server/access-gate.tsx +70 -29
  498. package/src/server/action-client.ts +88 -15
  499. package/src/server/action-encryption.ts +144 -0
  500. package/src/server/action-handler.ts +53 -6
  501. package/src/server/actions.ts +10 -9
  502. package/src/server/als-registry.ts +34 -6
  503. package/src/server/build-manifest.ts +10 -4
  504. package/src/server/compress.ts +25 -7
  505. package/src/server/debug.ts +1 -1
  506. package/src/server/default-logger.ts +99 -0
  507. package/src/server/deny-page-resolver.ts +154 -0
  508. package/src/server/deny-renderer.ts +24 -38
  509. package/src/server/dev-holding-server.ts +185 -0
  510. package/src/server/dev-source-map.ts +31 -0
  511. package/src/server/dev-warnings.ts +4 -49
  512. package/src/server/early-hints.ts +36 -15
  513. package/src/server/error-boundary-wrapper.ts +74 -22
  514. package/src/server/fallback-error.ts +74 -102
  515. package/src/server/flight-injection-state.ts +113 -0
  516. package/src/server/flight-scripts.ts +62 -0
  517. package/src/server/flush.ts +2 -1
  518. package/src/server/form-data.ts +76 -0
  519. package/src/server/html-injectors.ts +280 -120
  520. package/src/server/index.ts +25 -177
  521. package/src/server/internal.ts +169 -0
  522. package/src/server/logger.ts +44 -36
  523. package/src/server/middleware-runner.ts +31 -4
  524. package/src/server/node-stream-transforms.ts +509 -0
  525. package/src/server/page-deny-boundary.tsx +56 -0
  526. package/src/server/pipeline-interception.ts +17 -16
  527. package/src/server/pipeline-metadata.ts +13 -0
  528. package/src/server/pipeline.ts +261 -66
  529. package/src/server/primitives.ts +111 -28
  530. package/src/server/render-timeout.ts +108 -0
  531. package/src/server/request-context.ts +293 -132
  532. package/src/server/route-element-builder.ts +283 -191
  533. package/src/server/route-handler.ts +24 -4
  534. package/src/server/route-matcher.ts +31 -20
  535. package/src/server/rsc-entry/api-handler.ts +15 -16
  536. package/src/server/rsc-entry/error-renderer.ts +305 -89
  537. package/src/server/rsc-entry/helpers.ts +134 -5
  538. package/src/server/rsc-entry/index.ts +304 -111
  539. package/src/server/rsc-entry/rsc-payload.ts +65 -18
  540. package/src/server/rsc-entry/rsc-stream.ts +81 -13
  541. package/src/server/rsc-entry/ssr-bridge.ts +14 -5
  542. package/src/server/rsc-entry/ssr-renderer.ts +171 -38
  543. package/src/server/safe-load.ts +60 -0
  544. package/src/server/sensitive-fields.ts +230 -0
  545. package/src/server/sitemap-generator.ts +338 -0
  546. package/src/server/sitemap-handler.ts +126 -0
  547. package/src/server/slot-resolver.ts +244 -229
  548. package/src/server/ssr-entry.ts +215 -32
  549. package/src/server/ssr-render.ts +289 -67
  550. package/src/server/ssr-wrappers.tsx +139 -0
  551. package/src/server/status-code-resolver.ts +1 -1
  552. package/src/server/stream-utils.ts +213 -0
  553. package/src/server/tracing.ts +20 -9
  554. package/src/server/tree-builder.ts +92 -58
  555. package/src/server/types.ts +3 -6
  556. package/src/server/version-skew.ts +104 -0
  557. package/src/shared/merge-search-params.ts +55 -0
  558. package/src/shims/font-google.ts +1 -1
  559. package/src/shims/font-local.ts +34 -0
  560. package/src/shims/headers.ts +5 -1
  561. package/src/shims/navigation-client.ts +1 -1
  562. package/src/shims/navigation.ts +7 -2
  563. package/src/utils/directive-parser.ts +5 -2
  564. package/src/utils/state-machine.ts +111 -0
  565. package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
  566. package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
  567. package/dist/_chunks/format-DviM89f0.js.map +0 -1
  568. package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
  569. package/dist/_chunks/request-context-DIkVh_jG.js +0 -330
  570. package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
  571. package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
  572. package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
  573. package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
  574. package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
  575. package/dist/cache/register-cached-function.d.ts +0 -17
  576. package/dist/cache/register-cached-function.d.ts.map +0 -1
  577. package/dist/client/browser-entry.d.ts +0 -21
  578. package/dist/client/browser-entry.d.ts.map +0 -1
  579. package/dist/client/link-status-provider.d.ts +0 -11
  580. package/dist/client/link-status-provider.d.ts.map +0 -1
  581. package/dist/client/transition-root.d.ts.map +0 -1
  582. package/dist/client/use-navigation-pending.d.ts.map +0 -1
  583. package/dist/cookies/index.js.map +0 -1
  584. package/dist/plugins/cache-transform.d.ts +0 -36
  585. package/dist/plugins/cache-transform.d.ts.map +0 -1
  586. package/dist/plugins/dynamic-transform.d.ts +0 -72
  587. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  588. package/dist/search-params/analyze.d.ts +0 -54
  589. package/dist/search-params/analyze.d.ts.map +0 -1
  590. package/dist/search-params/builtin-codecs.d.ts +0 -105
  591. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  592. package/dist/search-params/codecs.d.ts +0 -53
  593. package/dist/search-params/codecs.d.ts.map +0 -1
  594. package/dist/search-params/create.d.ts +0 -106
  595. package/dist/search-params/create.d.ts.map +0 -1
  596. package/dist/server/prerender.d.ts +0 -77
  597. package/dist/server/prerender.d.ts.map +0 -1
  598. package/dist/server/response-cache.d.ts +0 -54
  599. package/dist/server/response-cache.d.ts.map +0 -1
  600. package/src/cache/register-cached-function.ts +0 -103
  601. package/src/client/browser-entry.ts +0 -678
  602. package/src/client/link-status-provider.tsx +0 -30
  603. package/src/client/transition-root.tsx +0 -166
  604. package/src/plugins/cache-transform.ts +0 -199
  605. package/src/plugins/dynamic-transform.ts +0 -161
  606. package/src/search-params/analyze.ts +0 -192
  607. package/src/search-params/builtin-codecs.ts +0 -228
  608. package/src/search-params/create.ts +0 -321
  609. package/src/server/prerender.ts +0 -139
  610. package/src/server/response-cache.ts +0 -410
@@ -173,4 +173,80 @@ export const coerce = {
173
173
  return undefined;
174
174
  }
175
175
  },
176
+
177
+ /**
178
+ * Coerce a date string to a Date object.
179
+ * Handles `<input type="date">` (`"2024-01-15"`), `<input type="datetime-local">`
180
+ * (`"2024-01-15T10:30"`), and full ISO 8601 strings.
181
+ * - Valid date string → `Date`
182
+ * - `""` / `undefined` / `null` → `undefined`
183
+ * - Invalid date strings → `undefined` (schema validation will catch this)
184
+ * - Impossible dates that `new Date()` silently normalizes (e.g. Feb 31) → `undefined`
185
+ */
186
+ date(value: unknown): Date | undefined {
187
+ if (value === undefined || value === null || value === '') return undefined;
188
+ if (value instanceof Date) return value;
189
+ if (typeof value !== 'string') return undefined;
190
+ const date = new Date(value);
191
+ if (Number.isNaN(date.getTime())) return undefined;
192
+
193
+ // Overflow detection: extract Y/M/D from the input string and verify
194
+ // they match the parsed Date components. new Date('2024-02-31') silently
195
+ // normalizes to March 2nd — we reject such inputs.
196
+ const ymdMatch = value.match(/^(\d{4})-(\d{2})-(\d{2})/);
197
+ if (ymdMatch) {
198
+ const inputYear = Number(ymdMatch[1]);
199
+ const inputMonth = Number(ymdMatch[2]);
200
+ const inputDay = Number(ymdMatch[3]);
201
+
202
+ // Use UTC methods for date-only and Z-suffixed strings to avoid
203
+ // timezone offset shifting the day. For datetime-local (no Z suffix),
204
+ // the Date constructor parses in local time, so use local methods.
205
+ const isUTC = value.length === 10 || value.endsWith('Z');
206
+ const parsedYear = isUTC ? date.getUTCFullYear() : date.getFullYear();
207
+ const parsedMonth = isUTC ? date.getUTCMonth() + 1 : date.getMonth() + 1;
208
+ const parsedDay = isUTC ? date.getUTCDate() : date.getDate();
209
+
210
+ if (inputYear !== parsedYear || inputMonth !== parsedMonth || inputDay !== parsedDay) {
211
+ return undefined;
212
+ }
213
+ }
214
+
215
+ return date;
216
+ },
217
+
218
+ /**
219
+ * Create a File coercion function with optional size and mime type validation.
220
+ * Returns the File if valid, `undefined` otherwise.
221
+ *
222
+ * ```ts
223
+ * // Basic — just checks it's a real File
224
+ * z.preprocess(coerce.file(), z.instanceof(File))
225
+ *
226
+ * // With constraints
227
+ * z.preprocess(
228
+ * coerce.file({ maxSize: 5 * 1024 * 1024, accept: ['image/png', 'image/jpeg'] }),
229
+ * z.instanceof(File)
230
+ * )
231
+ * ```
232
+ */
233
+ file(options?: { maxSize?: number; accept?: string[] }): (value: unknown) => File | undefined {
234
+ return (value: unknown): File | undefined => {
235
+ if (value === undefined || value === null || value === '') return undefined;
236
+ if (!(value instanceof File)) return undefined;
237
+
238
+ // Empty file input (no selection): browsers submit File with name="" and size=0
239
+ if (value.size === 0 && value.name === '') return undefined;
240
+
241
+ if (options?.maxSize !== undefined && value.size > options.maxSize) {
242
+ return undefined;
243
+ }
244
+
245
+ if (options?.accept !== undefined && !options.accept.includes(value.type)) {
246
+ return undefined;
247
+ }
248
+
249
+ return value;
250
+ };
251
+ },
176
252
  };
@@ -7,6 +7,179 @@
7
7
  * Design docs: 02-rendering-pipeline.md, 18-build-system.md §"Entry Files"
8
8
  */
9
9
 
10
+ // ─── Buffered Transform ──────────────────────────────────────────────────────
11
+
12
+ /**
13
+ * Options for the buffered transform stream.
14
+ */
15
+ export interface BufferedTransformOptions {
16
+ /**
17
+ * Flush synchronously once the buffer reaches this many bytes.
18
+ * Prevents unbounded memory growth for very large Fizz flushes.
19
+ * Default: Infinity (no byte limit — flush only on tick boundary).
20
+ */
21
+ readonly maxBufferByteLength?: number;
22
+ }
23
+
24
+ /**
25
+ * Buffer incoming chunks and coalesce them within a single event loop tick.
26
+ *
27
+ * React Fizz may emit multiple micro-chunks within a single flush (e.g.,
28
+ * opening tags, attributes, closing tags as separate writes). Without
29
+ * buffering, downstream transforms (especially flight injection) could
30
+ * see chunk boundaries in the middle of HTML tags or attribute values.
31
+ *
32
+ * This transform collects all chunks that arrive in the same tick and
33
+ * emits them as a single concatenated chunk on the next `setImmediate`.
34
+ * This ensures each output chunk represents a coherent HTML fragment
35
+ * from a single Fizz flush — safe for downstream script injection at
36
+ * chunk boundaries.
37
+ *
38
+ * **Not a polling loop.** Uses a single-shot `setImmediate` per flush
39
+ * cycle — no recursive scheduling, no busy-wait. See design/02 §"No Polling".
40
+ *
41
+ * Inspired by Next.js `createBufferedTransformStream`.
42
+ */
43
+ export function createBufferedTransformStream(
44
+ options: BufferedTransformOptions = {}
45
+ ): TransformStream<Uint8Array, Uint8Array> {
46
+ const { maxBufferByteLength = Infinity } = options;
47
+
48
+ let bufferedChunks: Uint8Array[] = [];
49
+ let bufferByteLength = 0;
50
+ let pendingFlush: Promise<void> | undefined;
51
+
52
+ const flush = (controller: TransformStreamDefaultController<Uint8Array>) => {
53
+ if (bufferedChunks.length === 0) return;
54
+
55
+ // Concatenate all buffered chunks into a single output chunk
56
+ const merged = new Uint8Array(bufferByteLength);
57
+ let offset = 0;
58
+ for (const chunk of bufferedChunks) {
59
+ merged.set(chunk, offset);
60
+ offset += chunk.byteLength;
61
+ }
62
+
63
+ bufferedChunks = [];
64
+ bufferByteLength = 0;
65
+
66
+ try {
67
+ controller.enqueue(merged);
68
+ } catch {
69
+ // Controller may be errored (e.g., stream cancelled) — ignore
70
+ }
71
+ };
72
+
73
+ const scheduleFlush = (controller: TransformStreamDefaultController<Uint8Array>) => {
74
+ if (pendingFlush) return;
75
+
76
+ // Single-shot setImmediate — fires once at the end of the current
77
+ // event loop iteration (check phase), then the promise resolves.
78
+ // NOT a recursive loop — no CPU spin risk.
79
+ pendingFlush = new Promise<void>((resolve) => {
80
+ setImmediate(() => {
81
+ try {
82
+ flush(controller);
83
+ } finally {
84
+ pendingFlush = undefined;
85
+ resolve();
86
+ }
87
+ });
88
+ });
89
+ };
90
+
91
+ return new TransformStream<Uint8Array, Uint8Array>({
92
+ transform(chunk, controller) {
93
+ bufferedChunks.push(chunk);
94
+ bufferByteLength += chunk.byteLength;
95
+
96
+ if (bufferByteLength >= maxBufferByteLength) {
97
+ // Synchronous flush — buffer is too large to hold
98
+ flush(controller);
99
+ } else {
100
+ // Schedule a deferred flush for end of this tick
101
+ scheduleFlush(controller);
102
+ }
103
+ },
104
+ flush() {
105
+ // Wait for any pending scheduled flush to complete
106
+ return pendingFlush;
107
+ },
108
+ });
109
+ }
110
+
111
+ // ─── Move Suffix Transform ───────────────────────────────────────────────────
112
+
113
+ const SUFFIX = '</body></html>';
114
+
115
+ /**
116
+ * Move `</body></html>` to the end of the stream.
117
+ *
118
+ * React's renderToReadableStream emits `</body></html>` as part of the
119
+ * shell chunk. Content that arrives after the shell (Suspense resolutions,
120
+ * RSC script tags) would appear after the closing tags, producing invalid
121
+ * HTML like `</body></html><script>...</script>`.
122
+ *
123
+ * This transform strips the suffix when first encountered and re-emits
124
+ * it in `flush()` — after all content has passed through. If no suffix
125
+ * is found, it's appended anyway to ensure well-formed HTML.
126
+ *
127
+ * Equivalent to Next.js's `createMoveSuffixStream`.
128
+ */
129
+ export function createMoveSuffixStream(): TransformStream<Uint8Array, Uint8Array> {
130
+ const encoder = new TextEncoder();
131
+ const suffixBytes = encoder.encode(SUFFIX);
132
+ let foundSuffix = false;
133
+
134
+ return new TransformStream<Uint8Array, Uint8Array>({
135
+ transform(chunk, controller) {
136
+ if (foundSuffix) {
137
+ controller.enqueue(chunk);
138
+ return;
139
+ }
140
+
141
+ // Search for the suffix in this chunk
142
+ const text = new TextDecoder().decode(chunk, { stream: true });
143
+ const idx = text.indexOf(SUFFIX);
144
+ if (idx === -1) {
145
+ controller.enqueue(chunk);
146
+ return;
147
+ }
148
+
149
+ foundSuffix = true;
150
+
151
+ // If the entire chunk is exactly the suffix, skip it
152
+ if (chunk.byteLength === suffixBytes.byteLength) return;
153
+
154
+ // Emit content before the suffix
155
+ const before = text.slice(0, idx);
156
+ const after = text.slice(idx + SUFFIX.length);
157
+ if (before) controller.enqueue(encoder.encode(before));
158
+ // Emit content after the suffix (shouldn't normally exist,
159
+ // but handle it for robustness)
160
+ if (after) controller.enqueue(encoder.encode(after));
161
+ },
162
+ flush(controller) {
163
+ // Always emit the suffix at the very end — even if we didn't
164
+ // find it in the input (ensures well-formed HTML).
165
+ controller.enqueue(suffixBytes);
166
+ },
167
+ });
168
+ }
169
+
170
+ // ─── Injection Transforms ────────────────────────────────────────────────────
171
+
172
+ import { createMachine } from '../utils/state-machine.js';
173
+ import { flightChunkScript } from './flight-scripts.js';
174
+ import {
175
+ flightInjectionTransitions,
176
+ isHtmlDone,
177
+ isPullDone,
178
+ type FlightInjectionState,
179
+ type FlightInjectionEvent,
180
+ } from './flight-injection-state.js';
181
+ import { withTimeout, RenderTimeoutError } from './render-timeout.js';
182
+
10
183
  /**
11
184
  * Inject HTML content before a closing tag in the stream.
12
185
  *
@@ -95,22 +268,6 @@ export function injectScripts(
95
268
  return createInjector(stream, scriptsHtml, '</body>');
96
269
  }
97
270
 
98
- /**
99
- * Escape a string for safe embedding inside a `<script>` tag within
100
- * a JSON-encoded value.
101
- *
102
- * Only needs to prevent `</script>` from closing the tag early and
103
- * handle U+2028/U+2029 (line/paragraph separators valid in JSON but
104
- * historically problematic in JS). Since we use JSON.stringify for the
105
- * outer encoding, we only escape `<` and the line separators.
106
- */
107
- function htmlEscapeJsonString(str: string): string {
108
- return str
109
- .replace(/</g, '\\u003c')
110
- .replace(/\u2028/g, '\\u2028')
111
- .replace(/\u2029/g, '\\u2029');
112
- }
113
-
114
271
  /**
115
272
  * Transform an RSC Flight stream into a stream of inline `<script>` tags.
116
273
  *
@@ -118,42 +275,42 @@ function htmlEscapeJsonString(str: string): string {
118
275
  * transform) drives reads from the RSC stream on demand. No background
119
276
  * reader, no shared mutable arrays, no race conditions.
120
277
  *
121
- * Each RSC chunk becomes:
122
- * <script>(self.__timber_f=self.__timber_f||[]).push([1,"escaped_chunk"])</script>
123
- *
124
- * The first chunk emitted is the bootstrap signal [0] which the client
125
- * uses to initialize its buffer.
126
- *
127
- * Uses JSON-encoded typed tuples matching the pattern from Next.js:
128
- * [0] — bootstrap signal
129
- * [1, data] — RSC Flight data chunk (UTF-8 string)
278
+ * Each RSC chunk becomes a `<script>self.__timber_f.push([1,"data"])</script>`.
279
+ * The init script (which creates __timber_f) is in `<head>` via
280
+ * flightInitScript() — see flight-scripts.ts.
130
281
  */
131
282
  export function createInlinedRscStream(
132
- rscStream: ReadableStream<Uint8Array>
283
+ rscStream: ReadableStream<Uint8Array>,
284
+ renderTimeoutMs?: number
133
285
  ): ReadableStream<Uint8Array> {
134
286
  const encoder = new TextEncoder();
135
287
  const rscReader = rscStream.getReader();
136
288
  const decoder = new TextDecoder('utf-8', { fatal: true });
289
+ const timeoutMs = renderTimeoutMs ?? 30_000;
137
290
 
138
291
  return new ReadableStream<Uint8Array>({
139
- start(controller) {
140
- // Emit bootstrap signal tells the client that __timber_f is active
141
- const bootstrap = `<script>(self.__timber_f=self.__timber_f||[]).push(${htmlEscapeJsonString(JSON.stringify([0]))})</script>`;
142
- controller.enqueue(encoder.encode(bootstrap));
143
- },
292
+ // No bootstrap signal here — the init script is in <head> via
293
+ // flightInitScript() (see flight-scripts.ts). This ensures the
294
+ // __timber_f array exists before any chunk scripts execute.
144
295
  async pull(controller) {
145
296
  try {
146
- const { done, value } = await rscReader.read();
297
+ const readPromise = rscReader.read();
298
+ const { done, value } =
299
+ timeoutMs > 0
300
+ ? await withTimeout(readPromise, timeoutMs, 'RSC stream read timed out')
301
+ : await readPromise;
147
302
  if (done) {
148
303
  controller.close();
149
304
  return;
150
305
  }
151
306
  if (value) {
152
307
  const decoded = decoder.decode(value, { stream: true });
153
- const escaped = htmlEscapeJsonString(JSON.stringify([1, decoded]));
154
- controller.enqueue(encoder.encode(`<script>self.__timber_f.push(${escaped})</script>`));
308
+ controller.enqueue(encoder.encode(flightChunkScript(decoded)));
155
309
  }
156
310
  } catch (error) {
311
+ if (error instanceof RenderTimeoutError) {
312
+ rscReader.cancel(error).catch(() => {});
313
+ }
157
314
  controller.error(error);
158
315
  }
159
316
  },
@@ -162,67 +319,84 @@ export function createInlinedRscStream(
162
319
 
163
320
  /**
164
321
  * Merge RSC script stream into the HTML stream, injecting scripts
165
- * only as direct children of `<body>`.
322
+ * between HTML chunks at safe boundaries.
166
323
  *
167
- * This single transform replaces the previous two-stage pipeline
168
- * (createFlightInjectionTransform + createMoveSuffixStream). It:
324
+ * Suffix stripping (</body></html>) is handled upstream by
325
+ * createMoveSuffixStream. This transform only interleaves RSC
326
+ * scripts — no suffix tracking needed.
169
327
  *
170
- * 1. Strips `</body></html>` from the shell chunk so all subsequent
171
- * content is at the `<body>` level.
172
- * 2. Buffers RSC `<script>` tags and drains them after the suffix
173
- * has been stripped — guaranteeing body-level injection.
174
- * 3. Re-emits `</body></html>` at the very end after all RSC scripts.
328
+ * RSC scripts are buffered in pending[] by pullLoop and only
329
+ * drained from transform() (after a complete HTML chunk) or
330
+ * flush(). Never pushed directly from pullLoop to avoid mid-tag
331
+ * injection (TIM-527).
175
332
  *
176
- * Because the suffix is stripped before any scripts are injected,
177
- * scripts are always direct children of `<body>` regardless of how
178
- * React's renderToReadableStream chunks the HTML. No HTML structure
179
- * scanning or depth tracking needed — the suffix removal is the
180
- * structural guarantee.
333
+ * State machine phases:
334
+ * init streaming flushing done
335
+ * (any) error
181
336
  *
182
337
  * Inspired by Next.js createFlightDataInjectionTransformStream.
183
338
  */
184
339
  function createFlightInjectionTransform(
185
- rscScriptStream: ReadableStream<Uint8Array>
340
+ rscScriptStream: ReadableStream<Uint8Array>,
341
+ renderTimeoutMs?: number
186
342
  ): TransformStream<Uint8Array, Uint8Array> {
187
- const encoder = new TextEncoder();
188
- const decoder = new TextDecoder();
189
- const suffix = '</body></html>';
190
- const suffixBytes = encoder.encode(suffix);
191
-
192
343
  const rscReader = rscScriptStream.getReader();
344
+ const timeoutMs = renderTimeoutMs ?? 30_000;
345
+
346
+ const machine = createMachine<FlightInjectionState, FlightInjectionEvent>({
347
+ initial: { phase: 'init' },
348
+ transitions: flightInjectionTransitions,
349
+ });
350
+
193
351
  let pullPromise: Promise<void> | null = null;
194
- let donePulling = false;
195
- let pullError: unknown = null;
196
- // Once the suffix is stripped, all content is body-level and
197
- // scripts can safely be drained after any HTML chunk.
198
- let foundSuffix = false;
199
352
 
200
- // RSC script chunks waiting to be injected at the body level.
353
+ // RSC script chunks waiting to be drained at a safe boundary.
354
+ // pullLoop buffers here; transform(), flush(), and pullLoop's
355
+ // post-yield drain all consume from this buffer.
201
356
  const pending: Uint8Array[] = [];
202
357
 
358
+ // Controller reference — set on first transform() call so pullLoop
359
+ // can drain pending scripts between HTML chunks (after yielding).
360
+ let _controller: TransformStreamDefaultController<Uint8Array> | null = null;
361
+
203
362
  async function pullLoop(): Promise<void> {
204
- // Wait one macrotask so the HTML shell chunk flows through
205
- // transform() first. The browser needs the shell HTML before
206
- // RSC data script tags arrive.
207
- await new Promise<void>((r) => setTimeout(r, 0));
363
+ // Yield once so the first HTML shell chunk flows through
364
+ // transform() before we start reading RSC data.
365
+ await new Promise<void>((r) => setImmediate(r));
208
366
 
209
367
  try {
210
368
  for (;;) {
211
- const { done, value } = await rscReader.read();
369
+ // Guard each RSC read with a timeout.
370
+ // See design/02 §"Streaming Constraints".
371
+ const readPromise = rscReader.read();
372
+ const { done, value } =
373
+ timeoutMs > 0
374
+ ? await withTimeout(readPromise, timeoutMs, 'RSC stream read timed out')
375
+ : await readPromise;
212
376
  if (done) {
213
- donePulling = true;
377
+ machine.send({ type: 'PULL_DONE' });
214
378
  return;
215
379
  }
216
380
  pending.push(value);
217
- // Yield between reads so HTML chunks get a chance to flow
218
- // through transform() first. RSC and HTML are driven by the
219
- // same source — each RSC chunk typically produces a
220
- // corresponding HTML chunk from SSR.
221
- await new Promise<void>((r) => setTimeout(r, 0));
381
+ // Yield between reads so HTML chunks get priority.
382
+ // Once flush() fires, drain without yielding.
383
+ if (!isHtmlDone(machine.state)) {
384
+ await new Promise<void>((r) => setImmediate(r));
385
+ // After yielding, drain pending scripts. This ensures RSC
386
+ // flight data reaches the client at shell-flush time — without
387
+ // this, hydration blocks waiting for data stuck in pending[].
388
+ // Safe because the upstream buffered transform (TIM-528)
389
+ // guarantees chunks end at tag boundaries.
390
+ if (pending.length > 0 && _controller) {
391
+ drainPending(_controller);
392
+ }
393
+ }
222
394
  }
223
395
  } catch (err) {
224
- pullError = err;
225
- donePulling = true;
396
+ if (err instanceof RenderTimeoutError) {
397
+ rscReader.cancel(err).catch(() => {});
398
+ }
399
+ machine.send({ type: 'PULL_ERROR', error: err });
226
400
  }
227
401
  }
228
402
 
@@ -231,59 +405,36 @@ function createFlightInjectionTransform(
231
405
  while (pending.length > 0) {
232
406
  controller.enqueue(pending.shift()!);
233
407
  }
234
- if (pullError) {
235
- const err = pullError;
236
- pullError = null;
237
- controller.error(err);
408
+ if (machine.state.phase === 'error') {
409
+ controller.error(machine.state.error);
238
410
  }
239
411
  }
240
412
 
241
413
  return new TransformStream<Uint8Array, Uint8Array>({
242
414
  transform(chunk, controller) {
243
- // Start pulling RSC scripts into the buffer (if not started)
244
- if (!pullPromise) {
245
- pullPromise = pullLoop();
246
- }
415
+ _controller = controller;
247
416
 
248
- if (foundSuffix) {
249
- // Post-suffix: everything is body-level (Suspense chunks).
250
- // Emit HTML, then drain any buffered scripts.
251
- controller.enqueue(chunk);
252
- if (pending.length > 0) drainPending(controller);
253
- return;
417
+ if (machine.state.phase === 'init') {
418
+ machine.send({ type: 'FIRST_CHUNK' });
419
+ pullPromise = pullLoop();
254
420
  }
255
421
 
256
- // Look for </body></html> in the shell chunk.
257
- const text = decoder.decode(chunk, { stream: true });
258
- const idx = text.indexOf(suffix);
259
- if (idx !== -1) {
260
- foundSuffix = true;
261
- // Emit everything before the suffix (still inside <body>'s
262
- // child elements — don't inject scripts here).
263
- const before = text.slice(0, idx);
264
- const after = text.slice(idx + suffix.length);
265
- if (before) controller.enqueue(encoder.encode(before));
266
- // Now we're at body level — drain buffered scripts
267
- if (pending.length > 0) drainPending(controller);
268
- // Emit any content after the suffix (shouldn't normally exist)
269
- if (after) controller.enqueue(encoder.encode(after));
270
- } else {
271
- // Pre-suffix: inside nested elements. Pass through, don't
272
- // inject scripts (they'd become children of nested elements).
273
- controller.enqueue(chunk);
274
- }
422
+ // Emit the HTML chunk, then drain any buffered RSC scripts.
423
+ // Scripts always come AFTER a complete HTML chunk never mid-tag.
424
+ // The buffered transform upstream (TIM-528) ensures coherent chunks.
425
+ // Suffix stripping is upstream via createMoveSuffixStream (TIM-530).
426
+ controller.enqueue(chunk);
427
+ if (pending.length > 0) drainPending(controller);
275
428
  },
276
429
  flush(controller) {
277
- // HTML stream is done drain remaining RSC chunks at body level
430
+ // All HTML chunks emitted. Pull loop stops yielding.
431
+ machine.send({ type: 'HTML_DONE' });
432
+
278
433
  const finish = () => {
279
434
  drainPending(controller);
280
- // Re-emit the suffix at the very end so HTML is well-formed
281
- if (foundSuffix) {
282
- controller.enqueue(suffixBytes);
283
- }
284
435
  };
285
436
 
286
- if (donePulling) {
437
+ if (isPullDone(machine.state)) {
287
438
  finish();
288
439
  return;
289
440
  }
@@ -314,16 +465,25 @@ function createFlightInjectionTransform(
314
465
  */
315
466
  export function injectRscPayload(
316
467
  htmlStream: ReadableStream<Uint8Array>,
317
- rscStream: ReadableStream<Uint8Array> | undefined
468
+ rscStream: ReadableStream<Uint8Array> | undefined,
469
+ renderTimeoutMs?: number
318
470
  ): ReadableStream<Uint8Array> {
319
471
  if (!rscStream) return htmlStream;
320
472
 
321
473
  // Transform RSC binary stream → stream of <script> tags
322
- const rscScriptStream = createInlinedRscStream(rscStream);
323
-
324
- // Single transform: strip </body></html>, inject RSC scripts at
325
- // body level, re-emit suffix at the very end.
326
- return htmlStream.pipeThrough(createFlightInjectionTransform(rscScriptStream));
474
+ const rscScriptStream = createInlinedRscStream(rscStream, renderTimeoutMs);
475
+
476
+ // Pipeline: flightInjection moveSuffix
477
+ //
478
+ // 1. flightInjection interleaves RSC scripts between HTML chunks
479
+ // 2. moveSuffix strips </body></html> and re-emits at end
480
+ //
481
+ // The flight injector is upstream and interleaves scripts between
482
+ // HTML chunks. The moveSuffix transform then ensures </body></html>
483
+ // appears after all injected scripts, producing well-formed HTML.
484
+ return htmlStream
485
+ .pipeThrough(createFlightInjectionTransform(rscScriptStream, renderTimeoutMs))
486
+ .pipeThrough(createMoveSuffixStream());
327
487
  }
328
488
 
329
489
  /**
@@ -344,7 +504,7 @@ export interface ClientBootstrapConfig {
344
504
  preloadLinks: string;
345
505
  }
346
506
 
347
- /** Find a manifest entry by matching the key suffix (e.g. 'client/browser-entry.ts'). */
507
+ /** Find a manifest entry by matching the key suffix (e.g. 'client/browser-entry/index.ts'). */
348
508
  function findManifestEntry(map: Record<string, string>, suffix: string): string | undefined {
349
509
  for (const [key, value] of Object.entries(map)) {
350
510
  if (key.endsWith(suffix)) return value;
@@ -425,7 +585,7 @@ export function buildClientScripts(runtimeConfig: {
425
585
  // a monorepo). Match by suffix to handle both cases.
426
586
  const manifest = runtimeConfig.buildManifest;
427
587
  const browserEntryUrl = manifest
428
- ? findManifestEntry(manifest.js, 'client/browser-entry.ts')
588
+ ? findManifestEntry(manifest.js, 'client/browser-entry/index.ts')
429
589
  : undefined;
430
590
 
431
591
  let preloadLinks = '';
@@ -435,7 +595,7 @@ export function buildClientScripts(runtimeConfig: {
435
595
  // Modulepreload hints for browser entry dependencies
436
596
  const preloads =
437
597
  (manifest
438
- ? findManifestEntryArray(manifest.modulepreload, 'client/browser-entry.ts')
598
+ ? findManifestEntryArray(manifest.modulepreload, 'client/browser-entry/index.ts')
439
599
  : undefined) ?? [];
440
600
  for (const url of preloads) {
441
601
  preloadLinks += `<link rel="modulepreload" href="${url}">`;