@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
@@ -16,18 +16,21 @@
16
16
  */
17
17
 
18
18
  import { createElement } from 'react';
19
- import { renderToReadableStream } from '#/rsc-runtime/rsc.js';
19
+ import { renderToReadableStream } from '../rsc-runtime/rsc.js';
20
20
 
21
21
  import { DenySignal } from './primitives.js';
22
22
  import { logRenderError } from './logger.js';
23
+ import { loadModule } from './safe-load.js';
23
24
  import { isDebug } from './debug.js';
24
25
  import { resolveMetadata, renderMetadataToElements } from './metadata.js';
25
26
  import { resolveManifestStatusFile } from './manifest-status-resolver.js';
26
27
  import type { ManifestSegmentNode } from './route-matcher.js';
27
28
  import type { RouteMatch } from './pipeline.js';
28
29
  import type { NavContext } from './ssr-entry.js';
30
+ import { flightInitScript } from './flight-scripts.js';
29
31
  import type { ClientBootstrapConfig } from './html-injectors.js';
30
32
  import type { Metadata } from './types.js';
33
+ import { teeWithErrorPropagation } from './stream-utils.js';
31
34
 
32
35
  /** RSC content type for client navigation payload requests. */
33
36
  const RSC_CONTENT_TYPE = 'text/x-component';
@@ -108,7 +111,7 @@ export async function renderDenyPage(
108
111
  }
109
112
 
110
113
  // Load the status-code page component
111
- const mod = (await resolution.file.load()) as Record<string, unknown>;
114
+ const mod = await loadModule(resolution.file);
112
115
  if (!mod.default) {
113
116
  return new Response(null, { status: deny.status, headers: responseHeaders });
114
117
  }
