@timber-js/app 0.2.0-alpha.185 → 0.2.0-alpha.187

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 (570) hide show
  1. package/dist/_chunks/{actions-O_LsyCE4.js → actions-35jnMdeJ.js} +4 -3
  2. package/dist/_chunks/{actions-O_LsyCE4.js.map → actions-35jnMdeJ.js.map} +1 -1
  3. package/dist/_chunks/als-registry-C6kcfprT.js +41 -0
  4. package/dist/_chunks/als-registry-C6kcfprT.js.map +1 -0
  5. package/dist/_chunks/als-slots-BEEIPKYm.js +26 -0
  6. package/dist/_chunks/als-slots-BEEIPKYm.js.map +1 -0
  7. package/dist/_chunks/base-path-DaQrzbez.js +80 -0
  8. package/dist/_chunks/base-path-DaQrzbez.js.map +1 -0
  9. package/dist/_chunks/build-manifest-DWppEdLB.js +86 -0
  10. package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
  11. package/dist/_chunks/build-output-helper-C3DrfzZR.js +369 -0
  12. package/dist/_chunks/build-output-helper-C3DrfzZR.js.map +1 -0
  13. package/dist/_chunks/{cache-api-B-lhk9p4.js → cache-api-DjNrIWRR.js} +8 -14
  14. package/dist/_chunks/cache-api-DjNrIWRR.js.map +1 -0
  15. package/dist/_chunks/cli-check-CpmN7Nh-.js +256 -0
  16. package/dist/_chunks/cli-check-CpmN7Nh-.js.map +1 -0
  17. package/dist/_chunks/cli-schema-sync-CGMp_Psg.js +298 -0
  18. package/dist/_chunks/cli-schema-sync-CGMp_Psg.js.map +1 -0
  19. package/dist/_chunks/{cloudflare-CnT5Lr7U.js → cloudflare-CGP6BZKO.js} +92 -14
  20. package/dist/_chunks/{cloudflare-CnT5Lr7U.js.map → cloudflare-CGP6BZKO.js.map} +1 -1
  21. package/dist/_chunks/convention-lint-kXsgc_-7.js +784 -0
  22. package/dist/_chunks/convention-lint-kXsgc_-7.js.map +1 -0
  23. package/dist/_chunks/error-boundary-D-ODYX41.js +353 -0
  24. package/dist/_chunks/error-boundary-D-ODYX41.js.map +1 -0
  25. package/dist/_chunks/{fast-hash-D6hIVt1Y.js → fast-hash-C-tVYrLb.js} +6 -1
  26. package/dist/_chunks/fast-hash-C-tVYrLb.js.map +1 -0
  27. package/dist/_chunks/file-cache-DmX7OqZP.js +454 -0
  28. package/dist/_chunks/file-cache-DmX7OqZP.js.map +1 -0
  29. package/dist/_chunks/fs-identity-D7vb6GdI.js +208 -0
  30. package/dist/_chunks/fs-identity-D7vb6GdI.js.map +1 -0
  31. package/dist/_chunks/{logger-AWfuX-KJ.js → logger-D8xJZXIN.js} +34 -51
  32. package/dist/_chunks/logger-D8xJZXIN.js.map +1 -0
  33. package/dist/_chunks/mdx-file-C005ay-P.js +25 -0
  34. package/dist/_chunks/mdx-file-C005ay-P.js.map +1 -0
  35. package/dist/_chunks/{plugin-context---kTF5v8.js → plugin-context-rCinWLiE.js} +8 -2
  36. package/dist/_chunks/plugin-context-rCinWLiE.js.map +1 -0
  37. package/dist/_chunks/purge-store-Byr8XOjU.js +14 -0
  38. package/dist/_chunks/purge-store-Byr8XOjU.js.map +1 -0
  39. package/dist/_chunks/{resolve-schema-Dz3fcFUo.js → resolve-schema-5ma5pp1b.js} +2 -2
  40. package/dist/_chunks/{resolve-schema-Dz3fcFUo.js.map → resolve-schema-5ma5pp1b.js.map} +1 -1
  41. package/dist/_chunks/{router-ref-CtmF-aPv.js → router-ref-DuYuV_0Q.js} +2 -2
  42. package/dist/_chunks/router-ref-DuYuV_0Q.js.map +1 -0
  43. package/dist/_chunks/rsc-cache-key-DD0fl_-s.js +243 -0
  44. package/dist/_chunks/rsc-cache-key-DD0fl_-s.js.map +1 -0
  45. package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js +40 -0
  46. package/dist/_chunks/rsc-error-envelope-tT5PJs4q.js.map +1 -0
  47. package/dist/_chunks/rsc-media-type-DRqE_lD_.js +46 -0
  48. package/dist/_chunks/rsc-media-type-DRqE_lD_.js.map +1 -0
  49. package/dist/_chunks/rsc-payload-path-B_LBodc2.js +48 -0
  50. package/dist/_chunks/rsc-payload-path-B_LBodc2.js.map +1 -0
  51. package/dist/_chunks/scanner-C8b0Gcw3.js +1564 -0
  52. package/dist/_chunks/scanner-C8b0Gcw3.js.map +1 -0
  53. package/dist/_chunks/schema-bridge-Cc2Gngu1.js +199 -0
  54. package/dist/_chunks/schema-bridge-Cc2Gngu1.js.map +1 -0
  55. package/dist/_chunks/{segment-classify-Byy425ng.js → segment-classify-C539Pa2O.js} +23 -2
  56. package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -0
  57. package/dist/_chunks/segment-context-CjOlyB8Y.js +97 -0
  58. package/dist/_chunks/segment-context-CjOlyB8Y.js.map +1 -0
  59. package/dist/_chunks/{canonicalize-DQHyFClh.js → segment-keys-BawYuNFO.js} +61 -2
  60. package/dist/_chunks/segment-keys-BawYuNFO.js.map +1 -0
  61. package/dist/_chunks/slot-params-BCTmZkQB.js +76 -0
  62. package/dist/_chunks/slot-params-BCTmZkQB.js.map +1 -0
  63. package/dist/_chunks/{ssr-data-BOWsq18U.js → ssr-data-14MXm7Pj.js} +17 -2
  64. package/dist/_chunks/ssr-data-14MXm7Pj.js.map +1 -0
  65. package/dist/_chunks/{use-query-states-DFvWd-EA.js → use-query-states-BbU5Ge1V.js} +74 -26
  66. package/dist/_chunks/use-query-states-BbU5Ge1V.js.map +1 -0
  67. package/dist/_chunks/use-segment-params-C4r4BD9T.js +398 -0
  68. package/dist/_chunks/use-segment-params-C4r4BD9T.js.map +1 -0
  69. package/dist/_chunks/walkers-RzN6AFjr.js +141 -0
  70. package/dist/_chunks/walkers-RzN6AFjr.js.map +1 -0
  71. package/dist/adapters/build-output-helper.d.ts +37 -0
  72. package/dist/adapters/build-output-helper.d.ts.map +1 -1
  73. package/dist/adapters/cloudflare-dev.js +1 -1
  74. package/dist/adapters/cloudflare-kv-cache.js +1 -1
  75. package/dist/adapters/cloudflare.d.ts.map +1 -1
  76. package/dist/adapters/cloudflare.js +1 -1
  77. package/dist/adapters/compress-module.d.ts +12 -0
  78. package/dist/adapters/compress-module.d.ts.map +1 -1
  79. package/dist/adapters/fs-identity.d.ts +64 -0
  80. package/dist/adapters/fs-identity.d.ts.map +1 -0
  81. package/dist/adapters/nitro.d.ts.map +1 -1
  82. package/dist/adapters/nitro.js +56 -5
  83. package/dist/adapters/nitro.js.map +1 -1
  84. package/dist/adapters/shared.d.ts +57 -1
  85. package/dist/adapters/shared.d.ts.map +1 -1
  86. package/dist/adapters/types.d.ts +13 -1
  87. package/dist/adapters/types.d.ts.map +1 -1
  88. package/dist/cache/fast-hash.d.ts +5 -0
  89. package/dist/cache/fast-hash.d.ts.map +1 -1
  90. package/dist/cache/index.js +1 -1
  91. package/dist/cdn/cloudflare-purge.js +30 -0
  92. package/dist/cdn/cloudflare-purge.js.map +1 -0
  93. package/dist/cdn/fastly-purge.js +33 -0
  94. package/dist/cdn/fastly-purge.js.map +1 -0
  95. package/dist/cdn/index.js +94 -0
  96. package/dist/cdn/index.js.map +1 -0
  97. package/dist/cdn/workers-cache-purge.js +35 -0
  98. package/dist/cdn/workers-cache-purge.js.map +1 -0
  99. package/dist/cli-check.d.ts +153 -0
  100. package/dist/cli-check.d.ts.map +1 -0
  101. package/dist/cli.d.ts +34 -8
  102. package/dist/cli.d.ts.map +1 -1
  103. package/dist/cli.js +46 -21
  104. package/dist/cli.js.map +1 -1
  105. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
  106. package/dist/client/browser-entry/hydrate.d.ts +20 -9
  107. package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
  108. package/dist/client/browser-entry/index.d.ts +1 -1
  109. package/dist/client/browser-entry/index.d.ts.map +1 -1
  110. package/dist/client/browser-entry/post-hydration.d.ts +4 -1
  111. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
  112. package/dist/client/browser-entry/router-init.d.ts +3 -0
  113. package/dist/client/browser-entry/router-init.d.ts.map +1 -1
  114. package/dist/client/browser-entry/rsc-stream.d.ts +8 -0
  115. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -1
  116. package/dist/client/error-boundary.d.ts +7 -0
  117. package/dist/client/error-boundary.d.ts.map +1 -1
  118. package/dist/client/error-boundary.js +1 -162
  119. package/dist/client/history.d.ts +13 -6
  120. package/dist/client/history.d.ts.map +1 -1
  121. package/dist/client/index.d.ts +1 -0
  122. package/dist/client/index.d.ts.map +1 -1
  123. package/dist/client/index.js +42 -41
  124. package/dist/client/index.js.map +1 -1
  125. package/dist/client/internal.d.ts +4 -3
  126. package/dist/client/internal.d.ts.map +1 -1
  127. package/dist/client/internal.js +877 -311
  128. package/dist/client/internal.js.map +1 -1
  129. package/dist/client/link.d.ts +1 -7
  130. package/dist/client/link.d.ts.map +1 -1
  131. package/dist/client/navigation-api.d.ts +2 -2
  132. package/dist/client/navigation-commit.d.ts +87 -0
  133. package/dist/client/navigation-commit.d.ts.map +1 -0
  134. package/dist/client/navigation-context.d.ts +37 -20
  135. package/dist/client/navigation-context.d.ts.map +1 -1
  136. package/dist/client/navigation-root.d.ts +63 -23
  137. package/dist/client/navigation-root.d.ts.map +1 -1
  138. package/dist/client/params-context.d.ts +81 -0
  139. package/dist/client/params-context.d.ts.map +1 -0
  140. package/dist/client/router-effects.d.ts +129 -0
  141. package/dist/client/router-effects.d.ts.map +1 -0
  142. package/dist/client/router-lifecycle.d.ts +55 -0
  143. package/dist/client/router-lifecycle.d.ts.map +1 -0
  144. package/dist/client/router-pipeline.d.ts +84 -0
  145. package/dist/client/router-pipeline.d.ts.map +1 -0
  146. package/dist/client/router-ref.d.ts +1 -1
  147. package/dist/client/router-ref.d.ts.map +1 -1
  148. package/dist/client/router-skew.d.ts +21 -0
  149. package/dist/client/router-skew.d.ts.map +1 -0
  150. package/dist/client/router-types.d.ts +207 -0
  151. package/dist/client/router-types.d.ts.map +1 -0
  152. package/dist/client/router.d.ts +1 -182
  153. package/dist/client/router.d.ts.map +1 -1
  154. package/dist/client/rsc-fetch.d.ts +47 -26
  155. package/dist/client/rsc-fetch.d.ts.map +1 -1
  156. package/dist/client/segment-cache.d.ts +87 -34
  157. package/dist/client/segment-cache.d.ts.map +1 -1
  158. package/dist/client/ssr-data.d.ts +6 -0
  159. package/dist/client/ssr-data.d.ts.map +1 -1
  160. package/dist/client/stale-client.d.ts +69 -0
  161. package/dist/client/stale-client.d.ts.map +1 -0
  162. package/dist/client/state.d.ts +10 -1
  163. package/dist/client/state.d.ts.map +1 -1
  164. package/dist/client/top-loader.d.ts +2 -1
  165. package/dist/client/top-loader.d.ts.map +1 -1
  166. package/dist/client/unload-guard.d.ts +5 -0
  167. package/dist/client/unload-guard.d.ts.map +1 -1
  168. package/dist/client/use-cookie.d.ts.map +1 -1
  169. package/dist/client/use-query-states.d.ts +9 -3
  170. package/dist/client/use-query-states.d.ts.map +1 -1
  171. package/dist/client/use-router.d.ts +1 -1
  172. package/dist/client/use-segment-params.d.ts +18 -8
  173. package/dist/client/use-segment-params.d.ts.map +1 -1
  174. package/dist/codec.js +1 -1
  175. package/dist/cookies/define-cookie.d.ts.map +1 -1
  176. package/dist/cookies/index.js +5 -5
  177. package/dist/cookies/index.js.map +1 -1
  178. package/dist/index.d.ts +4 -1
  179. package/dist/index.d.ts.map +1 -1
  180. package/dist/index.js +1009 -759
  181. package/dist/index.js.map +1 -1
  182. package/dist/params/index.js +1 -1
  183. package/dist/plugin-context.d.ts +46 -0
  184. package/dist/plugin-context.d.ts.map +1 -1
  185. package/dist/plugins/adapter-build.d.ts.map +1 -1
  186. package/dist/plugins/build-manifest.d.ts +1 -1
  187. package/dist/plugins/build-manifest.d.ts.map +1 -1
  188. package/dist/plugins/entries.d.ts.map +1 -1
  189. package/dist/plugins/fonts.d.ts.map +1 -1
  190. package/dist/plugins/request-dep/analysis.d.ts +106 -0
  191. package/dist/plugins/request-dep/analysis.d.ts.map +1 -0
  192. package/dist/plugins/request-dep/index.d.ts +75 -0
  193. package/dist/plugins/request-dep/index.d.ts.map +1 -0
  194. package/dist/plugins/request-dep/origin.d.ts +61 -0
  195. package/dist/plugins/request-dep/origin.d.ts.map +1 -0
  196. package/dist/plugins/routing.d.ts.map +1 -1
  197. package/dist/plugins/shims.d.ts.map +1 -1
  198. package/dist/plugins/static-build.d.ts +160 -8
  199. package/dist/plugins/static-build.d.ts.map +1 -1
  200. package/dist/routing/codegen-shared.d.ts +3 -44
  201. package/dist/routing/codegen-shared.d.ts.map +1 -1
  202. package/dist/routing/codegen-types.d.ts +28 -31
  203. package/dist/routing/codegen-types.d.ts.map +1 -1
  204. package/dist/routing/codegen-write.d.ts +51 -0
  205. package/dist/routing/codegen-write.d.ts.map +1 -0
  206. package/dist/routing/codegen.d.ts.map +1 -1
  207. package/dist/routing/collision-probe.d.ts +104 -0
  208. package/dist/routing/collision-probe.d.ts.map +1 -0
  209. package/dist/routing/collision-spaces.d.ts +26 -0
  210. package/dist/routing/collision-spaces.d.ts.map +1 -0
  211. package/dist/routing/convention-lint.d.ts +18 -4
  212. package/dist/routing/convention-lint.d.ts.map +1 -1
  213. package/dist/routing/export-detect.d.ts +16 -0
  214. package/dist/routing/export-detect.d.ts.map +1 -1
  215. package/dist/routing/index.js +4 -3
  216. package/dist/routing/interception.d.ts +235 -6
  217. package/dist/routing/interception.d.ts.map +1 -1
  218. package/dist/routing/link-codegen.d.ts +19 -4
  219. package/dist/routing/link-codegen.d.ts.map +1 -1
  220. package/dist/routing/manifest-codegen.d.ts +1 -7
  221. package/dist/routing/manifest-codegen.d.ts.map +1 -1
  222. package/dist/routing/scanner.d.ts.map +1 -1
  223. package/dist/routing/segment-classify.d.ts +33 -0
  224. package/dist/routing/segment-classify.d.ts.map +1 -1
  225. package/dist/routing/segment-keys.d.ts +95 -0
  226. package/dist/routing/segment-keys.d.ts.map +1 -0
  227. package/dist/routing/slot-placement.d.ts +48 -0
  228. package/dist/routing/slot-placement.d.ts.map +1 -0
  229. package/dist/routing/types.d.ts +0 -6
  230. package/dist/routing/types.d.ts.map +1 -1
  231. package/dist/routing/walkers.d.ts +6 -0
  232. package/dist/routing/walkers.d.ts.map +1 -1
  233. package/dist/schema-bridge.d.ts +60 -9
  234. package/dist/schema-bridge.d.ts.map +1 -1
  235. package/dist/search-params/define.d.ts +62 -14
  236. package/dist/search-params/define.d.ts.map +1 -1
  237. package/dist/search-params/index.d.ts +0 -1
  238. package/dist/search-params/index.d.ts.map +1 -1
  239. package/dist/search-params/index.js +221 -10
  240. package/dist/search-params/index.js.map +1 -1
  241. package/dist/search-params/parse-total.d.ts +70 -0
  242. package/dist/search-params/parse-total.d.ts.map +1 -0
  243. package/dist/search-params/wrappers.d.ts +26 -3
  244. package/dist/search-params/wrappers.d.ts.map +1 -1
  245. package/dist/server/access-gate.d.ts +19 -8
  246. package/dist/server/access-gate.d.ts.map +1 -1
  247. package/dist/server/action-handler.d.ts.map +1 -1
  248. package/dist/server/actions.d.ts +6 -3
  249. package/dist/server/actions.d.ts.map +1 -1
  250. package/dist/server/als-registry.d.ts +18 -1
  251. package/dist/server/als-registry.d.ts.map +1 -1
  252. package/dist/server/build-manifest.d.ts +13 -1
  253. package/dist/server/build-manifest.d.ts.map +1 -1
  254. package/dist/server/chain-url-parts.d.ts +82 -0
  255. package/dist/server/chain-url-parts.d.ts.map +1 -0
  256. package/dist/server/children-interception.d.ts +49 -0
  257. package/dist/server/children-interception.d.ts.map +1 -0
  258. package/dist/server/compress.d.ts.map +1 -1
  259. package/dist/server/default-status-page.d.ts +45 -0
  260. package/dist/server/default-status-page.d.ts.map +1 -0
  261. package/dist/server/deny-boundary.d.ts +148 -15
  262. package/dist/server/deny-boundary.d.ts.map +1 -1
  263. package/dist/server/deny-renderer.d.ts +15 -4
  264. package/dist/server/deny-renderer.d.ts.map +1 -1
  265. package/dist/server/error-boundary-wrapper.d.ts +85 -15
  266. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  267. package/dist/server/head-response.d.ts +35 -0
  268. package/dist/server/head-response.d.ts.map +1 -0
  269. package/dist/server/index.d.ts +0 -1
  270. package/dist/server/index.d.ts.map +1 -1
  271. package/dist/server/index.js +3 -2
  272. package/dist/server/index.js.map +1 -1
  273. package/dist/server/internal.d.ts +3 -1
  274. package/dist/server/internal.d.ts.map +1 -1
  275. package/dist/server/internal.js +712 -418
  276. package/dist/server/internal.js.map +1 -1
  277. package/dist/server/metadata-collector.d.ts +52 -0
  278. package/dist/server/metadata-collector.d.ts.map +1 -0
  279. package/dist/server/param-coercion.d.ts +22 -6
  280. package/dist/server/param-coercion.d.ts.map +1 -1
  281. package/dist/server/pipeline-helpers.d.ts +0 -18
  282. package/dist/server/pipeline-helpers.d.ts.map +1 -1
  283. package/dist/server/pipeline-interception.d.ts +59 -9
  284. package/dist/server/pipeline-interception.d.ts.map +1 -1
  285. package/dist/server/pipeline-outcome.d.ts.map +1 -1
  286. package/dist/server/pipeline-phases.d.ts.map +1 -1
  287. package/dist/server/pipeline.d.ts +11 -0
  288. package/dist/server/pipeline.d.ts.map +1 -1
  289. package/dist/server/primitives.d.ts +23 -0
  290. package/dist/server/primitives.d.ts.map +1 -1
  291. package/dist/server/publish-params.d.ts +33 -0
  292. package/dist/server/publish-params.d.ts.map +1 -0
  293. package/dist/server/request-context.d.ts +48 -0
  294. package/dist/server/request-context.d.ts.map +1 -1
  295. package/dist/server/route-element-builder.d.ts +22 -3
  296. package/dist/server/route-element-builder.d.ts.map +1 -1
  297. package/dist/server/route-handler.d.ts.map +1 -1
  298. package/dist/server/route-matcher.d.ts +13 -0
  299. package/dist/server/route-matcher.d.ts.map +1 -1
  300. package/dist/server/rsc-cache-key-guard.d.ts +78 -0
  301. package/dist/server/rsc-cache-key-guard.d.ts.map +1 -0
  302. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  303. package/dist/server/rsc-entry/deny-fallback.d.ts.map +1 -1
  304. package/dist/server/rsc-entry/error-renderer.d.ts +15 -3
  305. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  306. package/dist/server/rsc-entry/helpers.d.ts +2 -17
  307. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  308. package/dist/server/rsc-entry/index.d.ts +0 -1
  309. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  310. package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
  311. package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -1
  312. package/dist/server/rsc-entry/rsc-payload.d.ts +1 -2
  313. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  314. package/dist/server/rsc-entry/rsc-stream.d.ts +15 -2
  315. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  316. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  317. package/dist/server/skippable-prefix.d.ts +23 -0
  318. package/dist/server/skippable-prefix.d.ts.map +1 -0
  319. package/dist/server/slot-interception.d.ts +80 -0
  320. package/dist/server/slot-interception.d.ts.map +1 -0
  321. package/dist/server/slot-resolver.d.ts +70 -8
  322. package/dist/server/slot-resolver.d.ts.map +1 -1
  323. package/dist/server/ssr-bridge-types.d.ts +17 -0
  324. package/dist/server/ssr-bridge-types.d.ts.map +1 -1
  325. package/dist/server/ssr-entry.d.ts +0 -1
  326. package/dist/server/ssr-entry.d.ts.map +1 -1
  327. package/dist/server/ssr-wrappers.d.ts +24 -13
  328. package/dist/server/ssr-wrappers.d.ts.map +1 -1
  329. package/dist/server/state-tree-diff.d.ts +6 -27
  330. package/dist/server/state-tree-diff.d.ts.map +1 -1
  331. package/dist/server/static-generator.d.ts +6 -0
  332. package/dist/server/static-generator.d.ts.map +1 -1
  333. package/dist/server/static-not-found.d.ts +52 -0
  334. package/dist/server/static-not-found.d.ts.map +1 -0
  335. package/dist/server/status-code-resolver.d.ts +8 -1
  336. package/dist/server/status-code-resolver.d.ts.map +1 -1
  337. package/dist/server/tree-builder.d.ts +28 -36
  338. package/dist/server/tree-builder.d.ts.map +1 -1
  339. package/dist/server/types.d.ts +12 -7
  340. package/dist/server/types.d.ts.map +1 -1
  341. package/dist/server/utils/element-type.d.ts +40 -0
  342. package/dist/server/utils/element-type.d.ts.map +1 -0
  343. package/dist/shared/als-slots.d.ts +41 -0
  344. package/dist/shared/als-slots.d.ts.map +1 -0
  345. package/dist/shared/base-path.d.ts +56 -0
  346. package/dist/shared/base-path.d.ts.map +1 -0
  347. package/dist/shared/param-value.d.ts +80 -0
  348. package/dist/shared/param-value.d.ts.map +1 -0
  349. package/dist/shared/payload-root.d.ts +108 -0
  350. package/dist/shared/payload-root.d.ts.map +1 -0
  351. package/dist/shared/rsc-cache-key.d.ts +163 -0
  352. package/dist/shared/rsc-cache-key.d.ts.map +1 -0
  353. package/dist/shared/rsc-error-envelope.d.ts +25 -0
  354. package/dist/shared/rsc-error-envelope.d.ts.map +1 -0
  355. package/dist/shared/rsc-manifest.d.ts +28 -0
  356. package/dist/shared/rsc-manifest.d.ts.map +1 -0
  357. package/dist/shared/rsc-media-type.d.ts +40 -0
  358. package/dist/shared/rsc-media-type.d.ts.map +1 -0
  359. package/dist/shared/rsc-payload-path.d.ts +42 -0
  360. package/dist/shared/rsc-payload-path.d.ts.map +1 -0
  361. package/dist/shared/segment-info.d.ts +59 -0
  362. package/dist/shared/segment-info.d.ts.map +1 -0
  363. package/dist/shared/slot-params.d.ts +51 -0
  364. package/dist/shared/slot-params.d.ts.map +1 -0
  365. package/dist/shared/static-platform-files.d.ts +71 -0
  366. package/dist/shared/static-platform-files.d.ts.map +1 -0
  367. package/docs/api/30-api-server.mdx +1 -1
  368. package/docs/api/31-api-client.mdx +4 -2
  369. package/docs/api/33-api-search-params.mdx +38 -16
  370. package/docs/api/35-api-typescript.mdx +3 -3
  371. package/docs/api/36-cli.mdx +34 -7
  372. package/docs/learn/00-introduction.mdx +1 -1
  373. package/docs/learn/02-pages-and-layouts.mdx +2 -2
  374. package/docs/learn/05-typed-params.mdx +8 -8
  375. package/docs/learn/07-typed-routes.mdx +12 -7
  376. package/docs/learn/11-error-handling.mdx +18 -0
  377. package/docs/learn/12-client-navigation.mdx +2 -2
  378. package/docs/learn/14-deploying.mdx +23 -0
  379. package/docs/more/01-advanced-routing.mdx +173 -3
  380. package/docs/more/03-coming-from-nextjs.mdx +2 -2
  381. package/docs/more/04-metadata-and-fonts.mdx +1 -1
  382. package/docs/more/50-ai-agent-instructions.mdx +6 -4
  383. package/package.json +9 -6
  384. package/src/adapters/build-output-helper.ts +116 -3
  385. package/src/adapters/cloudflare.ts +90 -12
  386. package/src/adapters/compress-module.ts +79 -1
  387. package/src/adapters/fs-identity.ts +156 -0
  388. package/src/adapters/nitro.ts +6 -6
  389. package/src/adapters/shared.ts +196 -21
  390. package/src/adapters/types.ts +13 -1
  391. package/src/cache/fast-hash.ts +5 -0
  392. package/src/cli-check.ts +458 -0
  393. package/src/cli.ts +59 -24
  394. package/src/client/browser-entry/action-dispatch.ts +11 -5
  395. package/src/client/browser-entry/hydrate.ts +40 -29
  396. package/src/client/browser-entry/index.ts +15 -6
  397. package/src/client/browser-entry/post-hydration.ts +10 -9
  398. package/src/client/browser-entry/router-init.ts +104 -48
  399. package/src/client/browser-entry/rsc-stream.ts +11 -2
  400. package/src/client/error-boundary.tsx +85 -16
  401. package/src/client/history.ts +13 -6
  402. package/src/client/index.ts +14 -3
  403. package/src/client/internal.ts +4 -3
  404. package/src/client/link.tsx +120 -72
  405. package/src/client/navigation-api.ts +3 -3
  406. package/src/client/navigation-commit.ts +197 -0
  407. package/src/client/navigation-context.ts +40 -67
  408. package/src/client/navigation-root.tsx +326 -101
  409. package/src/client/params-context.ts +192 -0
  410. package/src/client/router-effects.ts +231 -0
  411. package/src/client/router-lifecycle.ts +288 -0
  412. package/src/client/router-pipeline.ts +393 -0
  413. package/src/client/router-ref.ts +1 -1
  414. package/src/client/router-skew.ts +30 -0
  415. package/src/client/router-types.ts +230 -0
  416. package/src/client/router.ts +243 -707
  417. package/src/client/rsc-fetch.ts +183 -106
  418. package/src/client/segment-cache.ts +129 -44
  419. package/src/client/ssr-data.ts +6 -0
  420. package/src/client/stale-client.ts +191 -0
  421. package/src/client/state.ts +14 -1
  422. package/src/client/top-loader.tsx +2 -1
  423. package/src/client/unload-guard.ts +34 -2
  424. package/src/client/use-cookie.ts +9 -2
  425. package/src/client/use-query-states.ts +102 -39
  426. package/src/client/use-router.ts +1 -1
  427. package/src/client/use-segment-params.ts +41 -18
  428. package/src/cookies/define-cookie.ts +6 -1
  429. package/src/index.ts +25 -4
  430. package/src/plugin-context.ts +58 -0
  431. package/src/plugins/adapter-build.ts +4 -0
  432. package/src/plugins/build-manifest.ts +34 -13
  433. package/src/plugins/entries.ts +4 -0
  434. package/src/plugins/fonts.ts +11 -8
  435. package/src/plugins/request-dep/analysis.ts +447 -0
  436. package/src/plugins/request-dep/index.ts +376 -0
  437. package/src/plugins/request-dep/origin.ts +310 -0
  438. package/src/plugins/routing.ts +97 -102
  439. package/src/plugins/shims.ts +0 -1
  440. package/src/plugins/static-build.ts +391 -95
  441. package/src/routing/codegen-shared.ts +3 -79
  442. package/src/routing/codegen-types.ts +28 -31
  443. package/src/routing/codegen-write.ts +139 -0
  444. package/src/routing/codegen.ts +86 -172
  445. package/src/routing/collision-probe.ts +438 -0
  446. package/src/routing/collision-spaces.ts +281 -0
  447. package/src/routing/convention-lint.ts +139 -40
  448. package/src/routing/export-detect.ts +151 -7
  449. package/src/routing/interception.ts +896 -50
  450. package/src/routing/link-codegen.ts +32 -65
  451. package/src/routing/manifest-codegen.ts +6 -62
  452. package/src/routing/scanner.ts +117 -92
  453. package/src/routing/segment-classify.ts +57 -0
  454. package/src/routing/segment-keys.ts +146 -0
  455. package/src/routing/slot-placement.ts +97 -0
  456. package/src/routing/types.ts +0 -6
  457. package/src/routing/walkers.ts +8 -0
  458. package/src/schema-bridge.ts +180 -58
  459. package/src/search-params/define.ts +108 -66
  460. package/src/search-params/index.ts +0 -1
  461. package/src/search-params/parse-total.ts +78 -0
  462. package/src/search-params/wrappers.ts +60 -11
  463. package/src/server/access-gate.tsx +60 -40
  464. package/src/server/action-handler.ts +4 -5
  465. package/src/server/actions.ts +6 -3
  466. package/src/server/als-registry.ts +18 -1
  467. package/src/server/build-manifest.ts +14 -1
  468. package/src/server/chain-url-parts.ts +163 -0
  469. package/src/server/children-interception.ts +115 -0
  470. package/src/server/compress.ts +9 -1
  471. package/src/server/default-status-page.ts +127 -0
  472. package/src/server/deny-boundary.ts +269 -41
  473. package/src/server/deny-renderer.ts +111 -39
  474. package/src/server/error-boundary-wrapper.ts +166 -79
  475. package/src/server/head-response.ts +54 -0
  476. package/src/server/index.ts +1 -3
  477. package/src/server/internal.ts +2 -2
  478. package/src/server/metadata-collector.ts +115 -0
  479. package/src/server/param-coercion.ts +51 -69
  480. package/src/server/pipeline-helpers.ts +2 -47
  481. package/src/server/pipeline-interception.ts +81 -32
  482. package/src/server/pipeline-outcome.ts +4 -5
  483. package/src/server/pipeline-phases.ts +77 -25
  484. package/src/server/pipeline.ts +57 -10
  485. package/src/server/prebuilt-runtime.ts +4 -4
  486. package/src/server/primitives.ts +25 -0
  487. package/src/server/publish-params.ts +42 -0
  488. package/src/server/request-context.ts +97 -18
  489. package/src/server/route-element-builder.ts +241 -253
  490. package/src/server/route-handler.ts +8 -8
  491. package/src/server/route-matcher.ts +21 -9
  492. package/src/server/rsc-cache-key-guard.ts +164 -0
  493. package/src/server/rsc-entry/api-handler.ts +6 -8
  494. package/src/server/rsc-entry/deny-fallback.ts +3 -2
  495. package/src/server/rsc-entry/error-renderer.ts +94 -35
  496. package/src/server/rsc-entry/helpers.ts +33 -28
  497. package/src/server/rsc-entry/index.ts +36 -33
  498. package/src/server/rsc-entry/render-route.ts +18 -10
  499. package/src/server/rsc-entry/revalidate-renderer.ts +3 -2
  500. package/src/server/rsc-entry/rsc-payload.ts +113 -40
  501. package/src/server/rsc-entry/rsc-stream.ts +29 -5
  502. package/src/server/rsc-entry/ssr-renderer.ts +38 -22
  503. package/src/server/skippable-prefix.ts +92 -0
  504. package/src/server/slot-interception.ts +168 -0
  505. package/src/server/slot-resolver.ts +263 -158
  506. package/src/server/ssr-bridge-types.ts +18 -0
  507. package/src/server/ssr-entry.ts +20 -10
  508. package/src/server/ssr-wrappers.tsx +33 -32
  509. package/src/server/state-tree-diff.ts +14 -55
  510. package/src/server/static-generator.ts +68 -29
  511. package/src/server/static-not-found.ts +134 -0
  512. package/src/server/status-code-resolver.ts +28 -11
  513. package/src/server/tree-builder.ts +35 -218
  514. package/src/server/types.ts +12 -7
  515. package/src/server/utils/element-type.ts +72 -0
  516. package/src/shared/als-slots.ts +72 -0
  517. package/src/shared/base-path.ts +80 -0
  518. package/src/shared/param-value.ts +244 -0
  519. package/src/shared/payload-root.ts +151 -0
  520. package/src/shared/rsc-cache-key.ts +269 -0
  521. package/src/shared/rsc-error-envelope.ts +31 -0
  522. package/src/shared/rsc-manifest.ts +29 -0
  523. package/src/shared/rsc-media-type.ts +43 -0
  524. package/src/shared/rsc-payload-path.ts +45 -0
  525. package/src/shared/segment-info.ts +60 -0
  526. package/src/shared/slot-params.ts +111 -0
  527. package/src/shared/static-platform-files.ts +75 -0
  528. package/dist/_chunks/build-output-helper-DOGYFb_X.js +0 -196
  529. package/dist/_chunks/build-output-helper-DOGYFb_X.js.map +0 -1
  530. package/dist/_chunks/cache-api-B-lhk9p4.js.map +0 -1
  531. package/dist/_chunks/canonicalize-DQHyFClh.js.map +0 -1
  532. package/dist/_chunks/cli-schema-sync-BTWEKJXo.js +0 -668
  533. package/dist/_chunks/cli-schema-sync-BTWEKJXo.js.map +0 -1
  534. package/dist/_chunks/define-COtkxMRT.js +0 -191
  535. package/dist/_chunks/define-COtkxMRT.js.map +0 -1
  536. package/dist/_chunks/define-c4au4I9R.js +0 -82
  537. package/dist/_chunks/define-c4au4I9R.js.map +0 -1
  538. package/dist/_chunks/fast-hash-D6hIVt1Y.js.map +0 -1
  539. package/dist/_chunks/logger-AWfuX-KJ.js.map +0 -1
  540. package/dist/_chunks/navigation-root-bUDZLw74.js +0 -124
  541. package/dist/_chunks/navigation-root-bUDZLw74.js.map +0 -1
  542. package/dist/_chunks/plugin-context---kTF5v8.js.map +0 -1
  543. package/dist/_chunks/registry-DbJPKoBp.js +0 -20
  544. package/dist/_chunks/registry-DbJPKoBp.js.map +0 -1
  545. package/dist/_chunks/router-ref-CtmF-aPv.js.map +0 -1
  546. package/dist/_chunks/schema-bridge-DT_Tn0Xf.js +0 -119
  547. package/dist/_chunks/schema-bridge-DT_Tn0Xf.js.map +0 -1
  548. package/dist/_chunks/segment-classify-Byy425ng.js.map +0 -1
  549. package/dist/_chunks/segment-context-ZDnXDkbz.js +0 -34
  550. package/dist/_chunks/segment-context-ZDnXDkbz.js.map +0 -1
  551. package/dist/_chunks/ssr-data-BOWsq18U.js.map +0 -1
  552. package/dist/_chunks/use-query-states-DFvWd-EA.js.map +0 -1
  553. package/dist/_chunks/use-segment-params-D1CzlgBo.js +0 -151
  554. package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +0 -1
  555. package/dist/_chunks/walkers-_6zKFlch.js +0 -1002
  556. package/dist/_chunks/walkers-_6zKFlch.js.map +0 -1
  557. package/dist/client/error-boundary.js.map +0 -1
  558. package/dist/plugins/request-dep.d.ts +0 -32
  559. package/dist/plugins/request-dep.d.ts.map +0 -1
  560. package/dist/search-params/registry.d.ts +0 -20
  561. package/dist/search-params/registry.d.ts.map +0 -1
  562. package/dist/segment-params/define.d.ts +0 -89
  563. package/dist/segment-params/define.d.ts.map +0 -1
  564. package/dist/segment-params/index.d.ts +0 -3
  565. package/dist/segment-params/index.d.ts.map +0 -1
  566. package/dist/segment-params/index.js +0 -2
  567. package/src/plugins/request-dep.ts +0 -499
  568. package/src/search-params/registry.ts +0 -31
  569. package/src/segment-params/define.ts +0 -249
  570. package/src/segment-params/index.ts +0 -9
