@timber-js/app 0.2.0-alpha.8 → 0.2.0-alpha.80

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 (573) hide show
  1. package/LICENSE +8 -0
  2. package/dist/_chunks/actions-Dg-ANYHb.js +421 -0
  3. package/dist/_chunks/actions-Dg-ANYHb.js.map +1 -0
  4. package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-HS0LGUl2.js} +1 -1
  5. package/dist/_chunks/als-registry-HS0LGUl2.js.map +1 -0
  6. package/dist/_chunks/chunk-DYhsFzuS.js +33 -0
  7. package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
  8. package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
  9. package/dist/_chunks/define-C77ScO0m.js +106 -0
  10. package/dist/_chunks/define-C77ScO0m.js.map +1 -0
  11. package/dist/_chunks/define-CZqDwhSu.js +199 -0
  12. package/dist/_chunks/define-CZqDwhSu.js.map +1 -0
  13. package/dist/_chunks/define-cookie-C2IkoFGN.js +94 -0
  14. package/dist/_chunks/define-cookie-C2IkoFGN.js.map +1 -0
  15. package/dist/_chunks/{format-DviM89f0.js → dev-warnings-DpGRGoDi.js} +5 -44
  16. package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +1 -0
  17. package/dist/_chunks/format-CYBGxKtc.js +14 -0
  18. package/dist/_chunks/format-CYBGxKtc.js.map +1 -0
  19. package/dist/_chunks/{interception-BOoWmLUA.js → interception-Dpn_UfAD.js} +171 -97
  20. package/dist/_chunks/interception-Dpn_UfAD.js.map +1 -0
  21. package/dist/_chunks/merge-search-params-Cm_KIWDX.js +41 -0
  22. package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +1 -0
  23. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DS3eKNmf.js} +1 -1
  24. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
  25. package/dist/_chunks/request-context-qMsWgy9C.js +478 -0
  26. package/dist/_chunks/request-context-qMsWgy9C.js.map +1 -0
  27. package/dist/_chunks/schema-bridge-C3xl_vfb.js +86 -0
  28. package/dist/_chunks/schema-bridge-C3xl_vfb.js.map +1 -0
  29. package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
  30. package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
  31. package/dist/_chunks/segment-context-fHFLF1PE.js +34 -0
  32. package/dist/_chunks/segment-context-fHFLF1PE.js.map +1 -0
  33. package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-DzuI0bIV.js} +1 -1
  34. package/dist/_chunks/{ssr-data-MjmprTmO.js.map → ssr-data-DzuI0bIV.js.map} +1 -1
  35. package/dist/_chunks/stale-reload-C2plcNtG.js +64 -0
  36. package/dist/_chunks/stale-reload-C2plcNtG.js.map +1 -0
  37. package/dist/_chunks/{tracing-CemImE6h.js → tracing-CCYbKn5n.js} +60 -9
  38. package/dist/_chunks/tracing-CCYbKn5n.js.map +1 -0
  39. package/dist/_chunks/use-params-Br9YSUFV.js +295 -0
  40. package/dist/_chunks/use-params-Br9YSUFV.js.map +1 -0
  41. package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-Lo_s_pw2.js} +4 -4
  42. package/dist/_chunks/use-query-states-Lo_s_pw2.js.map +1 -0
  43. package/dist/_chunks/wrappers-_DTmImGt.js +63 -0
  44. package/dist/_chunks/wrappers-_DTmImGt.js.map +1 -0
  45. package/dist/adapters/cloudflare-dev.d.ts +109 -0
  46. package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
  47. package/dist/adapters/cloudflare-dev.js +73 -0
  48. package/dist/adapters/cloudflare-dev.js.map +1 -0
  49. package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
  50. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
  51. package/dist/adapters/cloudflare-kv-cache.js +95 -0
  52. package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
  53. package/dist/adapters/cloudflare.d.ts +148 -12
  54. package/dist/adapters/cloudflare.d.ts.map +1 -1
  55. package/dist/adapters/cloudflare.js +135 -11
  56. package/dist/adapters/cloudflare.js.map +1 -1
  57. package/dist/adapters/compress-module.d.ts.map +1 -1
  58. package/dist/adapters/nitro.d.ts +17 -1
  59. package/dist/adapters/nitro.d.ts.map +1 -1
  60. package/dist/adapters/nitro.js +56 -13
  61. package/dist/adapters/nitro.js.map +1 -1
  62. package/dist/cache/cache-api.d.ts +24 -0
  63. package/dist/cache/cache-api.d.ts.map +1 -0
  64. package/dist/cache/handler-store.d.ts +31 -0
  65. package/dist/cache/handler-store.d.ts.map +1 -0
  66. package/dist/cache/index.d.ts +23 -7
  67. package/dist/cache/index.d.ts.map +1 -1
  68. package/dist/cache/index.js +142 -80
  69. package/dist/cache/index.js.map +1 -1
  70. package/dist/cache/singleflight.d.ts +18 -1
  71. package/dist/cache/singleflight.d.ts.map +1 -1
  72. package/dist/cache/sizeof.d.ts +22 -0
  73. package/dist/cache/sizeof.d.ts.map +1 -0
  74. package/dist/cache/timber-cache.d.ts +1 -1
  75. package/dist/cache/timber-cache.d.ts.map +1 -1
  76. package/dist/cli.d.ts +6 -1
  77. package/dist/cli.d.ts.map +1 -1
  78. package/dist/cli.js +6 -1
  79. package/dist/cli.js.map +1 -1
  80. package/dist/client/browser-dev.d.ts +27 -1
  81. package/dist/client/browser-dev.d.ts.map +1 -1
  82. package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
  83. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
  84. package/dist/client/browser-entry/hmr.d.ts +21 -0
  85. package/dist/client/browser-entry/hmr.d.ts.map +1 -0
  86. package/dist/client/browser-entry/hydrate.d.ts +46 -0
  87. package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
  88. package/dist/client/browser-entry/index.d.ts +30 -0
  89. package/dist/client/browser-entry/index.d.ts.map +1 -0
  90. package/dist/client/browser-entry/post-hydration.d.ts +26 -0
  91. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
  92. package/dist/client/browser-entry/router-init.d.ts +23 -0
  93. package/dist/client/browser-entry/router-init.d.ts.map +1 -0
  94. package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
  95. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
  96. package/dist/client/browser-entry/scroll.d.ts +19 -0
  97. package/dist/client/browser-entry/scroll.d.ts.map +1 -0
  98. package/dist/client/error-boundary.d.ts +12 -5
  99. package/dist/client/error-boundary.d.ts.map +1 -1
  100. package/dist/client/error-boundary.js +10 -4
  101. package/dist/client/error-boundary.js.map +1 -1
  102. package/dist/client/error-reconstituter.d.ts +54 -0
  103. package/dist/client/error-reconstituter.d.ts.map +1 -0
  104. package/dist/client/form.d.ts +2 -2
  105. package/dist/client/form.d.ts.map +1 -1
  106. package/dist/client/history.d.ts +19 -4
  107. package/dist/client/history.d.ts.map +1 -1
  108. package/dist/client/index.d.ts +7 -21
  109. package/dist/client/index.d.ts.map +1 -1
  110. package/dist/client/index.js +210 -1017
  111. package/dist/client/index.js.map +1 -1
  112. package/dist/client/internal.d.ts +18 -0
  113. package/dist/client/internal.d.ts.map +1 -0
  114. package/dist/client/internal.js +890 -0
  115. package/dist/client/internal.js.map +1 -0
  116. package/dist/client/link-pending-store.d.ts +63 -0
  117. package/dist/client/link-pending-store.d.ts.map +1 -0
  118. package/dist/client/link.d.ts +90 -32
  119. package/dist/client/link.d.ts.map +1 -1
  120. package/dist/client/nav-link-store.d.ts +36 -0
  121. package/dist/client/nav-link-store.d.ts.map +1 -0
  122. package/dist/client/navigation-api-types.d.ts +90 -0
  123. package/dist/client/navigation-api-types.d.ts.map +1 -0
  124. package/dist/client/navigation-api.d.ts +115 -0
  125. package/dist/client/navigation-api.d.ts.map +1 -0
  126. package/dist/client/navigation-context.d.ts +13 -2
  127. package/dist/client/navigation-context.d.ts.map +1 -1
  128. package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +42 -8
  129. package/dist/client/navigation-root.d.ts.map +1 -0
  130. package/dist/client/nuqs-adapter.d.ts.map +1 -1
  131. package/dist/client/router-ref.d.ts +1 -1
  132. package/dist/client/router.d.ts +70 -4
  133. package/dist/client/router.d.ts.map +1 -1
  134. package/dist/client/rsc-fetch.d.ts +38 -3
  135. package/dist/client/rsc-fetch.d.ts.map +1 -1
  136. package/dist/client/segment-cache.d.ts +1 -1
  137. package/dist/client/segment-cache.d.ts.map +1 -1
  138. package/dist/client/segment-outlet.d.ts +63 -0
  139. package/dist/client/segment-outlet.d.ts.map +1 -0
  140. package/dist/client/ssr-data.d.ts +13 -4
  141. package/dist/client/ssr-data.d.ts.map +1 -1
  142. package/dist/client/stale-reload.d.ts +15 -0
  143. package/dist/client/stale-reload.d.ts.map +1 -1
  144. package/dist/client/top-loader.d.ts +5 -5
  145. package/dist/client/top-loader.d.ts.map +1 -1
  146. package/dist/client/use-link-status.d.ts +5 -5
  147. package/dist/client/use-link-status.d.ts.map +1 -1
  148. package/dist/client/use-params.d.ts +6 -4
  149. package/dist/client/use-params.d.ts.map +1 -1
  150. package/dist/client/{use-navigation-pending.d.ts → use-pending-navigation.d.ts} +4 -4
  151. package/dist/client/use-pending-navigation.d.ts.map +1 -0
  152. package/dist/client/use-query-states.d.ts +1 -1
  153. package/dist/client/use-query-states.d.ts.map +1 -1
  154. package/dist/client/use-router.d.ts +1 -1
  155. package/dist/codec.d.ts +33 -0
  156. package/dist/codec.d.ts.map +1 -0
  157. package/dist/codec.js +2 -0
  158. package/dist/config-types.d.ts +210 -0
  159. package/dist/config-types.d.ts.map +1 -0
  160. package/dist/content/index.d.ts +1 -10
  161. package/dist/content/index.d.ts.map +1 -1
  162. package/dist/content/index.js +0 -2
  163. package/dist/cookies/define-cookie.d.ts +35 -14
  164. package/dist/cookies/define-cookie.d.ts.map +1 -1
  165. package/dist/cookies/index.js +1 -83
  166. package/dist/fonts/css.d.ts +1 -0
  167. package/dist/fonts/css.d.ts.map +1 -1
  168. package/dist/index.d.ts +45 -192
  169. package/dist/index.d.ts.map +1 -1
  170. package/dist/index.js +12296 -11901
  171. package/dist/index.js.map +1 -1
  172. package/dist/plugin-context.d.ts +84 -0
  173. package/dist/plugin-context.d.ts.map +1 -0
  174. package/dist/plugins/adapter-build.d.ts +1 -1
  175. package/dist/plugins/adapter-build.d.ts.map +1 -1
  176. package/dist/plugins/build-manifest.d.ts +2 -2
  177. package/dist/plugins/build-manifest.d.ts.map +1 -1
  178. package/dist/plugins/build-report.d.ts +3 -3
  179. package/dist/plugins/build-report.d.ts.map +1 -1
  180. package/dist/plugins/client-chunks.d.ts +32 -0
  181. package/dist/plugins/client-chunks.d.ts.map +1 -0
  182. package/dist/plugins/content.d.ts +1 -1
  183. package/dist/plugins/content.d.ts.map +1 -1
  184. package/dist/plugins/dev-browser-logs.d.ts +84 -0
  185. package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
  186. package/dist/plugins/dev-error-overlay.d.ts +26 -1
  187. package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
  188. package/dist/plugins/dev-logs.d.ts +1 -1
  189. package/dist/plugins/dev-logs.d.ts.map +1 -1
  190. package/dist/plugins/dev-server.d.ts +1 -1
  191. package/dist/plugins/dev-server.d.ts.map +1 -1
  192. package/dist/plugins/entries.d.ts +1 -1
  193. package/dist/plugins/entries.d.ts.map +1 -1
  194. package/dist/plugins/fonts.d.ts +19 -5
  195. package/dist/plugins/fonts.d.ts.map +1 -1
  196. package/dist/plugins/mdx.d.ts +1 -1
  197. package/dist/plugins/mdx.d.ts.map +1 -1
  198. package/dist/plugins/routing.d.ts +1 -1
  199. package/dist/plugins/routing.d.ts.map +1 -1
  200. package/dist/plugins/server-bundle.d.ts.map +1 -1
  201. package/dist/plugins/shims.d.ts +6 -5
  202. package/dist/plugins/shims.d.ts.map +1 -1
  203. package/dist/plugins/static-build.d.ts +4 -4
  204. package/dist/plugins/static-build.d.ts.map +1 -1
  205. package/dist/routing/codegen.d.ts +2 -2
  206. package/dist/routing/codegen.d.ts.map +1 -1
  207. package/dist/routing/index.d.ts +2 -0
  208. package/dist/routing/index.d.ts.map +1 -1
  209. package/dist/routing/index.js +3 -2
  210. package/dist/routing/scanner.d.ts.map +1 -1
  211. package/dist/routing/segment-classify.d.ts +46 -0
  212. package/dist/routing/segment-classify.d.ts.map +1 -0
  213. package/dist/routing/status-file-lint.d.ts +2 -1
  214. package/dist/routing/status-file-lint.d.ts.map +1 -1
  215. package/dist/routing/types.d.ts +16 -4
  216. package/dist/routing/types.d.ts.map +1 -1
  217. package/dist/rsc-runtime/rsc.d.ts +1 -1
  218. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  219. package/dist/rsc-runtime/ssr.d.ts +12 -0
  220. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  221. package/dist/schema-bridge.d.ts +76 -0
  222. package/dist/schema-bridge.d.ts.map +1 -0
  223. package/dist/search-params/define.d.ts +139 -0
  224. package/dist/search-params/define.d.ts.map +1 -0
  225. package/dist/search-params/index.d.ts +4 -7
  226. package/dist/search-params/index.d.ts.map +1 -1
  227. package/dist/search-params/index.js +4 -474
  228. package/dist/search-params/registry.d.ts +2 -2
  229. package/dist/search-params/registry.d.ts.map +1 -1
  230. package/dist/search-params/wrappers.d.ts +53 -0
  231. package/dist/search-params/wrappers.d.ts.map +1 -0
  232. package/dist/segment-params/define.d.ts +78 -0
  233. package/dist/segment-params/define.d.ts.map +1 -0
  234. package/dist/segment-params/index.d.ts +6 -0
  235. package/dist/segment-params/index.d.ts.map +1 -0
  236. package/dist/segment-params/index.js +4 -0
  237. package/dist/server/access-gate.d.ts +4 -0
  238. package/dist/server/access-gate.d.ts.map +1 -1
  239. package/dist/server/action-client.d.ts +12 -1
  240. package/dist/server/action-client.d.ts.map +1 -1
  241. package/dist/server/action-encryption.d.ts +76 -0
  242. package/dist/server/action-encryption.d.ts.map +1 -0
  243. package/dist/server/action-handler.d.ts.map +1 -1
  244. package/dist/server/actions.d.ts +3 -6
  245. package/dist/server/actions.d.ts.map +1 -1
  246. package/dist/server/als-registry.d.ts +32 -4
  247. package/dist/server/als-registry.d.ts.map +1 -1
  248. package/dist/server/build-manifest.d.ts +2 -2
  249. package/dist/server/build-manifest.d.ts.map +1 -1
  250. package/dist/server/debug.d.ts +1 -1
  251. package/dist/server/default-logger.d.ts +22 -0
  252. package/dist/server/default-logger.d.ts.map +1 -0
  253. package/dist/server/deny-page-resolver.d.ts +52 -0
  254. package/dist/server/deny-page-resolver.d.ts.map +1 -0
  255. package/dist/server/deny-renderer.d.ts.map +1 -1
  256. package/dist/server/dev-holding-server.d.ts +52 -0
  257. package/dist/server/dev-holding-server.d.ts.map +1 -0
  258. package/dist/server/dev-warnings.d.ts +1 -21
  259. package/dist/server/dev-warnings.d.ts.map +1 -1
  260. package/dist/server/early-hints.d.ts +13 -5
  261. package/dist/server/early-hints.d.ts.map +1 -1
  262. package/dist/server/error-boundary-wrapper.d.ts +7 -1
  263. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  264. package/dist/server/fallback-error.d.ts +4 -3
  265. package/dist/server/fallback-error.d.ts.map +1 -1
  266. package/dist/server/flight-injection-state.d.ts +66 -0
  267. package/dist/server/flight-injection-state.d.ts.map +1 -0
  268. package/dist/server/flight-scripts.d.ts +42 -0
  269. package/dist/server/flight-scripts.d.ts.map +1 -0
  270. package/dist/server/flush.d.ts.map +1 -1
  271. package/dist/server/form-data.d.ts +29 -0
  272. package/dist/server/form-data.d.ts.map +1 -1
  273. package/dist/server/html-injectors.d.ts +51 -11
  274. package/dist/server/html-injectors.d.ts.map +1 -1
  275. package/dist/server/index.d.ts +6 -43
  276. package/dist/server/index.d.ts.map +1 -1
  277. package/dist/server/index.js +38 -2798
  278. package/dist/server/index.js.map +1 -1
  279. package/dist/server/internal.d.ts +46 -0
  280. package/dist/server/internal.d.ts.map +1 -0
  281. package/dist/server/internal.js +2883 -0
  282. package/dist/server/internal.js.map +1 -0
  283. package/dist/server/logger.d.ts +25 -7
  284. package/dist/server/logger.d.ts.map +1 -1
  285. package/dist/server/middleware-runner.d.ts +19 -4
  286. package/dist/server/middleware-runner.d.ts.map +1 -1
  287. package/dist/server/node-stream-transforms.d.ts +113 -0
  288. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  289. package/dist/server/page-deny-boundary.d.ts +31 -0
  290. package/dist/server/page-deny-boundary.d.ts.map +1 -0
  291. package/dist/server/pipeline-interception.d.ts +1 -1
  292. package/dist/server/pipeline-interception.d.ts.map +1 -1
  293. package/dist/server/pipeline-metadata.d.ts +6 -0
  294. package/dist/server/pipeline-metadata.d.ts.map +1 -1
  295. package/dist/server/pipeline.d.ts +42 -10
  296. package/dist/server/pipeline.d.ts.map +1 -1
  297. package/dist/server/primitives.d.ts +69 -18
  298. package/dist/server/primitives.d.ts.map +1 -1
  299. package/dist/server/render-timeout.d.ts +51 -0
  300. package/dist/server/render-timeout.d.ts.map +1 -0
  301. package/dist/server/request-context.d.ts +112 -43
  302. package/dist/server/request-context.d.ts.map +1 -1
  303. package/dist/server/route-element-builder.d.ts +27 -1
  304. package/dist/server/route-element-builder.d.ts.map +1 -1
  305. package/dist/server/route-handler.d.ts.map +1 -1
  306. package/dist/server/route-matcher.d.ts +9 -2
  307. package/dist/server/route-matcher.d.ts.map +1 -1
  308. package/dist/server/rsc-entry/api-handler.d.ts +2 -2
  309. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  310. package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
  311. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  312. package/dist/server/rsc-entry/helpers.d.ts +48 -5
  313. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  314. package/dist/server/rsc-entry/index.d.ts +8 -3
  315. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  316. package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
  317. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  318. package/dist/server/rsc-entry/rsc-stream.d.ts +4 -1
  319. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  320. package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
  321. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  322. package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
  323. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  324. package/dist/server/safe-load.d.ts +46 -0
  325. package/dist/server/safe-load.d.ts.map +1 -0
  326. package/dist/server/sitemap-generator.d.ts +129 -0
  327. package/dist/server/sitemap-generator.d.ts.map +1 -0
  328. package/dist/server/sitemap-handler.d.ts +22 -0
  329. package/dist/server/sitemap-handler.d.ts.map +1 -0
  330. package/dist/server/slot-resolver.d.ts +1 -1
  331. package/dist/server/slot-resolver.d.ts.map +1 -1
  332. package/dist/server/ssr-entry.d.ts +22 -0
  333. package/dist/server/ssr-entry.d.ts.map +1 -1
  334. package/dist/server/ssr-render.d.ts +39 -21
  335. package/dist/server/ssr-render.d.ts.map +1 -1
  336. package/dist/server/ssr-wrappers.d.ts +50 -0
  337. package/dist/server/ssr-wrappers.d.ts.map +1 -0
  338. package/dist/server/status-code-resolver.d.ts +1 -1
  339. package/dist/server/status-code-resolver.d.ts.map +1 -1
  340. package/dist/server/stream-utils.d.ts +36 -0
  341. package/dist/server/stream-utils.d.ts.map +1 -0
  342. package/dist/server/tracing.d.ts +4 -4
  343. package/dist/server/tracing.d.ts.map +1 -1
  344. package/dist/server/tree-builder.d.ts +22 -19
  345. package/dist/server/tree-builder.d.ts.map +1 -1
  346. package/dist/server/types.d.ts +1 -4
  347. package/dist/server/types.d.ts.map +1 -1
  348. package/dist/server/version-skew.d.ts +61 -0
  349. package/dist/server/version-skew.d.ts.map +1 -0
  350. package/dist/shared/merge-search-params.d.ts +22 -0
  351. package/dist/shared/merge-search-params.d.ts.map +1 -0
  352. package/dist/shims/font-google.d.ts +1 -1
  353. package/dist/shims/font-google.d.ts.map +1 -1
  354. package/dist/shims/font-google.js +42 -0
  355. package/dist/shims/font-google.js.map +1 -0
  356. package/dist/shims/font-local.d.ts +26 -0
  357. package/dist/shims/font-local.d.ts.map +1 -0
  358. package/dist/shims/font-local.js +20 -0
  359. package/dist/shims/font-local.js.map +1 -0
  360. package/dist/shims/headers.d.ts +2 -1
  361. package/dist/shims/headers.d.ts.map +1 -1
  362. package/dist/shims/navigation-client.d.ts +1 -1
  363. package/dist/shims/navigation-client.d.ts.map +1 -1
  364. package/dist/shims/navigation.d.ts +3 -2
  365. package/dist/shims/navigation.d.ts.map +1 -1
  366. package/dist/utils/directive-parser.d.ts +5 -2
  367. package/dist/utils/directive-parser.d.ts.map +1 -1
  368. package/dist/utils/state-machine.d.ts +80 -0
  369. package/dist/utils/state-machine.d.ts.map +1 -0
  370. package/package.json +53 -23
  371. package/src/adapters/cloudflare-dev.ts +177 -0
  372. package/src/adapters/cloudflare-kv-cache.ts +142 -0
  373. package/src/adapters/cloudflare.ts +342 -28
  374. package/src/adapters/compress-module.ts +24 -4
  375. package/src/adapters/nitro.ts +52 -8
  376. package/src/adapters/wrangler.d.ts +7 -0
  377. package/src/cache/cache-api.ts +38 -0
  378. package/src/cache/handler-store.ts +68 -0
  379. package/src/cache/index.ts +81 -18
  380. package/src/cache/singleflight.ts +62 -4
  381. package/src/cache/sizeof.ts +31 -0
  382. package/src/cache/timber-cache.ts +24 -20
  383. package/src/cli.ts +6 -1
  384. package/src/client/browser-dev.ts +128 -1
  385. package/src/client/browser-entry/action-dispatch.ts +116 -0
  386. package/src/client/browser-entry/hmr.ts +81 -0
  387. package/src/client/browser-entry/hydrate.ts +145 -0
  388. package/src/client/browser-entry/index.ts +138 -0
  389. package/src/client/browser-entry/post-hydration.ts +119 -0
  390. package/src/client/browser-entry/router-init.ts +193 -0
  391. package/src/client/browser-entry/rsc-stream.ts +157 -0
  392. package/src/client/browser-entry/scroll.ts +27 -0
  393. package/src/client/error-boundary.tsx +48 -16
  394. package/src/client/error-reconstituter.tsx +65 -0
  395. package/src/client/form.tsx +2 -2
  396. package/src/client/history.ts +26 -4
  397. package/src/client/index.ts +19 -38
  398. package/src/client/internal.ts +57 -0
  399. package/src/client/link-pending-store.ts +111 -0
  400. package/src/client/link.tsx +329 -97
  401. package/src/client/nav-link-store.ts +47 -0
  402. package/src/client/navigation-api-types.ts +112 -0
  403. package/src/client/navigation-api.ts +332 -0
  404. package/src/client/navigation-context.ts +31 -6
  405. package/src/client/navigation-root.tsx +342 -0
  406. package/src/client/nuqs-adapter.tsx +16 -3
  407. package/src/client/router-ref.ts +1 -1
  408. package/src/client/router.ts +299 -72
  409. package/src/client/rsc-fetch.ts +97 -8
  410. package/src/client/segment-cache.ts +1 -1
  411. package/src/client/segment-outlet.tsx +86 -0
  412. package/src/client/ssr-data.ts +13 -5
  413. package/src/client/stale-reload.ts +72 -3
  414. package/src/client/top-loader.tsx +16 -8
  415. package/src/client/use-link-status.ts +7 -7
  416. package/src/client/use-params.ts +7 -5
  417. package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
  418. package/src/client/use-query-states.ts +3 -3
  419. package/src/client/use-router.ts +1 -1
  420. package/src/codec.ts +49 -0
  421. package/src/config-types.ts +208 -0
  422. package/src/content/index.ts +5 -13
  423. package/src/cookies/define-cookie.ts +78 -25
  424. package/src/cookies/index.ts +8 -0
  425. package/src/fonts/css.ts +2 -1
  426. package/src/index.ts +258 -354
  427. package/src/plugin-context.ts +200 -0
  428. package/src/plugins/adapter-build.ts +8 -2
  429. package/src/plugins/build-manifest.ts +13 -2
  430. package/src/plugins/build-report.ts +3 -3
  431. package/src/plugins/client-chunks.ts +65 -0
  432. package/src/plugins/content.ts +1 -1
  433. package/src/plugins/dev-browser-logs.ts +288 -0
  434. package/src/plugins/dev-error-overlay.ts +70 -1
  435. package/src/plugins/dev-logs.ts +1 -1
  436. package/src/plugins/dev-server.ts +70 -9
  437. package/src/plugins/entries.ts +71 -10
  438. package/src/plugins/fonts.ts +168 -61
  439. package/src/plugins/mdx.ts +1 -1
  440. package/src/plugins/routing.ts +57 -17
  441. package/src/plugins/server-action-exports.ts +1 -1
  442. package/src/plugins/server-bundle.ts +32 -1
  443. package/src/plugins/shims.ts +135 -35
  444. package/src/plugins/static-build.ts +17 -11
  445. package/src/routing/codegen.ts +165 -105
  446. package/src/routing/index.ts +2 -0
  447. package/src/routing/scanner.ts +93 -23
  448. package/src/routing/segment-classify.ts +89 -0
  449. package/src/routing/status-file-lint.ts +3 -2
  450. package/src/routing/types.ts +17 -4
  451. package/src/rsc-runtime/rsc.ts +2 -0
  452. package/src/rsc-runtime/ssr.ts +50 -0
  453. package/src/rsc-runtime/vendor-types.d.ts +7 -0
  454. package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
  455. package/src/search-params/define.ts +482 -0
  456. package/src/search-params/index.ts +14 -20
  457. package/src/search-params/registry.ts +2 -2
  458. package/src/search-params/wrappers.ts +85 -0
  459. package/src/segment-params/define.ts +279 -0
  460. package/src/segment-params/index.ts +29 -0
  461. package/src/server/access-gate.tsx +70 -29
  462. package/src/server/action-client.ts +21 -2
  463. package/src/server/action-encryption.ts +144 -0
  464. package/src/server/action-handler.ts +21 -4
  465. package/src/server/actions.ts +10 -9
  466. package/src/server/als-registry.ts +34 -6
  467. package/src/server/build-manifest.ts +10 -4
  468. package/src/server/compress.ts +25 -7
  469. package/src/server/debug.ts +1 -1
  470. package/src/server/default-logger.ts +99 -0
  471. package/src/server/deny-page-resolver.ts +154 -0
  472. package/src/server/deny-renderer.ts +24 -38
  473. package/src/server/dev-holding-server.ts +185 -0
  474. package/src/server/dev-warnings.ts +4 -49
  475. package/src/server/early-hints.ts +36 -15
  476. package/src/server/error-boundary-wrapper.ts +74 -22
  477. package/src/server/fallback-error.ts +31 -15
  478. package/src/server/flight-injection-state.ts +113 -0
  479. package/src/server/flight-scripts.ts +62 -0
  480. package/src/server/flush.ts +2 -1
  481. package/src/server/form-data.ts +76 -0
  482. package/src/server/html-injectors.ts +280 -120
  483. package/src/server/index.ts +26 -177
  484. package/src/server/internal.ts +169 -0
  485. package/src/server/logger.ts +44 -36
  486. package/src/server/middleware-runner.ts +31 -4
  487. package/src/server/node-stream-transforms.ts +509 -0
  488. package/src/server/page-deny-boundary.tsx +56 -0
  489. package/src/server/pipeline-interception.ts +17 -16
  490. package/src/server/pipeline-metadata.ts +13 -0
  491. package/src/server/pipeline.ts +227 -62
  492. package/src/server/primitives.ts +111 -28
  493. package/src/server/render-timeout.ts +108 -0
  494. package/src/server/request-context.ts +293 -132
  495. package/src/server/route-element-builder.ts +283 -191
  496. package/src/server/route-handler.ts +24 -4
  497. package/src/server/route-matcher.ts +24 -20
  498. package/src/server/rsc-entry/api-handler.ts +15 -16
  499. package/src/server/rsc-entry/error-renderer.ts +300 -89
  500. package/src/server/rsc-entry/helpers.ts +134 -5
  501. package/src/server/rsc-entry/index.ts +200 -112
  502. package/src/server/rsc-entry/rsc-payload.ts +65 -18
  503. package/src/server/rsc-entry/rsc-stream.ts +65 -13
  504. package/src/server/rsc-entry/ssr-bridge.ts +14 -5
  505. package/src/server/rsc-entry/ssr-renderer.ts +168 -38
  506. package/src/server/safe-load.ts +60 -0
  507. package/src/server/sitemap-generator.ts +338 -0
  508. package/src/server/sitemap-handler.ts +126 -0
  509. package/src/server/slot-resolver.ts +244 -229
  510. package/src/server/ssr-entry.ts +211 -32
  511. package/src/server/ssr-render.ts +289 -67
  512. package/src/server/ssr-wrappers.tsx +139 -0
  513. package/src/server/status-code-resolver.ts +1 -1
  514. package/src/server/stream-utils.ts +213 -0
  515. package/src/server/tracing.ts +20 -9
  516. package/src/server/tree-builder.ts +92 -58
  517. package/src/server/types.ts +3 -6
  518. package/src/server/version-skew.ts +104 -0
  519. package/src/shared/merge-search-params.ts +55 -0
  520. package/src/shims/font-google.ts +1 -1
  521. package/src/shims/font-local.ts +34 -0
  522. package/src/shims/headers.ts +5 -1
  523. package/src/shims/navigation-client.ts +1 -1
  524. package/src/shims/navigation.ts +7 -2
  525. package/src/utils/directive-parser.ts +5 -2
  526. package/src/utils/state-machine.ts +111 -0
  527. package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
  528. package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
  529. package/dist/_chunks/format-DviM89f0.js.map +0 -1
  530. package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
  531. package/dist/_chunks/request-context-DIkVh_jG.js +0 -330
  532. package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
  533. package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
  534. package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
  535. package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
  536. package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
  537. package/dist/cache/register-cached-function.d.ts +0 -17
  538. package/dist/cache/register-cached-function.d.ts.map +0 -1
  539. package/dist/client/browser-entry.d.ts +0 -21
  540. package/dist/client/browser-entry.d.ts.map +0 -1
  541. package/dist/client/link-status-provider.d.ts +0 -11
  542. package/dist/client/link-status-provider.d.ts.map +0 -1
  543. package/dist/client/transition-root.d.ts.map +0 -1
  544. package/dist/client/use-navigation-pending.d.ts.map +0 -1
  545. package/dist/cookies/index.js.map +0 -1
  546. package/dist/plugins/cache-transform.d.ts +0 -36
  547. package/dist/plugins/cache-transform.d.ts.map +0 -1
  548. package/dist/plugins/dynamic-transform.d.ts +0 -72
  549. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  550. package/dist/search-params/analyze.d.ts +0 -54
  551. package/dist/search-params/analyze.d.ts.map +0 -1
  552. package/dist/search-params/builtin-codecs.d.ts +0 -105
  553. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  554. package/dist/search-params/codecs.d.ts +0 -53
  555. package/dist/search-params/codecs.d.ts.map +0 -1
  556. package/dist/search-params/create.d.ts +0 -106
  557. package/dist/search-params/create.d.ts.map +0 -1
  558. package/dist/search-params/index.js.map +0 -1
  559. package/dist/server/prerender.d.ts +0 -77
  560. package/dist/server/prerender.d.ts.map +0 -1
  561. package/dist/server/response-cache.d.ts +0 -54
  562. package/dist/server/response-cache.d.ts.map +0 -1
  563. package/src/cache/register-cached-function.ts +0 -103
  564. package/src/client/browser-entry.ts +0 -678
  565. package/src/client/link-status-provider.tsx +0 -30
  566. package/src/client/transition-root.tsx +0 -166
  567. package/src/plugins/cache-transform.ts +0 -199
  568. package/src/plugins/dynamic-transform.ts +0 -161
  569. package/src/search-params/analyze.ts +0 -192
  570. package/src/search-params/builtin-codecs.ts +0 -228
  571. package/src/search-params/create.ts +0 -321
  572. package/src/server/prerender.ts +0 -139
  573. package/src/server/response-cache.ts +0 -410