@@ -116,9 +119,6 @@ export async function renderDenyPage(
116
119
  const ErrorPageComponent = mod.default as (...args: unknown[]) => unknown;
117
120
  const h = createElement as (...args: unknown[]) => React.ReactElement;
118
121
 
119
- // Check shell opt-out: export const shell = false
120
- const shellEnabled = mod.shell !== false;
121
-
122
122
  // 4xx status-code pages receive { status, dangerouslyPassData }
123
123
  // per design/10-error-handling.md §"Status-Code File Props"
124
124
  let element = h(ErrorPageComponent, {
@@ -126,23 +126,14 @@ export async function renderDenyPage(
126
126
  dangerouslyPassData: deny.data,
127
127
  });
128
128
 
129
- // Wrap in layouts unless shell is explicitly disabled
130
- if (shellEnabled) {
131
- const resolvedSegments = new Set(segments.slice(0, resolution.segmentIndex + 1));
132
- const layoutsToWrap = layoutComponents.filter((lc) => resolvedSegments.has(lc.segment));
133
- for (let i = layoutsToWrap.length - 1; i >= 0; i--) {
134
- const { component } = layoutsToWrap[i];
135
- element = h(component, null, element);
136
- }
137
- } else if (isDebug()) {
138
- // Dev-mode: warn if shell=false might conflict with Suspense
139
- // The actual Suspense boundary check happens at render time in the pipeline.
140
- // This is a preemptive log for developer awareness.
141
- console.warn(
142
- `[timber] Status-code file ${resolution.file.filePath} exports shell = false. ` +
143
- 'If deny() fires inside a Suspense boundary, layouts are already committed and ' +
144
- 'cannot be unwrapped. The shell opt-out will be ignored in that case.'
145
- );
129
+ // Always wrap in layout shell.
130
+ // NOTE: Shell opt-out (export const shell = false) is a future feature
131
+ // pending a proper design doc. See design backlog.
132
+ const resolvedSegments = new Set(segments.slice(0, resolution.segmentIndex + 1));
133
+ const layoutsToWrap = layoutComponents.filter((lc) => resolvedSegments.has(lc.segment));
134
+ for (let i = layoutsToWrap.length - 1; i >= 0; i--) {
135
+ const { component } = layoutsToWrap[i];
136
+ element = h(component, null, element);
146
137
  }
147
138
 
148
139
  // Build head HTML from error page metadata (if any)
@@ -170,15 +161,15 @@ export async function renderDenyPage(
170
161
  debugChannel: createDebugChannelSink(),
171
162
  });
172
163
 
173
- const [ssrStream, inlineStream] = rscStream.tee();
164
+ const [ssrStream, inlineStream] = teeWithErrorPropagation(rscStream);
174
165
 
175
166
  const navContext: NavContext = {
176
167
  pathname: new URL(req.url).pathname,
177
- params: match.params,
168
+ params: match.segmentParams,
178
169
  searchParams: Object.fromEntries(new URL(req.url).searchParams),
179
170
  statusCode: deny.status,
180
171
  responseHeaders,
181
- headHtml,
172
+ headHtml: headHtml + flightInitScript(),
182
173
  bootstrapScriptContent: clientBootstrap.bootstrapScriptContent,
183
174
  rscStream: inlineStream,
184
175
  };
@@ -206,7 +197,7 @@ export async function renderDenyPageAsRsc(
206
197
  return new Response(null, { status: deny.status, headers: responseHeaders });
207
198
  }
208
199
 
209
- const mod = (await resolution.file.load()) as Record<string, unknown>;
200
+ const mod = await loadModule(resolution.file);
210
201
  if (!mod.default) {
211
202
  responseHeaders.set('content-type', `${RSC_CONTENT_TYPE}; charset=utf-8`);
212
203
  return new Response(null, { status: deny.status, headers: responseHeaders });
@@ -215,22 +206,17 @@ export async function renderDenyPageAsRsc(
215
206
  const ErrorPageComponent = mod.default as (...args: unknown[]) => unknown;
216
207
  const h = createElement as (...args: unknown[]) => React.ReactElement;
217
208
 
218
- // Check shell opt-out
219
- const shellEnabled = mod.shell !== false;
220
-
221
209
  let element = h(ErrorPageComponent, {
222
210
  status: deny.status,
223
211
  dangerouslyPassData: deny.data,
224
212
  });
225
213
 
226
- // Wrap in layouts unless shell is explicitly disabled
227
- if (shellEnabled) {
228
- const resolvedSegments = new Set(segments.slice(0, resolution.segmentIndex + 1));
229
- const layoutsToWrap = layoutComponents.filter((lc) => resolvedSegments.has(lc.segment));
230
- for (let i = layoutsToWrap.length - 1; i >= 0; i--) {
231
- const { component } = layoutsToWrap[i];
232
- element = h(component, null, element);
233
- }
214
+ // Always wrap in layout shell.
215
+ const resolvedSegments = new Set(segments.slice(0, resolution.segmentIndex + 1));
216
+ const layoutsToWrap = layoutComponents.filter((lc) => resolvedSegments.has(lc.segment));
217
+ for (let i = layoutsToWrap.length - 1; i >= 0; i--) {
218
+ const { component } = layoutsToWrap[i];
219
+ element = h(component, null, element);
234
220
  }
235
221
 
236
222
  const rscStream = renderToReadableStream(element, {
@@ -272,7 +258,7 @@ async function renderDenyPageJson(
272
258
  // JSON status files are loaded as modules that export the JSON content.
273
259
  // The manifest's load() imports the .json file, which Vite handles as a
274
260
  // default export of the parsed JSON object.
275
- const mod = (await resolution.file.load()) as Record<string, unknown>;
261
+ const mod = await loadModule(resolution.file);
276
262
  const jsonContent = mod.default ?? mod;
277
263
 
278
264
  responseHeaders.set('content-type', 'application/json; charset=utf-8');
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Dev holding server — serves a loading page while Vite initializes.
3
+ *
4
+ * When `timber dev` (or `vite dev`) starts, Vite takes several seconds
5
+ * to initialize all plugins, scan routes, and boot the RSC environment.
6
+ * During this window, the port is unbound and browsers get
7
+ * ERR_CONNECTION_REFUSED.
8
+ *
9
+ * This module creates a lightweight HTTP server that binds the port
10
+ * immediately and serves a branded holding page with auto-refresh.
11
+ * Once Vite is ready, the holding server is closed and Vite's server
12
+ * takes over the port.
13
+ *
14
+ * The holding server is started in rootSync's config() hook (the
15
+ * earliest Vite plugin lifecycle point where we know the port) and
16
+ * closed in timber-dev-server's configureServer() hook (the last
17
+ * plugin, right before Vite calls server.listen()).
18
+ *
19
+ * Browser requests (Accept: text/html) get the HTML holding page.
20
+ * API requests (Accept: application/json) get a 503 JSON response.
21
+ * All responses include Retry-After: 1.
22
+ *
23
+ * See design/21-dev-server.md, TIM-665.
24
+ */
25
+
26
+ import http from 'node:http';
27
+
28
+ // ─── Types ────────────────────────────────────────────────────────────────
29
+
30
+ export interface HoldingServer {
31
+ /**
32
+ * Start listening on the given port.
33
+ * Returns the actual bound port (useful when port is 0 for OS assignment).
34
+ */
35
+ listen(port: number): Promise<number>;
36
+
37
+ /** Gracefully close the server and stop accepting connections. */
38
+ close(): Promise<void>;
39
+ }
40
+
41
+ // ─── Holding Page HTML ────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * Minimal self-contained HTML holding page.
45
+ *
46
+ * Matches the timber.js docs site theme:
47
+ * - Light mode: warm stone/grain background, timber/bark text
48
+ * - Dark mode: stone-900 background, stone-200 text
49
+ * - 🪵 timber.js branding
50
+ *
51
+ * Uses meta-refresh (1s) for auto-reload — works without JavaScript.
52
+ * Inline CSS only, no external dependencies.
53
+ */
54
+ const HOLDING_PAGE_HTML = [
55
+ '<!DOCTYPE html>',
56
+ '<html lang="en">',
57
+ '<head>',
58
+ ' <meta charset="utf-8">',
59
+ ' <meta name="viewport" content="width=device-width, initial-scale=1">',
60
+ ' <meta http-equiv="refresh" content="2">',
61
+ ' <title>timber — starting...</title>',
62
+ ' <style>',
63
+ ' *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }',
64
+ ' body {',
65
+ ' font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;',
66
+ ' background: #fafaf9;',
67
+ ' color: #44403c;',
68
+ ' display: flex;',
69
+ ' align-items: center;',
70
+ ' justify-content: center;',
71
+ ' min-height: 100vh;',
72
+ ' -webkit-font-smoothing: antialiased;',
73
+ ' }',
74
+ ' @media (prefers-color-scheme: dark) {',
75
+ ' body { background: #1c1917; color: #e7e5e4; }',
76
+ ' .message { color: #a8a29e; }',
77
+ ' .spinner { border-color: #57534e; border-top-color: #a1887f; }',
78
+ ' .logo { color: #e7e5e4; }',
79
+ ' }',
80
+ ' .container { text-align: center; padding: 2rem; }',
81
+ ' .logo {',
82
+ ' font-size: 1.5rem;',
83
+ ' font-weight: 700;',
84
+ ' letter-spacing: -0.02em;',
85
+ ' color: #5c3d2e;',
86
+ ' margin-bottom: 1.5rem;',
87
+ ' }',
88
+ ' .message {',
89
+ ' font-size: 0.95rem;',
90
+ ' color: #78716c;',
91
+ ' margin-bottom: 2rem;',
92
+ ' }',
93
+ ' .spinner {',
94
+ ' width: 24px;',
95
+ ' height: 24px;',
96
+ ' border: 2.5px solid #d7ccc8;',
97
+ ' border-top-color: #6d4c41;',
98
+ ' border-radius: 50%;',
99
+ ' animation: spin 0.8s linear infinite;',
100
+ ' margin: 0 auto;',
101
+ ' }',
102
+ ' @keyframes spin { to { transform: rotate(360deg); } }',
103
+ ' </style>',
104
+ '</head>',
105
+ '<body>',
106
+ ' <div class="container">',
107
+ ' <div class="logo">\u{1FAB5} timber.js</div>',
108
+ ' <p class="message">Dev server starting&hellip;</p>',
109
+ ' <div class="spinner"></div>',
110
+ ' </div>',
111
+ '</body>',
112
+ '</html>',
113
+ ].join('\n');
114
+
115
+ // ─── Factory ──────────────────────────────────────────────────────────────
116
+
117
+ /**
118
+ * Create a holding HTTP server that serves a loading page during startup.
119
+ *
120
+ * Usage (inside Vite plugin):
121
+ * ```ts
122
+ * // In config() hook — earliest point where port is known
123
+ * const holding = createHoldingServer();
124
+ * holding.listen(config.server?.port ?? 5173);
125
+ *
126
+ * // In last plugin's configureServer() — wrap listen for seamless handoff
127
+ * const originalListen = server.listen.bind(server);
128
+ * server.listen = async (...args) => {
129
+ * await holding.close();
130
+ * return originalListen(...args);
131
+ * };
132
+ * ```
133
+ */
134
+ export function createHoldingServer(): HoldingServer {
135
+ const server = http.createServer((req, res) => {
136
+ const accept = req.headers.accept ?? '';
137
+
138
+ // API requests: JSON 503
139
+ if (accept.includes('application/json') && !accept.includes('text/html')) {
140
+ res.writeHead(503, {
141
+ 'Content-Type': 'application/json; charset=utf-8',
142
+ 'Retry-After': '1',
143
+ 'Cache-Control': 'no-store',
144
+ });
145
+ res.end(
146
+ JSON.stringify({
147
+ error: 'Service Unavailable',
148
+ message: 'timber dev server is starting — please retry shortly',
149
+ })
150
+ );
151
+ return;
152
+ }
153
+
154
+ // Browser and other requests: HTML holding page
155
+ res.writeHead(503, {
156
+ 'Content-Type': 'text/html; charset=utf-8',
157
+ 'Retry-After': '1',
158
+ 'Cache-Control': 'no-store',
159
+ });
160
+ res.end(HOLDING_PAGE_HTML);
161
+ });
162
+
163
+ return {
164
+ listen(port: number): Promise<number> {
165
+ return new Promise((resolve, reject) => {
166
+ server.once('error', reject);
167
+ server.listen(port, () => {
168
+ server.removeListener('error', reject);
169
+ const addr = server.address();
170
+ const boundPort = typeof addr === 'object' && addr ? addr.port : port;
171
+ resolve(boundPort);
172
+ });
173
+ });
174
+ },
175
+
176
+ close(): Promise<void> {
177
+ return new Promise((resolve, reject) => {
178
+ server.close((err) => {
179
+ if (err) reject(err);
180
+ else resolve();
181
+ });
182
+ });
183
+ },
184
+ };
185
+ }
@@ -25,7 +25,6 @@ export const WarningId = {
25
25
  REDIRECT_IN_SUSPENSE: 'REDIRECT_IN_SUSPENSE',
26
26
  REDIRECT_IN_ACCESS: 'REDIRECT_IN_ACCESS',
27
27
  STATIC_REQUEST_API: 'STATIC_REQUEST_API',
28
- CACHE_REQUEST_PROPS: 'CACHE_REQUEST_PROPS',
29
28
  SLOW_SLOT_NO_SUSPENSE: 'SLOW_SLOT_NO_SUSPENSE',
30
29
  } as const;
31
30
 
@@ -111,7 +110,7 @@ export function warnSuspenseWrappingChildren(layoutFile: string): void {
111
110
  'warn',
112
111
  `Layout at ${layoutFile} wraps {children} in <Suspense>. ` +
113
112
  'This prevents child pages from setting HTTP status codes. ' +
114
- 'Use useNavigationPending() for loading states instead.'
113
+ 'Use usePendingNavigation() for loading states instead.'
115
114
  );
116
115
  }
117
116
 
@@ -179,7 +178,7 @@ export function warnRedirectInAccess(accessFile: string, line?: number): void {
179
178
  }
180
179
 
181
180
  /**
182
- * Warn when cookies() or headers() is called during a static build.
181
+ * Warn when getCookies() or getHeaders() is called during a static build.
183
182
  *
184
183
  * In output: 'static' mode, there is no per-request context — these APIs
185
184
  * read build-time values only. This is almost always a mistake.
@@ -197,33 +196,8 @@ export function warnStaticRequestApi(api: 'cookies' | 'headers', file: string):
197
196
  );
198
197
  }
199
198
 
200
- /**
201
- * Warn when a "use cache" component receives request-specific props.
202
- *
203
- * Cached components should not depend on per-request data — a userId or
204
- * sessionId in the props means the cache will either be ineffective
205
- * (key per user) or dangerous (serve one user's data to another).
206
- *
207
- * @param componentName - Name of the cached component
208
- * @param propName - Name of the suspicious prop
209
- * @param file - Relative path to the component file
210
- * @param line - Line number
211
- */
212
- export function warnCacheRequestProps(
213
- componentName: string,
214
- propName: string,
215
- file: string,
216
- line?: number
217
- ): void {
218
- const location = line ? `${file}:${line}` : file;
219
- emitOnce(
220
- WarningId.CACHE_REQUEST_PROPS,
221
- `${componentName}:${propName}:${location}`,
222
- 'warn',
223
- `Cached component ${componentName} receives prop "${propName}" which appears request-specific. ` +
224
- 'Cached components should not depend on per-request data.'
225
- );
226
- }
199
+ // NOTE: warnCacheRequestProps removed — 'use cache' directive is a future feature.
200
+ // See design/06-caching.md.
227
201
 
228
202
  /**
229
203
  * Warn when a parallel slot resolves slowly without a <Suspense> wrapper.
@@ -245,25 +219,6 @@ export function warnSlowSlotWithoutSuspense(slotName: string, durationMs: number
245
219
  );
246
220
  }
247
221
 
248
- // ─── Legacy aliases ─────────────────────────────────────────────────────────
249
-
250
- /** @deprecated Use warnStaticRequestApi instead */
251
- export const warnDynamicApiInStaticBuild = warnStaticRequestApi;
252
-
253
- /** @deprecated Use warnRedirectInAccess instead */
254
- export function warnRedirectInSlotAccess(slotName: string): void {
255
- warnRedirectInAccess(`${slotName}/access.ts`);
256
- }
257
-
258
- /** @deprecated Use warnDenyInSuspense / warnRedirectInSuspense instead */
259
- export function warnDenyAfterFlush(signal: 'deny' | 'redirect'): void {
260
- if (signal === 'deny') {
261
- warnDenyInSuspense('unknown');
262
- } else {
263
- warnRedirectInSuspense('unknown');
264
- }
265
- }
266
-
267
222
  // ─── Testing ────────────────────────────────────────────────────────────────
268
223
 
269
224
  /**
@@ -58,15 +58,31 @@ export interface EarlyHint {
58
58
  /**
59
59
  * Format a single EarlyHint as a Link header value.
60
60
  *
61
+ * Attribute order: `as` before `rel` to match Cloudflare CDN's cached
62
+ * Early Hints format. Cloudflare caches Link headers from 200 responses
63
+ * and re-emits them as 103 Early Hints on subsequent requests. If our
64
+ * attribute order differs from Cloudflare's cached copy, the browser
65
+ * sees two preload headers for the same URL (different attribute order)
66
+ * and warns "Preload was ignored." Matching the order ensures the
67
+ * browser deduplicates them correctly.
68
+ *
61
69
  * Examples:
62
- * `</styles/root.css>; rel=preload; as=style`
63
- * `</fonts/inter.woff2>; rel=preload; as=font; crossorigin=anonymous`
70
+ * `</styles/root.css>; as=style; rel=preload`
71
+ * `</fonts/inter.woff2>; as=font; rel=preload; crossorigin=anonymous`
64
72
  * `</_timber/client.js>; rel=modulepreload`
65
73
  * `<https://fonts.googleapis.com>; rel=preconnect`
66
74
  */
67
75
  export function formatLinkHeader(hint: EarlyHint): string {
76
+ // For preload hints, emit `as` before `rel` to match Cloudflare's
77
+ // cached header format and avoid duplicate preload warnings.
78
+ if (hint.as !== undefined) {
79
+ let value = `<${hint.href}>; as=${hint.as}; rel=${hint.rel}`;
80
+ if (hint.crossOrigin !== undefined) value += `; crossorigin=${hint.crossOrigin}`;
81
+ if (hint.fetchPriority !== undefined) value += `; fetchpriority=${hint.fetchPriority}`;
82
+ return value;
83
+ }
84
+ // For modulepreload / preconnect (no `as`), emit rel first.
68
85
  let value = `<${hint.href}>; rel=${hint.rel}`;
69
- if (hint.as !== undefined) value += `; as=${hint.as}`;
70
86
  if (hint.crossOrigin !== undefined) value += `; crossorigin=${hint.crossOrigin}`;
71
87
  if (hint.fetchPriority !== undefined) value += `; fetchpriority=${hint.fetchPriority}`;
72
88
  return value;
@@ -84,8 +100,8 @@ export interface EarlyHintOptions {
84
100
  * Collect all Link header strings for a matched route's segment chain.
85
101
  *
86
102
  * Walks the build manifest to emit hints for:
87
- * - CSS stylesheets (rel=preload; as=style)
88
- * - Font assets (rel=preload; as=font; crossorigin)
103
+ * - CSS stylesheets (as=style; rel=preload)
104
+ * - Font assets (as=font; rel=preload; crossorigin)
89
105
  * - JS modulepreload hints (rel=modulepreload) — unless skipJs is set
90
106
  *
91
107
  * Also emits global CSS from the `_global` manifest key. Route files
@@ -94,7 +110,7 @@ export interface EarlyHintOptions {
94
110
  * key contains all CSS assets from the client build — fine for early
95
111
  * hints since they're just prefetch signals.
96
112
  *
97
- * Returns formatted Link header strings, deduplicated, root → leaf order.
113
+ * Returns formatted Link header strings, deduplicated by URL, root → leaf order.
98
114
  * Returns an empty array in dev mode (manifest is empty).
99
115
  */
100
116
  export function collectEarlyHintHeaders(
@@ -103,30 +119,35 @@ export function collectEarlyHintHeaders(
103
119
  options?: EarlyHintOptions
104
120
  ): string[] {
105
121
  const result: string[] = [];
106
- const seen = new Set<string>();
122
+ // Dedup by URL (href), not by full formatted header string.
123
+ // Different code paths can produce the same URL with different attribute
124
+ // ordering, which would bypass a full-string dedup and produce duplicate
125
+ // Link headers that trigger browser "preload was ignored" warnings.
126
+ const seenUrls = new Set<string>();
107
127
 
108
- const add = (header: string) => {
109
- if (!seen.has(header)) {
110
- seen.add(header);
128
+ const add = (url: string, header: string) => {
129
+ if (!seenUrls.has(url)) {
130
+ seenUrls.add(url);
111
131
  result.push(header);
112
132
  }
113
133
  };
114
134
 
115
- // Per-route CSS — rel=preload; as=style
135
+ // Per-route CSS — as=style; rel=preload
116
136
  for (const url of collectRouteCss(segments, manifest)) {
117
- add(formatLinkHeader({ href: url, rel: 'preload', as: 'style' }));
137
+ add(url, formatLinkHeader({ href: url, rel: 'preload', as: 'style' }));
118
138
  }
119
139
 
120
140
  // Global CSS — all CSS assets from the client bundle.
121
141
  // Covers CSS that the RSC plugin injects via data-rsc-css-href,
122
142
  // which isn't keyed to route segments in our manifest.
123
143
  for (const url of manifest.css['_global'] ?? []) {
124
- add(formatLinkHeader({ href: url, rel: 'preload', as: 'style' }));
144
+ add(url, formatLinkHeader({ href: url, rel: 'preload', as: 'style' }));
125
145
  }
126
146
 
127
- // Fonts — rel=preload; as=font; crossorigin (crossorigin required per spec)
147
+ // Fonts — as=font; rel=preload; crossorigin (crossorigin required per spec)
128
148
  for (const font of collectRouteFonts(segments, manifest)) {
129
149
  add(
150
+ font.href,
130
151
  formatLinkHeader({ href: font.href, rel: 'preload', as: 'font', crossOrigin: 'anonymous' })
131
152
  );
132
153
  }
@@ -134,7 +155,7 @@ export function collectEarlyHintHeaders(
134
155
  // JS chunks — rel=modulepreload (skip when client JS is disabled)
135
156
  if (!options?.skipJs) {
136
157
  for (const url of collectRouteModulepreloads(segments, manifest)) {
137
- add(formatLinkHeader({ href: url, rel: 'modulepreload' }));
158
+ add(url, formatLinkHeader({ href: url, rel: 'modulepreload' }));
138
159
  }
139
160
  }
140
161
 
@@ -5,8 +5,23 @@
5
5
  * See design/10-error-handling.md.
6
6
  */
7
7
 
8
- import { TimberErrorBoundary } from '#/client/error-boundary.js';
8
+ import { TimberErrorBoundary } from '../client/error-boundary.js';
9
9
  import type { ManifestSegmentNode } from './route-matcher.js';
10
+ import { loadModule } from './safe-load.js';
11
+
12
+ /** MDX/markdown extensions — server components that cannot be passed as function props. */
13
+ const MDX_EXTENSIONS = new Set(['.mdx', '.md']);
14
+
15
+ /**
16
+ * Check if a manifest file path ends with an MDX/markdown extension.
17
+ * MDX components are server components and cannot cross the RSC→client
18
+ * boundary as function props to TimberErrorBoundary.
19
+ */
20
+ function isMdxFilePath(filePath: string): boolean {
21
+ const dotIndex = filePath.lastIndexOf('.');
22
+ if (dotIndex === -1) return false;
23
+ return MDX_EXTENSIONS.has(filePath.slice(dotIndex));
24
+ }
10
25
 
11
26
  /**
12
27
  * Wrap an element in error boundaries defined by a route segment.
@@ -15,11 +30,17 @@ import type { ManifestSegmentNode } from './route-matcher.js';
15
30
  * 1. Specific status files (e.g., 404.tsx, 500.tsx) — highest priority at runtime
16
31
  * 2. Category catch-alls (4xx.tsx, 5xx.tsx)
17
32
  * 3. error.tsx — catches anything not matched by status files
33
+ *
34
+ * MDX status files are server components and cannot be passed as function
35
+ * props to TimberErrorBoundary (a 'use client' component). Instead, they
36
+ * are pre-rendered as elements and passed as fallbackElement. See TIM-503.
18
37
  */
19
38
  export async function wrapSegmentWithErrorBoundaries(
20
39
  segment: ManifestSegmentNode,
21
40
  element: React.ReactElement,
22
- h: (...args: unknown[]) => React.ReactElement
41
+ h: (...args: unknown[]) => React.ReactElement,
42
+ /** When true, skip 4xx error boundaries — deny catching handles them in-tree. See TIM-666. */
43
+ skipDenyBoundaries = false
23
44
  ): Promise<React.ReactElement> {
24
45
  // Specific status files (innermost — highest priority at runtime)
25
46
  if (segment.statusFiles) {
@@ -27,13 +48,27 @@ export async function wrapSegmentWithErrorBoundaries(
27
48
  if (key !== '4xx' && key !== '5xx') {
28
49
  const status = parseInt(key, 10);
29
50
  if (!isNaN(status)) {
30
- const mod = (await file.load()) as Record<string, unknown>;
31
- if (mod.default) {
32
- element = h(TimberErrorBoundary, {
33
- fallbackComponent: mod.default,
34
- status,
35
- children: element,
36
- });
51
+ // Skip 4xx boundaries when deny catching is active — the deny
52
+ // page is rendered by AccessGate/PageDenyBoundary instead.
53
+ if (skipDenyBoundaries && status >= 400 && status <= 499) continue;
54
+ // .catch: error boundary construction must not fail if the
55
+ // error page module has a syntax error — skip this boundary.
56
+ const mod = await loadModule(file).catch(() => null);
57
+ if (mod?.default) {
58
+ if (isMdxFilePath(file.filePath)) {
59
+ // MDX: pre-render as element (server component can't be a function prop)
60
+ element = h(TimberErrorBoundary, {
61
+ fallbackElement: h(mod.default as never, { status }),
62
+ status,
63
+ children: element,
64
+ });
65
+ } else {
66
+ element = h(TimberErrorBoundary, {
67
+ fallbackComponent: mod.default,
68
+ status,
69
+ children: element,
70
+ });
71
+ }
37
72
  }
38
73
  }
39
74
  }
@@ -41,14 +76,24 @@ export async function wrapSegmentWithErrorBoundaries(
41
76
 
42
77
  // Category catch-alls (4xx.tsx, 5xx.tsx)
43
78
  for (const [key, file] of Object.entries(segment.statusFiles)) {
79
+ if (skipDenyBoundaries && key === '4xx') continue;
44
80
  if (key === '4xx' || key === '5xx') {
45
- const mod = (await file.load()) as Record<string, unknown>;
46
- if (mod.default) {
47
- element = h(TimberErrorBoundary, {
48
- fallbackComponent: mod.default,
49
- status: key === '4xx' ? 400 : 500,
50
- children: element,
51
- });
81
+ const mod = await loadModule(file).catch(() => null);
82
+ if (mod?.default) {
83
+ const categoryStatus = key === '4xx' ? 400 : 500;
84
+ if (isMdxFilePath(file.filePath)) {
85
+ element = h(TimberErrorBoundary, {
86
+ fallbackElement: h(mod.default as never, {}),
87
+ status: categoryStatus,
88
+ children: element,
89
+ });
90
+ } else {
91
+ element = h(TimberErrorBoundary, {
92
+ fallbackComponent: mod.default,
93
+ status: categoryStatus,
94
+ children: element,
95
+ });
96
+ }
52
97
  }
53
98
  }
54
99
  }
@@ -56,12 +101,19 @@ export async function wrapSegmentWithErrorBoundaries(
56
101
 
57
102
  // error.tsx (outermost — catches anything not matched by status files)
58
103
  if (segment.error) {
59
- const mod = (await segment.error.load()) as Record<string, unknown>;
60
- if (mod.default) {
61
- element = h(TimberErrorBoundary, {
62
- fallbackComponent: mod.default,
63
- children: element,
64
- });
104
+ const mod = await loadModule(segment.error).catch(() => null);
105
+ if (mod?.default) {
106
+ if (isMdxFilePath(segment.error.filePath)) {
107
+ element = h(TimberErrorBoundary, {
108
+ fallbackElement: h(mod.default as never, {}),
109
+ children: element,
110
+ });
111
+ } else {
112
+ element = h(TimberErrorBoundary, {
113
+ fallbackComponent: mod.default,
114
+ children: element,
115
+ });
116
+ }
65
117
  }
66
118
  }
67
119