@@ -19,7 +19,10 @@ import { createElement, Fragment } from 'react';
19
19
  import { renderToReadableStream } from '../rsc-runtime/rsc.js';
20
20
 
21
21
  import { DenySignal } from './primitives.js';
22
- import { renderDenyEntry, type DenyPageEntry } from './deny-boundary.js';
22
+ import { appVisibleSearch } from '../shared/rsc-cache-key.js';
23
+ import { getSlotParamsForClient } from './request-context.js';
24
+ import { withPublishedParams } from './publish-params.js';
25
+ import { renderDenyEntry, type DenyEntryShape } from './deny-boundary.js';
23
26
  import { getCookiesForSsr } from './cookie-context.js';
24
27
  import { logRenderError } from './logger.js';
25
28
  import { loadModule } from './safe-load.js';
@@ -28,6 +31,8 @@ import { isDebug } from './debug.js';
28
31
  import { resolveMetadata, renderMetadataToElements } from './metadata.js';
29
32
  import { headElementsToReact } from './metadata.js';
30
33
  import { resolveStatusFile } from './status-code-resolver.js';
34
+ import { defaultStatusPageResponse } from './default-status-page.js';
35
+ import { rscErrorEnvelope } from '../shared/rsc-error-envelope.js';
31
36
  import type { ManifestSegmentNode } from './route-matcher.js';