@@ -13,7 +13,7 @@
13
13
 
14
14
  import { canonicalize } from './canonicalize.js';
15
15
  import { runProxy, type ProxyExport } from './proxy.js';
16
- import { runMiddleware, type MiddlewareFn } from './middleware-runner.js';
16
+ import { runMiddlewareChain, type MiddlewareFn } from './middleware-runner.js';
17
17
  import { runWithTimingCollector, withTiming, getServerTimingHeader } from './server-timing.js';
18
18
  import {
19
19
  runWithRequestContext,
@@ -21,6 +21,7 @@ import {
21
21
  setMutableCookieContext,
22
22
  getSetCookieHeaders,
23
23
  markResponseFlushed,
24
+ setSegmentParams,
24
25
  } from './request-context.js';
25
26
  import {
26
27
  generateTraceId,
@@ -29,7 +30,7 @@ import {
29
30
  replaceTraceId,
30
31
  withSpan,
31
32
  setSpanAttribute,
32
- traceId,
33
+ getTraceId,
33
34
  } from './tracing.js';
34
35
  import {
35
36
  logRequestReceived,
@@ -42,10 +43,35 @@ import {
42
43
  } from './logger.js';
43
44
  import { callOnRequestError } from './instrumentation.js';
44
45
  import { RedirectSignal, DenySignal } from './primitives.js';
46
+ import { ParamCoercionError } from './route-element-builder.js';
47
+ import { checkVersionSkew, applyReloadHeaders } from './version-skew.js';
45
48
  import { serveStaticMetadataFile, serializeSitemap } from './pipeline-metadata.js';
49
+ import { loadModule } from './safe-load.js';
46
50
  import { findInterceptionMatch } from './pipeline-interception.js';
47
51
  import type { MiddlewareContext } from './types.js';
48
- import type { SegmentNode } from '#/routing/types.js';
52
+ import type { SegmentNode } from '../routing/types.js';
53
+
54
+ // ─── Prototype-Pollution-Safe Merge ────────────────────────────────────────
55
+
56
+ /** Keys that must never be merged via Object.assign — they pollute Object.prototype. */
57
+ const DANGEROUS_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
58
+
59
+ /**
60
+ * Shallow merge that skips prototype-polluting keys.
61
+ *
62
+ * Used instead of Object.assign when the source object comes from
63
+ * user-authored codec output (segmentParams.parse), which could
64
+ * contain __proto__, constructor, or prototype keys.
65
+ *
66
+ * See TIM-655, design/13-security.md
67
+ */
68
+ export function safeMerge(target: Record<string, unknown>, source: Record<string, unknown>): void {
69
+ for (const key of Object.keys(source)) {
70
+ if (!DANGEROUS_KEYS.has(key)) {
71
+ target[key] = source[key];
72
+ }
73
+ }
74
+ }
49
75
 
50
76
  // ─── Route Match Result ────────────────────────────────────────────────────
51
77
 
@@ -53,10 +79,10 @@ import type { SegmentNode } from '#/routing/types.js';
53
79
  export interface RouteMatch {
54
80
  /** The matched segment chain from root to leaf. */
55
81
  segments: SegmentNode[];
56
- /** Extracted route params (catch-all segments produce string[]). */
57
- params: Record<string, string | string[]>;
58
- /** The leaf segment's middleware.ts export, if any. */
59
- middleware?: MiddlewareFn;
82
+ /** Extracted segment params (catch-all segments produce string[]). */
83
+ segmentParams: Record<string, string | string[]>;
84
+ /** Middleware chain from the segment tree, ordered root-to-leaf. */
85
+ middlewareChain: MiddlewareFn[];
60
86
  }
61
87
 
62
88
  /** Function that matches a canonical pathname to a route. */
@@ -115,14 +141,25 @@ export interface PipelineConfig {
115
141
  * Generated at build time from intercepting route directories.
116
142
  * See design/07-routing.md §"Intercepting Routes"
117
143
  */
118
- interceptionRewrites?: import('#/routing/interception.js').InterceptionRewrite[];
144
+ interceptionRewrites?: import('../routing/interception.js').InterceptionRewrite[];
145
+ /**
146
+ * Control Server-Timing header output.
147
+ *
148
+ * - `'detailed'` — per-phase breakdown (proxy, middleware, render).
149
+ * - `'total'` — single `total;dur=N` entry (production-safe).
150
+ * - `false` — no Server-Timing header at all.
151
+ *
152
+ * Default: `'total'`.
153
+ */
154
+ serverTiming?: 'detailed' | 'total' | false;
119
155
  /**
120
- * Emit Server-Timing header on responses for Chrome DevTools visibility.
121
- * Only enable in dev mode exposes internal timing data.
156
+ * Auto-generated sitemap handler. When provided, the pipeline intercepts
157
+ * `/sitemap.xml` and `/sitemap/N.xml` requests and delegates to this
158
+ * function. Returns a Response or null (pass-through to regular routing).
122
159
  *
123
- * Default: false (production-safe).
160
+ * See design/16-metadata.md §"Auto-generated Sitemap"
124
161
  */
125
- enableServerTiming?: boolean;
162
+ autoSitemapHandler?: (pathname: string) => Promise<Response | null>;
126
163
  /**
127
164
  * Dev pipeline error callback — called when a pipeline phase (proxy,
128
165
  * middleware, render) catches an unhandled error. Used to wire the error
@@ -149,6 +186,51 @@ export interface PipelineConfig {
149
186
  ) => Response | Promise<Response>;
150
187
  }
151
188
 
189
+ // ─── Param Coercion ────────────────────────────────────────────────────────
190
+
191
+ /**
192
+ * Run segment param coercion on the matched route's segments.
193
+ *
194
+ * Loads params.ts modules from segments that have them, extracts the
195
+ * segmentParams definition, and coerces raw string params through codecs.
196
+ * Throws ParamCoercionError if any codec fails (→ 404).
197
+ *
198
+ * This runs BEFORE middleware, so ctx.segmentParams is already typed.
199
+ * See design/07-routing.md §"Where Coercion Runs"
200
+ */
201
+ export async function coerceSegmentParams(match: RouteMatch): Promise<void> {
202
+ const segments = match.segments as unknown as import('./route-matcher.js').ManifestSegmentNode[];
203
+
204
+ for (const segment of segments) {
205
+ // Only process segments that have a params.ts convention file
206
+ if (!segment.params) continue;
207
+
208
+ let mod: Record<string, unknown>;
209
+ try {
210
+ mod = await loadModule(segment.params);
211
+ } catch (err) {
212
+ throw new ParamCoercionError(
213
+ `Failed to load params module for segment "${segment.segmentName}": ${err instanceof Error ? err.message : String(err)}`
214
+ );
215
+ }
216
+
217
+ const segmentParamsDef = mod.segmentParams as
218
+ | { parse(raw: Record<string, string | string[]>): Record<string, unknown> }
219
+ | undefined;
220
+
221
+ if (!segmentParamsDef || typeof segmentParamsDef.parse !== 'function') continue;
222
+
223
+ try {
224
+ const coerced = segmentParamsDef.parse(match.segmentParams);
225
+ // Merge coerced values back — use safeMerge to prevent prototype pollution
226
+ // from malicious/buggy codec output. See TIM-655.
227
+ safeMerge(match.segmentParams, coerced as Record<string, unknown>);
228
+ } catch (err) {
229
+ throw new ParamCoercionError(err instanceof Error ? err.message : String(err));
230
+ }
231
+ }
232
+ }
233
+
152
234
  // ─── Pipeline ──────────────────────────────────────────────────────────────
153
235
 
154
236
  /**
@@ -165,7 +247,7 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
165
247
  earlyHints,
166
248
  stripTrailingSlash = true,
167
249
  slowRequestMs = 3000,
168
- enableServerTiming = false,
250
+ serverTiming = 'total',
169
251
  onPipelineError,
170
252
  } = config;
171
253
 
@@ -186,7 +268,7 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
186
268
  const traceIdValue = generateTraceId();
187
269
 
188
270
  return runWithTraceId(traceIdValue, async () => {
189
- // Establish request context ALS scope so headers() and cookies() work
271
+ // Establish request context ALS scope so getHeaders() and getCookies() work
190
272
  // throughout the entire request lifecycle (proxy, middleware, render).
191
273
  return runWithRequestContext(req, async () => {
192
274
  // In dev mode, wrap with timing collector for Server-Timing header.
@@ -216,25 +298,25 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
216
298
  // DevSpanProcessor reads this for tree/summary output.
217
299
  await setSpanAttribute('http.response.status_code', result.status);
218
300
 
219
- // Append Server-Timing header.
220
- // In dev mode: detailed per-phase breakdown (proxy, middleware, render).
221
- // In production: single total duration — safe to expose, no phase names.
301
+ // Append Server-Timing header based on configured mode.
222
302
  // Response.redirect() creates immutable headers, so we must
223
303
  // ensure mutability before writing Server-Timing.
224
- if (enableServerTiming) {
225
- const serverTiming = getServerTimingHeader();
226
- if (serverTiming) {
304
+ if (serverTiming === 'detailed') {
305
+ // Detailed: per-phase breakdown (proxy, middleware, render).
306
+ const timingHeader = getServerTimingHeader();
307
+ if (timingHeader) {
227
308
  result = ensureMutableResponse(result);
228
- result.headers.set('Server-Timing', serverTiming);
309
+ result.headers.set('Server-Timing', timingHeader);
229
310
  }
230
- } else {
231
- // Production: emit total request duration only.
232
- // No phase breakdown prevents information disclosure
233
- // while giving browser DevTools useful timing data.
311
+ } else if (serverTiming === 'total') {
312
+ // Total only: single `total;dur=N` no phase names.
313
+ // Prevents information disclosure while giving browser
314
+ // DevTools useful timing data.
234
315
  const totalMs = Math.round(performance.now() - startTime);
235
316
  result = ensureMutableResponse(result);
236
317
  result.headers.set('Server-Timing', `total;dur=${totalMs}`);
237
318
  }
319
+ // serverTiming === false: no header at all
238
320
 
239
321
  return result;
240
322
  }
@@ -254,7 +336,7 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
254
336
  return response;
255
337
  };
256
338
 
257
- return enableServerTiming ? runWithTimingCollector(runRequest) : runRequest();
339
+ return serverTiming === 'detailed' ? runWithTimingCollector(runRequest) : runRequest();
258
340
  });
259
341
  });
260
342
  };
@@ -272,7 +354,7 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
272
354
  }
273
355
  const proxyFn = () => runProxy(proxyExport, req, () => handleRequest(req, method, path));
274
356
  return await withSpan('timber.proxy', {}, () =>
275
- enableServerTiming ? withTiming('proxy', 'proxy.ts', proxyFn) : proxyFn()
357
+ serverTiming === 'detailed' ? withTiming('proxy', 'proxy.ts', proxyFn) : proxyFn()
276
358
  );
277
359
  } catch (error) {
278
360
  // Uncaught proxy.ts error → bare HTTP 500
@@ -283,6 +365,24 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
283
365
  }
284
366
  }
285
367
 
368
+ /**
369
+ * Build a redirect Response from a RedirectSignal.
370
+ *
371
+ * For RSC payload requests (client navigation), returns 204 + X-Timber-Redirect
372
+ * so the client router can perform a soft SPA redirect. A raw 302 would be
373
+ * turned into an opaque redirect by fetch({redirect:'manual'}), crashing
374
+ * createFromFetch. See design/19-client-navigation.md.
375
+ */
376
+ function buildRedirectResponse(signal: RedirectSignal, req: Request, headers: Headers): Response {
377
+ const isRsc = (req.headers.get('Accept') ?? '').includes('text/x-component');
378
+ if (isRsc) {
379
+ headers.set('X-Timber-Redirect', signal.location);
380
+ return new Response(null, { status: 204, headers });
381
+ }
382
+ headers.set('Location', signal.location);
383
+ return new Response(null, { status: signal.status, headers });
384
+ }
385
+
286
386
  async function handleRequest(req: Request, method: string, path: string): Promise<Response> {
287
387
  // Stage 1: URL canonicalization
288
388
  const url = new URL(req.url);
@@ -306,7 +406,7 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
306
406
  return await serveStaticMetadataFile(metaMatch);
307
407
  }
308
408
 
309
- const mod = (await metaMatch.file.load()) as { default?: Function };
409
+ const mod = await loadModule<{ default?: Function }>(metaMatch.file);
310
410
  if (typeof mod.default !== 'function') {
311
411
  return new Response('Metadata route must export a default function', { status: 500 });
312
412
  }
@@ -339,6 +439,36 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
339
439
  }
340
440
  }
341
441
 
442
+ // Stage 1b.2: Auto-generated sitemap — serves /sitemap.xml and /sitemap/N.xml
443
+ // when sitemap generation is enabled and no user-authored sitemap exists.
444
+ // Runs after metadata route matching so user sitemaps always take precedence.
445
+ // See design/16-metadata.md §"Auto-generated Sitemap"
446
+ if (config.autoSitemapHandler) {
447
+ try {
448
+ const sitemapResponse = await config.autoSitemapHandler(canonicalPathname);
449
+ if (sitemapResponse) return sitemapResponse;
450
+ } catch (error) {
451
+ logRenderError({ method, path, error });
452
+ if (onPipelineError && error instanceof Error) onPipelineError(error, 'auto-sitemap');
453
+ return new Response(null, { status: 500 });
454
+ }
455
+ }
456
+
457
+ // Stage 1c: Version skew detection (TIM-446).
458
+ // For RSC payload requests (client navigation), check if the client's
459
+ // deployment ID matches the current build. On mismatch, signal the
460
+ // client to do a full page reload instead of returning an RSC payload
461
+ // that references mismatched module IDs.
462
+ const isRscRequest = (req.headers.get('Accept') ?? '').includes('text/x-component');
463
+ if (isRscRequest) {
464
+ const skewCheck = checkVersionSkew(req);
465
+ if (!skewCheck.ok) {
466
+ const reloadHeaders = new Headers();
467
+ applyReloadHeaders(reloadHeaders);
468
+ return new Response(null, { status: 204, headers: reloadHeaders });
469
+ }
470
+ }
471
+
342
472
  // Stage 2: Route matching
343
473
  let match = matchRoute(canonicalPathname);
344
474
  let interception: InterceptionContext | undefined;
@@ -397,18 +527,57 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
397
527
  }
398
528
  }