32
37
  import type { RouteMatch } from './pipeline.js';
33
38
  import type { NavContext } from './ssr-bridge-types.js';
@@ -35,9 +40,7 @@ import { flightInitScript } from './flight-scripts.js';
35
40
  import type { ClientBootstrapConfig } from './html-injectors.js';
36
41
  import type { Metadata } from './types.js';
37
42
  import { teeWithErrorPropagation } from './stream-utils.js';
38
-
39
- /** RSC content type for client navigation payload requests. */
40
- const RSC_CONTENT_TYPE = 'text/x-component';
43
+ import { RSC_CONTENT_TYPE } from '../shared/rsc-media-type.js';
41
44
 
42
45
  /** Layout component entry for deny page wrapping. */
43
46
  export interface LayoutEntry {
@@ -79,8 +82,7 @@ function buildDenyElement(
79
82
  resolutionKind: 'exact' | 'category' | 'error',
80
83
  filePath: string
81
84
  ): React.ReactElement {
82
- const entry: DenyPageEntry = {
83
- status: deny.status,
85
+ const entry: DenyEntryShape = {
84
86
  component,
85
87
  kind: resolutionKind === 'error' ? 'error' : 'status',
86
88
  isMdx: isMdxFilePath(filePath),
@@ -88,12 +90,24 @@ function buildDenyElement(
88
90
  return renderDenyEntry(entry, deny.status, deny.data);
89
91
  }
90
92
 
93
+ /**
94
+ * Supplies a replacement for the framework default page at the end of the
95
+ * chain. Returning `null` keeps the framework default.
96
+ *
97
+ * The dev server uses this to substitute its route-listing 404 page. It is a
98
+ * parameter rather than a check on the produced Response because "the app
99
+ * authored no status page" is a fact about the *chain*, and inspecting the
100
+ * result for it (e.g. an empty body) stops being true the moment the chain
101
+ * grows a real terminal — which is exactly what TIM-1258 did.
102
+ */
103
+ export type DefaultPageRenderer = (status: number, responseHeaders: Headers) => Response | null;
104
+
91
105
  /**
92
106
  * Render a status-code error page for a DenySignal.
93
107
  *
94
108
  * Resolves the appropriate status-code file from the segment chain based
95
- * on format preference. Returns an HTML Response (component), JSON Response,
96
- * or bare fallback Response.
109
+ * on format preference. Returns an HTML Response (component), a JSON Response,
110
+ * or the framework default status page.
97
111
  */
98
112
  export async function renderDenyPage(
99
113
  deny: DenySignal,
@@ -104,23 +118,35 @@ export async function renderDenyPage(
104
118
  responseHeaders: Headers,
105
119
  clientBootstrap: ClientBootstrapConfig,
106
120
  createDebugChannelSink: DebugChannelFactory,
107
- callSsr: CallSsrFn
121
+ callSsr: CallSsrFn,
122
+ defaultPage?: DefaultPageRenderer,
123
+ firstDeniedIndex = Infinity
108
124
  ): Promise<Response> {
125
+ // Clamp the resolution walk to the denied segment — a status file below
126
+ // the denial is invisible to the in-tree chain and must not be selected
127
+ // by the fallback. The denying segment itself IS included (matching
128
+ // buildDenyPageChain's start-at-i semantics), but its layout is not
129
+ // (the gate-outside-layout rule from TIM-1074). See TIM-1358.
130
+ const maxIndex = firstDeniedIndex < Infinity ? firstDeniedIndex : undefined;
131
+
109
132
  // API routes (route.ts) → JSON only, never render components
110
133
  if (isApiRoute(segments)) {
111
- const jsonResponse = await renderDenyPageJson(deny, segments, responseHeaders);
134
+ const jsonResponse = await renderDenyPageJson(deny, segments, responseHeaders, maxIndex);
112
135
  if (jsonResponse) return jsonResponse;
113
136
  return bareJsonResponse(deny.status, responseHeaders);
114
137
  }
115
138
 
116
139
  // Page routes → component chain first, JSON fallback only if no component found.
117
- const resolution = resolveStatusFile(deny.status, segments, 'component');
140
+ const resolution = resolveStatusFile(deny.status, segments, 'component', maxIndex);
118
141
 
119
- // No component status file — try JSON chain before bare fallback
142
+ // No component status file — try JSON chain, then the framework default page.
120
143
  if (!resolution) {
121
- const jsonResponse = await renderDenyPageJson(deny, segments, responseHeaders);
144
+ const jsonResponse = await renderDenyPageJson(deny, segments, responseHeaders, maxIndex);
122
145
  if (jsonResponse) return jsonResponse;
123
- return new Response(null, { status: deny.status, headers: responseHeaders });
146
+ return (
147
+ defaultPage?.(deny.status, responseHeaders) ??
148
+ defaultStatusPageResponse(deny.status, responseHeaders)
149
+ );
124
150
  }
125
151
 
126
152
  // Dev warning: JSON status file exists but is shadowed by the component chain.
@@ -137,10 +163,20 @@ export async function renderDenyPage(
137
163
  }
138
164
  }
139
165
 
140
- // Load the status-code page component
141
- const mod = await loadModule(resolution.file);
142
- if (!mod.default) {
143
- return new Response(null, { status: deny.status, headers: responseHeaders });
166
+ // Load the status-code page component. A file that resolved but exports no
167
+ // default — or whose module fails to import or evaluate — is not a usable
168
+ // component match: continue down the documented chain (JSON, then framework
169
+ // default) rather than returning an empty body or letting the loader's
170
+ // rejection escape request handling. Mirrors buildDenyPageChain and the
171
+ // error-file resolver, which both swallow the load failure.
172
+ const mod = await loadModule(resolution.file).catch(() => null);
173
+ if (!mod?.default) {
174
+ const jsonResponse = await renderDenyPageJson(deny, segments, responseHeaders, maxIndex);
175
+ if (jsonResponse) return jsonResponse;
176
+ return (
177
+ defaultPage?.(deny.status, responseHeaders) ??
178
+ defaultStatusPageResponse(deny.status, responseHeaders)
179
+ );
144
180
  }
145
181
 
146
182
  const ErrorPageComponent = mod.default as (...args: unknown[]) => unknown;
@@ -156,10 +192,12 @@ export async function renderDenyPage(
156
192
  resolution.file.filePath
157
193
  );
158
194
 
159
- // Always wrap in layout shell.
160
- // NOTE: Shell opt-out (export const shell = false) is a future feature
161
- // pending a proper design doc. See design backlog.
162
- const resolvedSegments = new Set(segments.slice(0, resolution.segmentIndex + 1));
195
+ // Wrap in layout shell, clamped so a denied segment's layout never
196
+ // executes — the gate-outside-layout rule from TIM-1074. The denied
197
+ // segment's layout was loaded into `layoutComponents` but must not
198
+ // appear in the fallback response. See TIM-1358.
199
+ const layoutCeiling = Math.min(resolution.segmentIndex, firstDeniedIndex - 1);
200
+ const resolvedSegments = new Set(segments.slice(0, layoutCeiling + 1));
163
201
  const layoutsToWrap = layoutComponents.filter((lc) => resolvedSegments.has(lc.segment));
164
202
  for (let i = layoutsToWrap.length - 1; i >= 0; i--) {
165
203
  const { component } = layoutsToWrap[i];
@@ -176,7 +214,7 @@ export async function renderDenyPage(
176
214
  }
177
215
 
178
216
  // Render the error page to a fresh RSC Flight stream.
179
- const rscStream = renderToReadableStream(element, {
217
+ const rscStream = renderToReadableStream(withPublishedParams(element), {
180
218
  signal: req.signal,
181
219
  onError(error: unknown) {
182
220
  logRenderError({ method: req.method, path: new URL(req.url).pathname, error });
@@ -186,10 +224,13 @@ export async function renderDenyPage(
186
224
 
187
225
  const [ssrStream, inlineStream] = teeWithErrorPropagation(rscStream);
188
226
 
227
+ const slotParams = getSlotParamsForClient();
228
+
189
229
  const navContext: NavContext = {
190
230
  pathname: new URL(req.url).pathname,
191
231
  segmentParams: match.segmentParams,
192
- searchParams: Object.fromEntries(new URL(req.url).searchParams),
232
+ searchParams: Object.fromEntries(appVisibleSearch(new URL(req.url)).params),
233
+ slotParams,
193
234
  statusCode: deny.status,
194
235
  responseHeaders,
195
236
  headHtml: flightInitScript(),
@@ -199,7 +240,32 @@ export async function renderDenyPage(
199
240
  cookies: getCookiesForSsr(),
200
241
  };
201
242
 
202
- return callSsr(ssrStream, navContext);
243
+ try {
244
+ // `await` inside the try on purpose — see the same note in
245
+ // rsc-entry/error-renderer.ts. A status page that crashes during SSR
246
+ // ends in the framework default page, not a blank body: the pipeline's
247
+ // own deny fallback catches this and can only produce an empty response,
248
+ // and a crashing 404.tsx is exactly when the reader has nothing else to
249
+ // go on (TIM-1258).
250
+ return await callSsr(ssrStream, navContext);
251
+ } catch (renderError) {
252
+ logRenderError({ method: req.method, path: new URL(req.url).pathname, error: renderError });
253
+ return defaultStatusPageResponse(deny.status, responseHeaders);
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Terminal fallback for a client-navigation deny with no status-code file.
259
+ *
260
+ * The HTML path answers this case with the framework default page, but a
261
+ * client-navigation response cannot carry HTML — the Flight decoder would
262
+ * choke on it. Emit the hard-navigate envelope instead: the client abandons
263
+ * SPA navigation and the resulting document request renders that same default
264
+ * page. Before TIM-1258 this returned an empty Flight body, which the decoder
265
+ * hit as a malformed stream.
266
+ */
267
+ function denyHardNavigateResponse(status: number, responseHeaders: Headers): Response {
268
+ return rscErrorEnvelope(status, responseHeaders);
203
269
  }
204
270
 
205
271
  /**
@@ -214,19 +280,19 @@ export async function renderDenyPageAsRsc(
214
280
  layoutComponents: LayoutEntry[],
215
281
  req: Request,
216
282
  responseHeaders: Headers,
217
- createDebugChannelSink: DebugChannelFactory
283
+ createDebugChannelSink: DebugChannelFactory,
284
+ firstDeniedIndex = Infinity
218
285
  ): Promise<Response> {
219
- const resolution = resolveStatusFile(deny.status, segments, 'component');
286
+ const maxIndex = firstDeniedIndex < Infinity ? firstDeniedIndex : undefined;
287
+ const resolution = resolveStatusFile(deny.status, segments, 'component', maxIndex);
220
288
 
221
289
  if (!resolution) {
222
- responseHeaders.set('content-type', `${RSC_CONTENT_TYPE}; charset=utf-8`);
223
- return new Response(null, { status: deny.status, headers: responseHeaders });
290
+ return denyHardNavigateResponse(deny.status, responseHeaders);
224
291
  }
225
292
 
226
- const mod = await loadModule(resolution.file);
227
- if (!mod.default) {
228
- responseHeaders.set('content-type', `${RSC_CONTENT_TYPE}; charset=utf-8`);
229
- return new Response(null, { status: deny.status, headers: responseHeaders });
293
+ const mod = await loadModule(resolution.file).catch(() => null);
294
+ if (!mod?.default) {
295
+ return denyHardNavigateResponse(deny.status, responseHeaders);
230
296
  }
231
297
 
232
298
  const ErrorPageComponent = mod.default as (...args: unknown[]) => unknown;
@@ -239,15 +305,16 @@ export async function renderDenyPageAsRsc(
239
305
  resolution.file.filePath
240
306
  );
241
307
 
242
- // Always wrap in layout shell.
243
- const resolvedSegments = new Set(segments.slice(0, resolution.segmentIndex + 1));
308
+ // Wrap in layout shell, clamped to exclude denied segment layouts. TIM-1358.
309
+ const layoutCeiling = Math.min(resolution.segmentIndex, firstDeniedIndex - 1);
310
+ const resolvedSegments = new Set(segments.slice(0, layoutCeiling + 1));
244
311
  const layoutsToWrap = layoutComponents.filter((lc) => resolvedSegments.has(lc.segment));
245
312
  for (let i = layoutsToWrap.length - 1; i >= 0; i--) {
246
313
  const { component } = layoutsToWrap[i];
247
314
  element = h(component, null, element);
248
315
  }
249
316
 
250
- const rscStream = renderToReadableStream(element, {
317
+ const rscStream = renderToReadableStream(withPublishedParams(element), {
251
318
  signal: req.signal,
252
319
  onError(error: unknown) {
253
320
  console.error('[timber] Error page RSC render error:', error);
@@ -275,9 +342,10 @@ export async function renderDenyPageAsRsc(
275
342
  async function renderDenyPageJson(
276
343
  deny: DenySignal,
277
344
  segments: ManifestSegmentNode[],
278
- responseHeaders: Headers
345
+ responseHeaders: Headers,
346
+ maxIndex?: number
279
347
  ): Promise<Response | null> {
280
- const resolution = resolveStatusFile(deny.status, segments, 'json');
348
+ const resolution = resolveStatusFile(deny.status, segments, 'json', maxIndex);
281
349
 
282
350
  if (!resolution) {
283
351
  return null;
@@ -286,7 +354,11 @@ async function renderDenyPageJson(
286
354
  // JSON status files are loaded as modules that export the JSON content.
287
355
  // The manifest's load() imports the .json file, which Vite handles as a
288
356
  // default export of the parsed JSON object.
289
- const mod = await loadModule(resolution.file);
357
+ // A .json status file that fails to load is not a usable match — return
358
+ // null so the caller continues to the framework default rather than
359
+ // rejecting out of the chain.
360
+ const mod = await loadModule(resolution.file).catch(() => null);
361
+ if (!mod) return null;
290
362
  const jsonContent = mod.default ?? mod;
291
363
 
292
364
  responseHeaders.set('content-type', 'application/json; charset=utf-8');
@@ -1,106 +1,193 @@
1
1
  /**
2
- * Error boundary wrapper — wraps a React element in error boundaries from a route segment.
2
+ * Error boundary wrapper — wraps a React element in the error boundaries
3
+ * declared by a route segment (`{status}.tsx`, `4xx.tsx`/`5xx.tsx`, `error.tsx`).
3
4
  *
4
- * Extracted to allow reuse by both rsc-entry.ts and route-element-builder.ts.
5
- * See design/10-error-handling.md.
5
+ * This is the single implementation of that walk. It is driven by both
6
+ * construction sites:
7
+ *
8
+ * - `route-element-builder.ts` / `slot-resolver.ts` — the request-time
9
+ * renderer, walking the runtime manifest (`SegmentNode<ManifestFile>`).
10
+ * - `tree-builder.ts` — the build-time tree walker
11
+ * (`SegmentNode<RouteFile>`), with its loader and `createElement` injected.
12
+ *
13
+ * `errorBoundaryComponent` is injected rather than imported: `TimberErrorBoundary`
14
+ * is a `'use client'` module, and importing it here would pull client code into
15
+ * every consumer — including `tree-builder.ts`, which the server barrel reaches.
16
+ * `tests/use-client-pipeline.test.ts` walks the import graph to enforce this.
17
+ *
18
+ * See design/10-error-handling.md §"Status-Code File Variants".
6
19
  */
7
20
 
8
- import { TimberErrorBoundary } from '../client/error-boundary.js';
9
- import type { ManifestSegmentNode } from './route-matcher.js';
10
- import { loadModule } from './safe-load.js';
21
+ import type { ReactNode } from 'react';
22
+ import type { SegmentNode } from '../routing/types.js';
23
+ import { isValidElementType, type LoadedComponent } from './utils/element-type.js';
11
24
  import { isMdxFilePath } from './utils/mdx-file.js';
12
25
 
26
+ /** The minimum a route file must carry for the walk: a path to classify as MDX. */
27
+ interface BoundaryFile {
28
+ filePath: string;
29
+ }
30
+
13
31
  /**
14
- * Wrap an element in error boundaries defined by a route segment.
32
+ * Framework-injected error boundary wrapper.
33
+ * Wraps content with status-code error boundary handling.
15
34
  *
16
- * Processing order (innermost to outermost):
17
- * 1. Specific status files (e.g., 404.tsx, 500.tsx) — highest priority at runtime
18
- * 2. Category catch-alls (4xx.tsx, 5xx.tsx)
19
- * 3. error.tsx — catches anything not matched by status files
35
+ * Field types must agree with `TimberErrorBoundaryProps` in
36
+ * `client/error-boundary.tsx`. The two are kept structurally compatible by
37
+ * convention rather than by direct type import — this is the server-side
38
+ * construction site and may not import types from a 'use client' module.
39
+ */
40
+ export interface ErrorBoundaryProps {
41
+ /** The component to render when an error is caught (TSX status files). */
42
+ fallbackComponent?: LoadedComponent;
43
+ /** Pre-rendered fallback element (MDX status files — see TIM-503). */
44
+ fallbackElement?: ReactNode;
45
+ /** Status code filter: 400 = any 4xx, 500 = any 5xx, specific number = exact match. */
46
+ status?: number;
47
+ /**
48
+ * Segment key of the segment that declared this boundary. An in-tree deny
49
+ * catch site that matched a file it may not render in place re-throws with
50
+ * that file's owning key on the signal; boundaries whose key differs
51
+ * decline, so the deny page lands at its owner rather than at the first
52
+ * boundary the throw happens to pass. Unset for slot boundaries and for
53
+ * construction sites with no deny chains — an unkeyed boundary declines
54
+ * every owner-addressed deny. See TIM-1356.
55
+ */
56
+ segmentKey?: string;
57
+ children: ReactNode;
58
+ }
59
+
60
+ /** How to load a route file's module. Only `default` is read. */
61
+ type BoundaryModuleLoader<TFile> = (
62
+ file: TFile
63
+ ) => { default?: unknown } | Promise<{ default?: unknown }>;
64
+
65
+ /** Everything the walk needs from its host environment. */
66
+ export interface ErrorBoundaryWrapConfig<TFile, TElement> {
67
+ /** `React.createElement` or an equivalent element factory. */
68
+ createElement: (type: unknown, props: object) => TElement;
69
+ /** Loads a route file's module. Failures skip the boundary — see below. */
70
+ loadModule: BoundaryModuleLoader<TFile>;
71
+ /**
72
+ * The error boundary component to instantiate (`TimberErrorBoundary`, or a
73
+ * host-specific stand-in). Injected — see the module docstring.
74
+ */
75
+ errorBoundaryComponent: unknown;
76
+ /** When true, skip 4xx error boundaries — deny catching handles them in-tree. See TIM-666. */
77
+ skipDenyBoundaries?: boolean;
78
+ /** Segment key stamped on every boundary this walk creates. See `ErrorBoundaryProps`. */
79
+ segmentKey?: string;
80
+ }
81
+
82
+ /**
83
+ * Load a status/error file's component, or `null` if the boundary should be skipped.
84
+ *
85
+ * Two ways to get `null`, both deliberate:
86
+ * - the module fails to load (syntax error in the error page) — building an
87
+ * error boundary must not itself throw, so the boundary is skipped (TIM-584);
88
+ * - the default export is not a valid React component type, which would
89
+ * otherwise crash inside `createElement`.
90
+ */
91
+ async function loadBoundaryComponent<TFile>(
92
+ file: TFile,
93
+ loadModule: BoundaryModuleLoader<TFile>
94
+ ): Promise<LoadedComponent | null> {
95
+ let mod: { default?: unknown };
96
+ try {
97
+ mod = await loadModule(file);
98
+ } catch {
99
+ return null;
100
+ }
101
+ return isValidElementType(mod?.default) ? mod.default : null;
102
+ }
103
+
104
+ /**
105
+ * Wrap `element` in one error boundary rendering `Component` on failure.
20
106
  *
21
107
  * MDX status files are server components and cannot be passed as function
22
- * props to TimberErrorBoundary (a 'use client' component). Instead, they
23
- * are pre-rendered as elements and passed as fallbackElement. See TIM-503.
108
+ * props to `TimberErrorBoundary` (a 'use client' component). They are
109
+ * pre-rendered as elements and passed as `fallbackElement` instead. See TIM-503.
110
+ *
111
+ * @param status boundary status filter — omitted entirely for `error.tsx`
112
+ * @param fallbackProps props handed to an MDX fallback when it is pre-rendered
24
113
  */
25
- export async function wrapSegmentWithErrorBoundaries(
26
- segment: ManifestSegmentNode,
27
- element: React.ReactElement,
28
- h: (...args: unknown[]) => React.ReactElement,
29
- /** When true, skip 4xx error boundaries — deny catching handles them in-tree. See TIM-666. */
30
- skipDenyBoundaries = false
31
- ): Promise<React.ReactElement> {
32
- // Specific status files (innermost — highest priority at runtime)
114
+ function wrapInBoundary<TFile extends BoundaryFile, TElement extends ReactNode>(
115
+ element: TElement,
116
+ Component: LoadedComponent,
117
+ file: TFile,
118
+ status: number | undefined,
119
+ fallbackProps: object,
120
+ config: ErrorBoundaryWrapConfig<TFile, TElement>
121
+ ): TElement {
122
+ const props: ErrorBoundaryProps = isMdxFilePath(file.filePath)
123
+ ? { fallbackElement: config.createElement(Component, fallbackProps), children: element }
124
+ : { fallbackComponent: Component, children: element };
125
+ if (status !== undefined) props.status = status;
126
+ if (config.segmentKey !== undefined) props.segmentKey = config.segmentKey;
127
+ return config.createElement(config.errorBoundaryComponent, props);
128
+ }
129
+
130
+ /**
131
+ * Wrap an element in the error boundaries declared by a route segment.
132
+ *
133
+ * Wrapping is applied inside-out — the last wrap produces the outermost
134
+ * boundary — so the processing order below is innermost to outermost:
135
+ *
136
+ * 1. Specific status files (e.g. `404.tsx`, `503.tsx`) — highest priority at runtime
137
+ * 2. Category catch-alls (`4xx.tsx`, `5xx.tsx`)
138
+ * 3. `error.tsx` — catches anything not matched by a status file
139
+ *
140
+ * The order is load-bearing: it decides which boundary catches a given throw.
141
+ *
142
+ * See design/10-error-handling.md §"Format-Aware Fallback Chains".
143
+ */
144
+ export async function wrapSegmentWithErrorBoundaries<
145
+ TFile extends BoundaryFile,
146
+ TElement extends ReactNode,
147
+ >(
148
+ segment: SegmentNode<TFile>,
149
+ element: TElement,
150
+ config: ErrorBoundaryWrapConfig<TFile, TElement>
151
+ ): Promise<TElement> {
152
+ const { loadModule, skipDenyBoundaries = false } = config;
153
+
33
154
  if (segment.statusFiles) {
155
+ // Specific status files (innermost — highest priority at runtime)
34
156
  for (const [key, file] of Object.entries(segment.statusFiles)) {
35
- if (key !== '4xx' && key !== '5xx') {
36
- const status = parseInt(key, 10);
37
- if (!isNaN(status)) {
38
- // Skip 4xx boundaries when deny catching is active — the deny
39
- // page is rendered by AccessGate/PageDenyBoundary instead.
40
- if (skipDenyBoundaries && status >= 400 && status <= 499) continue;
41
- // .catch: error boundary construction must not fail if the
42
- // error page module has a syntax error — skip this boundary.
43
- const mod = await loadModule(file).catch(() => null);
44
- if (mod?.default) {
45
- if (isMdxFilePath(file.filePath)) {
46
- // MDX: pre-render as element (server component can't be a function prop)
47
- element = h(TimberErrorBoundary, {
48
- fallbackElement: h(mod.default as never, { status }),
49
- status,
50
- children: element,
51
- });
52
- } else {
53
- element = h(TimberErrorBoundary, {
54
- fallbackComponent: mod.default,
55
- status,
56
- children: element,
57
- });
58
- }
59
- }
60
- }
157
+ if (key === '4xx' || key === '5xx') continue;
158
+ const status = parseInt(key, 10);
159
+ if (isNaN(status)) continue;
160
+ // Skip 4xx boundaries when deny catching is active — the deny
161
+ // page is rendered by AccessGate/PageDenyBoundary instead.
162
+ if (skipDenyBoundaries && status >= 400 && status <= 499) continue;
163
+
164
+ const Component = await loadBoundaryComponent(file, loadModule);
165
+ if (Component) {
166
+ element = wrapInBoundary(element, Component, file, status, { status }, config);
61
167
  }
62
168
  }
63
169
 
64
170
  // Category catch-alls (4xx.tsx, 5xx.tsx)
65
171
  for (const [key, file] of Object.entries(segment.statusFiles)) {
172
+ if (key !== '4xx' && key !== '5xx') continue;
66
173
  if (skipDenyBoundaries && key === '4xx') continue;
67
- if (key === '4xx' || key === '5xx') {
68
- const mod = await loadModule(file).catch(() => null);
69
- if (mod?.default) {
70
- const categoryStatus = key === '4xx' ? 400 : 500;
71
- if (isMdxFilePath(file.filePath)) {
72
- element = h(TimberErrorBoundary, {
73
- fallbackElement: h(mod.default as never, {}),
74
- status: categoryStatus,
75
- children: element,
76
- });
77
- } else {
78
- element = h(TimberErrorBoundary, {
79
- fallbackComponent: mod.default,
80
- status: categoryStatus,
81
- children: element,
82
- });
83
- }
84
- }
174
+
175
+ const Component = await loadBoundaryComponent(file, loadModule);
176
+ if (Component) {
177
+ const categoryStatus = key === '4xx' ? 400 : 500;
178
+ element = wrapInBoundary(element, Component, file, categoryStatus, {}, config);
85
179
  }
86
180
  }
87
181
  }
88
182
 
89
- // error.tsx (outermost — catches anything not matched by status files)
183
+ // error.tsx (outermost — catches anything not matched by status files).
184
+ // error.tsx/error.mdx receives { error, digest, reset } props from the
185
+ // boundary at catch time; MDX error files are pre-rendered without them
186
+ // (they're static content).
90
187
  if (segment.error) {
91
- const mod = await loadModule(segment.error).catch(() => null);
92
- if (mod?.default) {
93
- if (isMdxFilePath(segment.error.filePath)) {
94
- element = h(TimberErrorBoundary, {
95
- fallbackElement: h(mod.default as never, {}),
96
- children: element,
97
- });
98
- } else {
99
- element = h(TimberErrorBoundary, {
100
- fallbackComponent: mod.default,
101
- children: element,
102
- });
103
- }
188
+ const Component = await loadBoundaryComponent(segment.error, loadModule);
189
+ if (Component) {
190
+ element = wrapInBoundary(element, Component, segment.error, undefined, {}, config);
104
191
  }
105
192
  }
106
193
 
@@ -0,0 +1,54 @@
1
+ /**
2
+ * HEAD body stripping — RFC 9110 §9.3.2.
3
+ *
4
+ * "The HEAD method is identical to GET except that the server MUST NOT send
5
+ * content in the response." The headers, however, must be the ones the
6
+ * corresponding GET would have produced — which is why timber renders the
7
+ * route in full and discards the body here rather than short-circuiting the
8
+ * render. Content-Type, Content-Length, Set-Cookie, cache directives and
9
+ * everything else ride through untouched.
10
+ *
11
+ * Node's `ServerResponse` happens to discard writes for HEAD, so the wire is
12
+ * usually correct even without this. That is a property of one adapter, not of
13
+ * the `Response` object: static generation, the Cloudflare and Nitro adapters,
14
+ * tests, and anything calling the pipeline handler as a function all observe
15
+ * the `Response` directly and saw the full body before TIM-1324.
16
+ *
17
+ * The pipeline applies this at its single exit so every response shape is
18
+ * covered — page render, API route, metadata route, deny page, error page,
19
+ * proxy short-circuit. The two unit-level producers that are also reachable as
20
+ * standalone functions (`handleRouteRequest`, `handleApiRoute`) call it too, so
21
+ * each honours HEAD on its own; they share this implementation rather than
22
+ * repeating it, and applying it twice is a no-op.
23
+ */
24
+
25
+ /**
26
+ * Return a bodyless copy of `response` when `method` is HEAD.
27
+ *
28
+ * A no-op for every other method and for responses that already carry no body
29
+ * (204, 304, redirects), so callers do not need to pre-check either.
30
+ *
31
+ * The discarded stream is cancelled: an SSR render that reached this point has
32
+ * a live producer attached, and dropping the reference without cancelling
33
+ * leaks it for the lifetime of the render (design/13-security.md A4).
34
+ */
35
+ export function stripHeadBody(response: Response, method: string): Response {
36
+ if (method.toUpperCase() !== 'HEAD') return response;
37
+ const body = response.body;
38
+ if (body === null) return response;
39
+
40
+ // `cancel()` rejects if the stream is already errored and throws
41
+ // synchronously if it is locked — neither is actionable here, the body is
42
+ // being discarded either way.
43
+ try {
44
+ body.cancel().catch(() => {});
45
+ } catch {
46
+ /* stream already locked or disturbed */
47
+ }
48
+
49
+ return new Response(null, {
50
+ status: response.status,
51
+ statusText: response.statusText,
52
+ headers: response.headers,
53
+ });
54
+ }
@@ -10,7 +10,7 @@ export type { RouteContext } from './types';
10
10
  export type { Metadata, MetadataRoute, MetadataHandler, MetadataResult } from './types';
11
11
 
12
12
  // Request Context — ALS-backed accessors (all sync)
13
- // Prefer defineSearchParams().get() and defineSegmentParams().get() for typed access.
13
+ // Prefer defineSearchParams().get() and getSegmentParams(SEGMENT_PATH) for typed access.
14
14
  // Design doc: design/04-authorization.md §"AccessContext does not include cookies or headers"
15
15
  export { getHeaders, getSegmentParams } from './request-context';
16
16
  export type { ReadonlyHeaders } from './request-context';
@@ -65,5 +65,3 @@ export { revalidatePath, revalidateTag } from './actions';
65
65
  export { getTraceId, getSpanId, withSpan, addSpanEvent } from './tracing';
66
66
 
67
67
  // Segment params types — re-exported for convenience.
68
- // defineSegmentParams itself lives at @timber-js/app/segment-params.
69
- export type { ParamsDefinition, InferParamField, ParamField } from '../segment-params/define.js';
@@ -66,12 +66,12 @@ export type {
66
66
  TreeBuilderConfig,
67
67
  TreeBuildResult,
68
68
  LoadedModule,
69
- LoadedComponent,
70
69
  ModuleLoader,
71
70
  AccessGateProps,
72
71
  SlotAccessGateProps,
73
- ErrorBoundaryProps,
74
72
  } from './tree-builder.js';
73
+ export type { LoadedComponent } from './utils/element-type.js';
74
+ export type { ErrorBoundaryProps } from './error-boundary-wrapper.js';
75
75
 
76
76
  // ── Access Gates ─────────────────────────────────────────────────────────
77
77
  export { AccessGate, SlotAccessGate } from './access-gate.js';