399
529
 
400
- // Stage 3: Leaf middleware.ts (only the leaf route's middleware runs)
401
- if (match.middleware) {
530
+ // Stage 2c: Param coercion (before middleware)
531
+ // Load params.ts modules from matched segments and coerce raw string
532
+ // params through defineSegmentParams codecs. Coercion failure → 404
533
+ // (middleware never runs). See design/07-routing.md §"Where Coercion Runs"
534
+ try {
535
+ await coerceSegmentParams(match);
536
+ } catch (error) {
537
+ if (error instanceof ParamCoercionError) {
538
+ // For API routes (route.ts), return a bare 404 — not an HTML page.
539
+ // API consumers expect JSON/empty responses, not rendered HTML.
540
+ const leafSegment = match.segments[match.segments.length - 1];
541
+ if (
542
+ (leafSegment as { route?: unknown }).route &&
543
+ !(leafSegment as { page?: unknown }).page
544
+ ) {
545
+ return new Response(null, { status: 404 });
546
+ }
547
+ // Route through the app's 404 page (404.tsx in root layout) instead of
548
+ // returning a bare empty 404 Response. Falls back to bare 404 only if
549
+ // no renderNoMatch renderer is configured.
550
+ if (config.renderNoMatch) {
551
+ return config.renderNoMatch(req, responseHeaders);
552
+ }
553
+ return new Response(null, { status: 404 });
554
+ }
555
+ throw error;
556
+ }
557
+
558
+ // Store coerced segment params in ALS so components can access them
559
+ // via getSegmentParams() instead of receiving them as a prop.
560
+ // See design/07-routing.md §"params.ts — Convention File for Typed Params"
561
+ setSegmentParams(match.segmentParams);
562
+
563
+ // Stage 3: Middleware chain (root-to-leaf, short-circuits on first Response)
564
+ if (match.middlewareChain.length > 0) {
402
565
  const ctx: MiddlewareContext = {
403
566
  req,
404
567
  requestHeaders: requestHeaderOverlay,
405
568
  headers: responseHeaders,
406
- params: match.params,
407
- searchParams: new URL(req.url).searchParams,
569
+ segmentParams: match.segmentParams,
408
570
  earlyHints: (hints) => {
409
571
  for (const hint of hints) {
410
- let value = `<${hint.href}>; rel=${hint.rel}`;
411
- if (hint.as !== undefined) value += `; as=${hint.as}`;
572
+ // Match Cloudflare's cached Early Hints attribute order: `as` before `rel`.
573
+ // Cloudflare caches Link headers and re-emits them on subsequent 200s.
574
+ // If our order differs, the browser sees duplicate preloads and warns.
575
+ let value: string;
576
+ if (hint.as !== undefined) {
577
+ value = `<${hint.href}>; as=${hint.as}; rel=${hint.rel}`;
578
+ } else {
579
+ value = `<${hint.href}>; rel=${hint.rel}`;
580
+ }
412
581
  if (hint.crossOrigin !== undefined) value += `; crossorigin=${hint.crossOrigin}`;
413
582
  if (hint.fetchPriority !== undefined) value += `; fetchpriority=${hint.fetchPriority}`;
414
583
  responseHeaders.append('Link', value);
@@ -419,9 +588,9 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
419
588
  try {
420
589
  // Enable cookie mutation during middleware (design/29-cookies.md §"Context Tracking")
421
590
  setMutableCookieContext(true);
422
- const middlewareFn = () => runMiddleware(match.middleware!, ctx);
591
+ const chainFn = () => runMiddlewareChain(match.middlewareChain, ctx);
423
592
  const middlewareResponse = await withSpan('timber.middleware', {}, () =>
424
- enableServerTiming ? withTiming('mw', 'middleware.ts', middlewareFn) : middlewareFn()
593
+ serverTiming === 'detailed' ? withTiming('mw', 'middleware.ts', chainFn) : chainFn()
425
594
  );
426
595
  setMutableCookieContext(false);
427
596
  if (middlewareResponse) {
@@ -430,28 +599,30 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
430
599
  // mutability before appending Set-Cookie entries.
431
600
  const finalResponse = ensureMutableResponse(middlewareResponse);
432
601
  applyCookieJar(finalResponse.headers);
602
+ // Merge parent-set responseHeaders onto the short-circuit response.
603
+ // Child-set headers take precedence — only add headers not already present.
604
+ // Snapshot existing keys first so multi-value headers (Set-Cookie, Link)
605
+ // from the parent are all appended when the child didn't set that key.
606
+ const existingKeys = new Set(
607
+ [...finalResponse.headers.keys()].map((k) => k.toLowerCase())
608
+ );
609
+ for (const [key, value] of responseHeaders.entries()) {
610
+ if (!existingKeys.has(key.toLowerCase())) {
611
+ finalResponse.headers.append(key, value);
612
+ }
613
+ }
433
614
  logMiddlewareShortCircuit({ method, path, status: finalResponse.status });
434
615
  return finalResponse;
435
616
  }
436
- // Middleware succeeded without short-circuiting — apply any
437
- // injected request headers so headers() returns them downstream.
617
+ // Middleware chain completed without short-circuiting — apply any
618
+ // injected request headers so getHeaders() returns them downstream.
438
619
  applyRequestHeaderOverlay(requestHeaderOverlay);
439
620
  } catch (error) {
440
621
  setMutableCookieContext(false);
441
- // RedirectSignal from middleware → HTTP redirect (not an error).
442
- // For RSC payload requests (client navigation), return 204 + X-Timber-Redirect
443
- // so the client router can perform a soft SPA redirect. A raw 302 would be
444
- // turned into an opaque redirect by fetch({redirect:'manual'}), crashing
445
- // createFromFetch. See design/19-client-navigation.md.
622
+ // RedirectSignal from middleware → HTTP redirect (not an error)
446
623
  if (error instanceof RedirectSignal) {
447
624
  applyCookieJar(responseHeaders);
448
- const isRsc = (req.headers.get('Accept') ?? '').includes('text/x-component');
449
- if (isRsc) {
450
- responseHeaders.set('X-Timber-Redirect', error.location);
451
- return new Response(null, { status: 204, headers: responseHeaders });
452
- }
453
- responseHeaders.set('Location', error.location);
454
- return new Response(null, { status: error.status, headers: responseHeaders });
625
+ return buildRedirectResponse(error, req, responseHeaders);
455
626
  }
456
627
  // DenySignal from middleware → HTTP deny status
457
628
  if (error instanceof DenySignal) {
@@ -476,7 +647,9 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
476
647
  const renderFn = () =>
477
648
  render(req, match, responseHeaders, requestHeaderOverlay, interception);
478
649
  const response = await withSpan('timber.render', { 'http.route': canonicalPathname }, () =>
479
- enableServerTiming ? withTiming('render', 'RSC + SSR render', renderFn) : renderFn()
650
+ serverTiming === 'detailed'
651
+ ? withTiming('render', 'RSC + SSR render', renderFn)
652
+ : renderFn()
480
653
  );
481
654
  markResponseFlushed();
482
655
  return response;
@@ -486,17 +659,9 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
486
659
  if (error instanceof DenySignal) {
487
660
  return new Response(null, { status: error.status });
488
661
  }
489
- // RedirectSignal leaked from render — honour the redirect.
490
- // For RSC payload requests, return 204 + X-Timber-Redirect so the
491
- // client router can perform a soft SPA redirect (same as middleware path).
662
+ // RedirectSignal leaked from render — honour the redirect
492
663
  if (error instanceof RedirectSignal) {
493
- const isRsc = (req.headers.get('Accept') ?? '').includes('text/x-component');
494
- if (isRsc) {
495
- responseHeaders.set('X-Timber-Redirect', error.location);
496
- return new Response(null, { status: 204, headers: responseHeaders });
497
- }
498
- responseHeaders.set('Location', error.location);
499
- return new Response(null, { status: error.status, headers: responseHeaders });
664
+ return buildRedirectResponse(error, req, responseHeaders);
500
665
  }
501
666
  logRenderError({ method, path, error });
502
667
  await fireOnRequestError(error, req, 'render');
@@ -532,7 +697,7 @@ async function fireOnRequestError(
532
697
  await callOnRequestError(
533
698
  error,
534
699
  { method: req.method, path: url.pathname, headers: headersObj },
535
- { phase, routePath: url.pathname, routeType: 'page', traceId: traceId() }
700
+ { phase, routePath: url.pathname, routeType: 'page', traceId: getTraceId() }
536
701
  );
537
702
  }
538
703
 
@@ -6,6 +6,8 @@
6
6
  import type { JsonSerializable } from './types.js';
7
7
  import { getWaitUntil as _getWaitUntil } from './waituntil-bridge.js';
8
8
  import { isDebug } from './debug.js';
9
+ import { getRequestSearchString } from './request-context.js';
10
+ import { mergePreservedSearchParams } from '../shared/merge-search-params.js';
9
11
 
10
12
  // ─── Dev-mode validation ────────────────────────────────────────────────────
11
13
 
@@ -143,37 +145,65 @@ export class DenySignal extends Error {
143
145
  }
144
146
  }
145
147
 
148
+ /** Options for deny() when using the object form. */
149
+ export interface DenyOptions {
150
+ /** HTTP status code (4xx or 5xx). Default: 403. */
151
+ status?: number;
152
+ /** Human-readable message (logged server-side, not sent to client). */
153
+ message?: string;
154
+ /** JSON-serializable data passed as `dangerouslyPassData` prop to status-code files. */
155
+ data?: JsonSerializable;
156
+ }
157
+
146
158
  /**
147
- * Universal denial primitive. Throws a `DenySignal` that the framework catches.
159
+ * Universal denial/error primitive. Throws a `DenySignal` that the framework catches.
148
160
  *
149
161
  * - In segment context (outside Suspense): produces HTTP status code
150
162
  * - In slot context: graceful degradation → denied.tsx → default.tsx → null
151
163
  * - Inside Suspense (hold window): promoted to pre-flush behavior
152
164
  * - Inside Suspense (after flush): error boundary + noindex meta
153
165
  *
154
- * @param status - Any 4xx HTTP status code. Defaults to 403.
155
- * @param data - Optional JSON-serializable data passed as `dangerouslyPassData` prop to status-code files.
166
+ * Supports both positional and object signatures:
167
+ * ```ts
168
+ * deny() // 403 (default)
169
+ * deny(404) // 404
170
+ * deny(503, { retry: true }) // 503 with data
171
+ * deny({ status: 503, message: 'Maintenance' }) // object form
172
+ * ```
173
+ *
174
+ * Accepts any 4xx or 5xx status code. This replaces the need for
175
+ * `throw new RenderError(...)` in user code — RenderError is now an
176
+ * internal pipeline detail.
177
+ *
178
+ * @param statusOrOptions - Status code (number) or options object. Default: 403.
179
+ * @param data - Optional JSON-serializable data (positional form only).
156
180
  */
157
- export function deny(status: number = 403, data?: JsonSerializable): never {
158
- if (status < 400 || status > 499) {
159
- throw new Error(
160
- `deny() requires a 4xx status code, got ${status}. ` +
161
- 'For 5xx errors, throw a RenderError instead.'
162
- );
181
+ export function deny(statusOrOptions?: number | DenyOptions, data?: JsonSerializable): never {
182
+ let status: number;
183
+ let resolvedData: JsonSerializable | undefined;
184
+
185
+ if (typeof statusOrOptions === 'object' && statusOrOptions !== null) {
186
+ status = statusOrOptions.status ?? 403;
187
+ resolvedData = statusOrOptions.data;
188
+ } else {
189
+ status = statusOrOptions ?? 403;
190
+ resolvedData = data;
163
191
  }
164
- warnIfNotSerializable(data, 'deny()');
165
- throw new DenySignal(status, data);
192
+
193
+ if (status < 400 || status > 599) {
194
+ throw new Error(`deny() requires a 4xx or 5xx status code, got ${status}.`);
195
+ }
196
+ warnIfNotSerializable(resolvedData, 'deny()');
197
+ throw new DenySignal(status, resolvedData);
166
198
  }
167
199
 
168
200
  /**
169
- * Convenience alias for `deny(404)`.
170
- *
171
- * Provided for Next.js API compatibility — libraries and user code that
172
- * call `notFound()` from `next/navigation` get the same behavior as
173
- * `deny(404)` in timber.
201
+ * @deprecated Use `deny(404)` instead.
202
+ * Kept for internal use by the Next.js shim layer.
203
+ * @internal
174
204
  */
175
205
  export function notFound(): never {
176
- throw new DenySignal(404);
206
+ deny(404);
177
207
  }
178
208
 
179
209
  /**
@@ -209,14 +239,63 @@ export class RedirectSignal extends Error {
209
239
  /** Pattern matching absolute URLs: http(s):// or protocol-relative // */
210
240
  const ABSOLUTE_URL_RE = /^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/)/;
211
241
 
242
+ /**
243
+ * Options for redirect() — alternative to passing a bare status code.
244
+ */
245
+ export interface RedirectOptions {
246
+ /** HTTP redirect status code (3xx). Defaults to 302 (or 308 when `permanent: true`). */
247
+ status?: number;
248
+ /**
249
+ * When true, defaults the status to 308 (Permanent Redirect, preserves HTTP method).
250
+ * If `status` is also provided, `status` takes precedence.
251
+ *
252
+ * @example
253
+ * redirect('/new-path', { permanent: true }); // 308
254
+ * redirect('/new-path', { permanent: true, status: 301 }); // 301
255
+ */
256
+ permanent?: boolean;
257
+ /**
258
+ * Preserve search params from the current request URL on the redirect target.
259
+ *
260
+ * - `true` — preserve ALL current search params (target params take precedence)
261
+ * - `string[]` — preserve only the named params (e.g. `['private', 'token']`)
262
+ *
263
+ * Target path's own query params always take precedence over preserved ones.
264
+ */
265
+ preserveSearchParams?: true | string[];
266
+ }
267
+
212
268
  /**
213
269
  * Redirect to a relative path. Rejects absolute and protocol-relative URLs.
214
270
  * Use `redirectExternal()` for external redirects with an allow-list.
215
271
  *
216
272
  * @param path - Relative path (e.g. '/login', 'settings', '/login?returnTo=/dash')
217
- * @param status - HTTP redirect status code (3xx). Defaults to 302.
273
+ * @param statusOrOptions - HTTP status code (3xx, default 302) or options object.
274
+ *
275
+ * @example
276
+ * // Simple redirect
277
+ * redirect('/login');
278
+ *
279
+ * // With status code
280
+ * redirect('/login', 301);
281
+ *
282
+ * // With preserved search params
283
+ * redirect(`/docs/${version}/${slug}`, { preserveSearchParams: ['foo'] });
218
284
  */
219
- export function redirect(path: string, status: number = 302): never {
285
+ export function redirect(path: string, statusOrOptions?: number | RedirectOptions): never {
286
+ let status: number;
287
+ let preserveSearchParams: true | string[] | undefined;
288
+
289
+ if (typeof statusOrOptions === 'number') {
290
+ status = statusOrOptions;
291
+ } else if (statusOrOptions) {
292
+ // Explicit status wins. Otherwise permanent: true → 308, default → 302.
293
+ status = statusOrOptions.status ?? (statusOrOptions.permanent ? 308 : 302);
294
+ preserveSearchParams = statusOrOptions.preserveSearchParams;
295
+ } else {
296
+ status = 302;
297
+ }
298
+
220
299
  if (status < 300 || status > 399) {
221
300
  throw new Error(`redirect() requires a 3xx status code, got ${status}.`);
222
301
  }
@@ -226,19 +305,23 @@ export function redirect(path: string, status: number = 302): never {
226
305
  'Use redirectExternal(url, allowList) for external redirects.'
227
306
  );
228
307
  }
229
- throw new RedirectSignal(path, status);
308
+
309
+ let resolvedPath = path;
310
+ if (preserveSearchParams) {
311
+ const currentSearch = getRequestSearchString();
312
+ resolvedPath = mergePreservedSearchParams(path, currentSearch, preserveSearchParams);
313
+ }
314
+
315
+ throw new RedirectSignal(resolvedPath, status);
230
316
  }
231
317
 
232
318
  /**
233
- * Permanent redirect to a relative path. Shorthand for `redirect(path, 308)`.
234
- *
235
- * Uses 308 (Permanent Redirect) which preserves the HTTP method — the browser
236
- * will replay POST requests to the new location. This matches Next.js behavior.
237
- *
238
- * @param path - Relative path (e.g. '/new-page', '/dashboard')
319
+ * @deprecated Use `redirect(path, { permanent: true })` instead.
320
+ * Kept for internal use by the Next.js shim layer.
321
+ * @internal
239
322
  */
240
- export function permanentRedirect(path: string): never {
241
- redirect(path, 308);
323
+ export function permanentRedirect(path: string, options?: Omit<RedirectOptions, 'status'>): never {
324
+ redirect(path, { permanent: true, ...options });
242
325
  }
243
326
 
244
327
  /**