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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (610) hide show
  1. package/dist/_chunks/actions-DLnUaR65.js +421 -0
  2. package/dist/_chunks/actions-DLnUaR65.js.map +1 -0
  3. package/dist/_chunks/{als-registry-B7DbZ2hS.js → als-registry-HS0LGUl2.js} +1 -1
  4. package/dist/_chunks/als-registry-HS0LGUl2.js.map +1 -0
  5. package/dist/_chunks/chunk-BYIpzuS7.js +39 -0
  6. package/dist/_chunks/{debug-gwlJkDuf.js → debug-ECi_61pb.js} +2 -2
  7. package/dist/_chunks/debug-ECi_61pb.js.map +1 -0
  8. package/dist/_chunks/define-C77ScO0m.js +106 -0
  9. package/dist/_chunks/define-C77ScO0m.js.map +1 -0
  10. package/dist/_chunks/define-Itxvcd7F.js +199 -0
  11. package/dist/_chunks/define-Itxvcd7F.js.map +1 -0
  12. package/dist/_chunks/define-cookie-BowvzoP0.js +94 -0
  13. package/dist/_chunks/define-cookie-BowvzoP0.js.map +1 -0
  14. package/dist/_chunks/{format-DviM89f0.js → dev-warnings-DpGRGoDi.js} +5 -44
  15. package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +1 -0
  16. package/dist/_chunks/format-CYBGxKtc.js +14 -0
  17. package/dist/_chunks/format-CYBGxKtc.js.map +1 -0
  18. package/dist/_chunks/{interception-BOoWmLUA.js → interception-DRlhJWbu.js} +219 -97
  19. package/dist/_chunks/interception-DRlhJWbu.js.map +1 -0
  20. package/dist/_chunks/merge-search-params-Cm_KIWDX.js +41 -0
  21. package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +1 -0
  22. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js → metadata-routes-DS3eKNmf.js} +1 -1
  23. package/dist/_chunks/{metadata-routes-Cjmvi3rQ.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
  24. package/dist/_chunks/request-context-CK5tZqIP.js +478 -0
  25. package/dist/_chunks/request-context-CK5tZqIP.js.map +1 -0
  26. package/dist/_chunks/schema-bridge-C3xl_vfb.js +86 -0
  27. package/dist/_chunks/schema-bridge-C3xl_vfb.js.map +1 -0
  28. package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
  29. package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
  30. package/dist/_chunks/segment-context-fHFLF1PE.js +34 -0
  31. package/dist/_chunks/segment-context-fHFLF1PE.js.map +1 -0
  32. package/dist/_chunks/{ssr-data-MjmprTmO.js → ssr-data-DzuI0bIV.js} +1 -1
  33. package/dist/_chunks/{ssr-data-MjmprTmO.js.map → ssr-data-DzuI0bIV.js.map} +1 -1
  34. package/dist/_chunks/stale-reload-BX5gL1r-.js +64 -0
  35. package/dist/_chunks/stale-reload-BX5gL1r-.js.map +1 -0
  36. package/dist/_chunks/{tracing-CemImE6h.js → tracing-CCYbKn5n.js} +60 -9
  37. package/dist/_chunks/tracing-CCYbKn5n.js.map +1 -0
  38. package/dist/_chunks/use-params-Br9YSUFV.js +295 -0
  39. package/dist/_chunks/use-params-Br9YSUFV.js.map +1 -0
  40. package/dist/_chunks/{use-query-states-D5KaffOK.js → use-query-states-BiV5GJgm.js} +7 -4
  41. package/dist/_chunks/use-query-states-BiV5GJgm.js.map +1 -0
  42. package/dist/adapters/cloudflare-dev.d.ts +109 -0
  43. package/dist/adapters/cloudflare-dev.d.ts.map +1 -0
  44. package/dist/adapters/cloudflare-dev.js +73 -0
  45. package/dist/adapters/cloudflare-dev.js.map +1 -0
  46. package/dist/adapters/cloudflare-kv-cache.d.ts +64 -0
  47. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -0
  48. package/dist/adapters/cloudflare-kv-cache.js +95 -0
  49. package/dist/adapters/cloudflare-kv-cache.js.map +1 -0
  50. package/dist/adapters/cloudflare.d.ts +148 -12
  51. package/dist/adapters/cloudflare.d.ts.map +1 -1
  52. package/dist/adapters/cloudflare.js +135 -11
  53. package/dist/adapters/cloudflare.js.map +1 -1
  54. package/dist/adapters/compress-module.d.ts.map +1 -1
  55. package/dist/adapters/nitro.d.ts +17 -1
  56. package/dist/adapters/nitro.d.ts.map +1 -1
  57. package/dist/adapters/nitro.js +56 -13
  58. package/dist/adapters/nitro.js.map +1 -1
  59. package/dist/cache/cache-api.d.ts +24 -0
  60. package/dist/cache/cache-api.d.ts.map +1 -0
  61. package/dist/cache/handler-store.d.ts +31 -0
  62. package/dist/cache/handler-store.d.ts.map +1 -0
  63. package/dist/cache/index.d.ts +23 -7
  64. package/dist/cache/index.d.ts.map +1 -1
  65. package/dist/cache/index.js +142 -80
  66. package/dist/cache/index.js.map +1 -1
  67. package/dist/cache/singleflight.d.ts +18 -1
  68. package/dist/cache/singleflight.d.ts.map +1 -1
  69. package/dist/cache/sizeof.d.ts +22 -0
  70. package/dist/cache/sizeof.d.ts.map +1 -0
  71. package/dist/cache/timber-cache.d.ts +1 -1
  72. package/dist/cache/timber-cache.d.ts.map +1 -1
  73. package/dist/cli.d.ts +6 -1
  74. package/dist/cli.d.ts.map +1 -1
  75. package/dist/cli.js +8 -3
  76. package/dist/cli.js.map +1 -1
  77. package/dist/client/browser-dev.d.ts +27 -1
  78. package/dist/client/browser-dev.d.ts.map +1 -1
  79. package/dist/client/browser-entry/action-dispatch.d.ts +17 -0
  80. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -0
  81. package/dist/client/browser-entry/hmr.d.ts +21 -0
  82. package/dist/client/browser-entry/hmr.d.ts.map +1 -0
  83. package/dist/client/browser-entry/hydrate.d.ts +46 -0
  84. package/dist/client/browser-entry/hydrate.d.ts.map +1 -0
  85. package/dist/client/browser-entry/index.d.ts +30 -0
  86. package/dist/client/browser-entry/index.d.ts.map +1 -0
  87. package/dist/client/browser-entry/post-hydration.d.ts +26 -0
  88. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -0
  89. package/dist/client/browser-entry/router-init.d.ts +23 -0
  90. package/dist/client/browser-entry/router-init.d.ts.map +1 -0
  91. package/dist/client/browser-entry/rsc-stream.d.ts +24 -0
  92. package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -0
  93. package/dist/client/browser-entry/scroll.d.ts +19 -0
  94. package/dist/client/browser-entry/scroll.d.ts.map +1 -0
  95. package/dist/client/error-boundary.d.ts +12 -5
  96. package/dist/client/error-boundary.d.ts.map +1 -1
  97. package/dist/client/error-boundary.js +10 -4
  98. package/dist/client/error-boundary.js.map +1 -1
  99. package/dist/client/error-reconstituter.d.ts +54 -0
  100. package/dist/client/error-reconstituter.d.ts.map +1 -0
  101. package/dist/client/form.d.ts +6 -3
  102. package/dist/client/form.d.ts.map +1 -1
  103. package/dist/client/history.d.ts +19 -4
  104. package/dist/client/history.d.ts.map +1 -1
  105. package/dist/client/index.d.ts +9 -21
  106. package/dist/client/index.d.ts.map +1 -1
  107. package/dist/client/index.js +229 -1018
  108. package/dist/client/index.js.map +1 -1
  109. package/dist/client/internal.d.ts +18 -0
  110. package/dist/client/internal.d.ts.map +1 -0
  111. package/dist/client/internal.js +890 -0
  112. package/dist/client/internal.js.map +1 -0
  113. package/dist/client/link-pending-store.d.ts +63 -0
  114. package/dist/client/link-pending-store.d.ts.map +1 -0
  115. package/dist/client/link.d.ts +62 -55
  116. package/dist/client/link.d.ts.map +1 -1
  117. package/dist/client/nav-link-store.d.ts +36 -0
  118. package/dist/client/nav-link-store.d.ts.map +1 -0
  119. package/dist/client/navigation-api-types.d.ts +90 -0
  120. package/dist/client/navigation-api-types.d.ts.map +1 -0
  121. package/dist/client/navigation-api.d.ts +115 -0
  122. package/dist/client/navigation-api.d.ts.map +1 -0
  123. package/dist/client/navigation-context.d.ts +13 -2
  124. package/dist/client/navigation-context.d.ts.map +1 -1
  125. package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +42 -8
  126. package/dist/client/navigation-root.d.ts.map +1 -0
  127. package/dist/client/nuqs-adapter.d.ts.map +1 -1
  128. package/dist/client/router-ref.d.ts +1 -1
  129. package/dist/client/router.d.ts +70 -4
  130. package/dist/client/router.d.ts.map +1 -1
  131. package/dist/client/rsc-fetch.d.ts +38 -3
  132. package/dist/client/rsc-fetch.d.ts.map +1 -1
  133. package/dist/client/segment-cache.d.ts +1 -1
  134. package/dist/client/segment-cache.d.ts.map +1 -1
  135. package/dist/client/segment-outlet.d.ts +63 -0
  136. package/dist/client/segment-outlet.d.ts.map +1 -0
  137. package/dist/client/ssr-data.d.ts +13 -4
  138. package/dist/client/ssr-data.d.ts.map +1 -1
  139. package/dist/client/stale-reload.d.ts +15 -0
  140. package/dist/client/stale-reload.d.ts.map +1 -1
  141. package/dist/client/top-loader.d.ts +5 -5
  142. package/dist/client/top-loader.d.ts.map +1 -1
  143. package/dist/client/use-link-status.d.ts +5 -5
  144. package/dist/client/use-link-status.d.ts.map +1 -1
  145. package/dist/client/use-params.d.ts +6 -4
  146. package/dist/client/use-params.d.ts.map +1 -1
  147. package/dist/client/{use-navigation-pending.d.ts → use-pending-navigation.d.ts} +4 -4
  148. package/dist/client/use-pending-navigation.d.ts.map +1 -0
  149. package/dist/client/use-query-states.d.ts +1 -1
  150. package/dist/client/use-query-states.d.ts.map +1 -1
  151. package/dist/client/use-router.d.ts +1 -1
  152. package/dist/codec.d.ts +33 -0
  153. package/dist/codec.d.ts.map +1 -0
  154. package/dist/codec.js +2 -0
  155. package/dist/config-types.d.ts +266 -0
  156. package/dist/config-types.d.ts.map +1 -0
  157. package/dist/config-validation.d.ts +51 -0
  158. package/dist/config-validation.d.ts.map +1 -0
  159. package/dist/content/index.d.ts +1 -10
  160. package/dist/content/index.d.ts.map +1 -1
  161. package/dist/content/index.js +0 -2
  162. package/dist/cookies/define-cookie.d.ts +35 -14
  163. package/dist/cookies/define-cookie.d.ts.map +1 -1
  164. package/dist/cookies/index.js +1 -83
  165. package/dist/fonts/bundle.d.ts +48 -0
  166. package/dist/fonts/bundle.d.ts.map +1 -0
  167. package/dist/fonts/css.d.ts +1 -0
  168. package/dist/fonts/css.d.ts.map +1 -1
  169. package/dist/fonts/dev-middleware.d.ts +22 -0
  170. package/dist/fonts/dev-middleware.d.ts.map +1 -0
  171. package/dist/fonts/pipeline.d.ts +138 -0
  172. package/dist/fonts/pipeline.d.ts.map +1 -0
  173. package/dist/fonts/transform.d.ts +72 -0
  174. package/dist/fonts/transform.d.ts.map +1 -0
  175. package/dist/fonts/types.d.ts +45 -1
  176. package/dist/fonts/types.d.ts.map +1 -1
  177. package/dist/fonts/virtual-modules.d.ts +59 -0
  178. package/dist/fonts/virtual-modules.d.ts.map +1 -0
  179. package/dist/index.d.ts +45 -190
  180. package/dist/index.d.ts.map +1 -1
  181. package/dist/index.js +4294 -2453
  182. package/dist/index.js.map +1 -1
  183. package/dist/plugin-context.d.ts +107 -0
  184. package/dist/plugin-context.d.ts.map +1 -0
  185. package/dist/plugins/adapter-build.d.ts +1 -1
  186. package/dist/plugins/adapter-build.d.ts.map +1 -1
  187. package/dist/plugins/build-manifest.d.ts +2 -2
  188. package/dist/plugins/build-manifest.d.ts.map +1 -1
  189. package/dist/plugins/build-report.d.ts +3 -3
  190. package/dist/plugins/build-report.d.ts.map +1 -1
  191. package/dist/plugins/client-chunks.d.ts +32 -0
  192. package/dist/plugins/client-chunks.d.ts.map +1 -0
  193. package/dist/plugins/content.d.ts +1 -1
  194. package/dist/plugins/content.d.ts.map +1 -1
  195. package/dist/plugins/dev-404-page.d.ts +56 -0
  196. package/dist/plugins/dev-404-page.d.ts.map +1 -0
  197. package/dist/plugins/dev-browser-logs.d.ts +84 -0
  198. package/dist/plugins/dev-browser-logs.d.ts.map +1 -0
  199. package/dist/plugins/dev-error-overlay.d.ts +49 -9
  200. package/dist/plugins/dev-error-overlay.d.ts.map +1 -1
  201. package/dist/plugins/dev-error-page.d.ts +58 -0
  202. package/dist/plugins/dev-error-page.d.ts.map +1 -0
  203. package/dist/plugins/dev-logs.d.ts +1 -1
  204. package/dist/plugins/dev-logs.d.ts.map +1 -1
  205. package/dist/plugins/dev-server.d.ts +1 -1
  206. package/dist/plugins/dev-server.d.ts.map +1 -1
  207. package/dist/plugins/dev-terminal-error.d.ts +28 -0
  208. package/dist/plugins/dev-terminal-error.d.ts.map +1 -0
  209. package/dist/plugins/entries.d.ts +1 -1
  210. package/dist/plugins/entries.d.ts.map +1 -1
  211. package/dist/plugins/fonts.d.ts +17 -73
  212. package/dist/plugins/fonts.d.ts.map +1 -1
  213. package/dist/plugins/mdx.d.ts +1 -1
  214. package/dist/plugins/mdx.d.ts.map +1 -1
  215. package/dist/plugins/routing.d.ts +1 -1
  216. package/dist/plugins/routing.d.ts.map +1 -1
  217. package/dist/plugins/server-bundle.d.ts.map +1 -1
  218. package/dist/plugins/shims.d.ts +6 -5
  219. package/dist/plugins/shims.d.ts.map +1 -1
  220. package/dist/plugins/static-build.d.ts +4 -4
  221. package/dist/plugins/static-build.d.ts.map +1 -1
  222. package/dist/routing/codegen.d.ts +2 -2
  223. package/dist/routing/codegen.d.ts.map +1 -1
  224. package/dist/routing/convention-lint.d.ts +41 -0
  225. package/dist/routing/convention-lint.d.ts.map +1 -0
  226. package/dist/routing/index.d.ts +2 -0
  227. package/dist/routing/index.d.ts.map +1 -1
  228. package/dist/routing/index.js +3 -2
  229. package/dist/routing/scanner.d.ts.map +1 -1
  230. package/dist/routing/segment-classify.d.ts +46 -0
  231. package/dist/routing/segment-classify.d.ts.map +1 -0
  232. package/dist/routing/status-file-lint.d.ts +2 -1
  233. package/dist/routing/status-file-lint.d.ts.map +1 -1
  234. package/dist/routing/types.d.ts +16 -4
  235. package/dist/routing/types.d.ts.map +1 -1
  236. package/dist/rsc-runtime/rsc.d.ts +1 -1
  237. package/dist/rsc-runtime/rsc.d.ts.map +1 -1
  238. package/dist/rsc-runtime/ssr.d.ts +12 -0
  239. package/dist/rsc-runtime/ssr.d.ts.map +1 -1
  240. package/dist/schema-bridge.d.ts +76 -0
  241. package/dist/schema-bridge.d.ts.map +1 -0
  242. package/dist/search-params/define.d.ts +139 -0
  243. package/dist/search-params/define.d.ts.map +1 -0
  244. package/dist/search-params/index.d.ts +4 -7
  245. package/dist/search-params/index.d.ts.map +1 -1
  246. package/dist/search-params/index.js +32 -441
  247. package/dist/search-params/index.js.map +1 -1
  248. package/dist/search-params/registry.d.ts +2 -2
  249. package/dist/search-params/registry.d.ts.map +1 -1
  250. package/dist/search-params/wrappers.d.ts +53 -0
  251. package/dist/search-params/wrappers.d.ts.map +1 -0
  252. package/dist/segment-params/define.d.ts +78 -0
  253. package/dist/segment-params/define.d.ts.map +1 -0
  254. package/dist/segment-params/index.d.ts +3 -0
  255. package/dist/segment-params/index.d.ts.map +1 -0
  256. package/dist/segment-params/index.js +2 -0
  257. package/dist/server/access-gate.d.ts +4 -0
  258. package/dist/server/access-gate.d.ts.map +1 -1
  259. package/dist/server/action-client.d.ts +41 -6
  260. package/dist/server/action-client.d.ts.map +1 -1
  261. package/dist/server/action-encryption.d.ts +76 -0
  262. package/dist/server/action-encryption.d.ts.map +1 -0
  263. package/dist/server/action-handler.d.ts +7 -0
  264. package/dist/server/action-handler.d.ts.map +1 -1
  265. package/dist/server/actions.d.ts +3 -6
  266. package/dist/server/actions.d.ts.map +1 -1
  267. package/dist/server/als-registry.d.ts +32 -4
  268. package/dist/server/als-registry.d.ts.map +1 -1
  269. package/dist/server/build-manifest.d.ts +2 -2
  270. package/dist/server/build-manifest.d.ts.map +1 -1
  271. package/dist/server/debug.d.ts +1 -1
  272. package/dist/server/default-logger.d.ts +22 -0
  273. package/dist/server/default-logger.d.ts.map +1 -0
  274. package/dist/server/deny-page-resolver.d.ts +52 -0
  275. package/dist/server/deny-page-resolver.d.ts.map +1 -0
  276. package/dist/server/deny-renderer.d.ts.map +1 -1
  277. package/dist/server/dev-holding-server.d.ts +52 -0
  278. package/dist/server/dev-holding-server.d.ts.map +1 -0
  279. package/dist/server/dev-source-map.d.ts +22 -0
  280. package/dist/server/dev-source-map.d.ts.map +1 -0
  281. package/dist/server/dev-warnings.d.ts +1 -21
  282. package/dist/server/dev-warnings.d.ts.map +1 -1
  283. package/dist/server/early-hints.d.ts +13 -5
  284. package/dist/server/early-hints.d.ts.map +1 -1
  285. package/dist/server/error-boundary-wrapper.d.ts +7 -1
  286. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  287. package/dist/server/fallback-error.d.ts +12 -7
  288. package/dist/server/fallback-error.d.ts.map +1 -1
  289. package/dist/server/flight-injection-state.d.ts +66 -0
  290. package/dist/server/flight-injection-state.d.ts.map +1 -0
  291. package/dist/server/flight-scripts.d.ts +42 -0
  292. package/dist/server/flight-scripts.d.ts.map +1 -0
  293. package/dist/server/flush.d.ts.map +1 -1
  294. package/dist/server/form-data.d.ts +29 -0
  295. package/dist/server/form-data.d.ts.map +1 -1
  296. package/dist/server/html-injectors.d.ts +51 -11
  297. package/dist/server/html-injectors.d.ts.map +1 -1
  298. package/dist/server/index.d.ts +5 -43
  299. package/dist/server/index.d.ts.map +1 -1
  300. package/dist/server/index.js +195 -2800
  301. package/dist/server/index.js.map +1 -1
  302. package/dist/server/internal.d.ts +46 -0
  303. package/dist/server/internal.d.ts.map +1 -0
  304. package/dist/server/internal.js +2900 -0
  305. package/dist/server/internal.js.map +1 -0
  306. package/dist/server/logger.d.ts +25 -7
  307. package/dist/server/logger.d.ts.map +1 -1
  308. package/dist/server/middleware-runner.d.ts +19 -4
  309. package/dist/server/middleware-runner.d.ts.map +1 -1
  310. package/dist/server/node-stream-transforms.d.ts +113 -0
  311. package/dist/server/node-stream-transforms.d.ts.map +1 -0
  312. package/dist/server/page-deny-boundary.d.ts +31 -0
  313. package/dist/server/page-deny-boundary.d.ts.map +1 -0
  314. package/dist/server/pipeline-interception.d.ts +1 -1
  315. package/dist/server/pipeline-interception.d.ts.map +1 -1
  316. package/dist/server/pipeline-metadata.d.ts +6 -0
  317. package/dist/server/pipeline-metadata.d.ts.map +1 -1
  318. package/dist/server/pipeline.d.ts +52 -10
  319. package/dist/server/pipeline.d.ts.map +1 -1
  320. package/dist/server/primitives.d.ts +69 -18
  321. package/dist/server/primitives.d.ts.map +1 -1
  322. package/dist/server/render-timeout.d.ts +51 -0
  323. package/dist/server/render-timeout.d.ts.map +1 -0
  324. package/dist/server/request-context.d.ts +112 -43
  325. package/dist/server/request-context.d.ts.map +1 -1
  326. package/dist/server/route-element-builder.d.ts +27 -1
  327. package/dist/server/route-element-builder.d.ts.map +1 -1
  328. package/dist/server/route-handler.d.ts.map +1 -1
  329. package/dist/server/route-matcher.d.ts +16 -2
  330. package/dist/server/route-matcher.d.ts.map +1 -1
  331. package/dist/server/rsc-entry/api-handler.d.ts +2 -2
  332. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  333. package/dist/server/rsc-entry/error-renderer.d.ts +26 -13
  334. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  335. package/dist/server/rsc-entry/helpers.d.ts +48 -5
  336. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  337. package/dist/server/rsc-entry/index.d.ts +20 -3
  338. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  339. package/dist/server/rsc-entry/rsc-payload.d.ts +3 -3
  340. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  341. package/dist/server/rsc-entry/rsc-stream.d.ts +14 -1
  342. package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
  343. package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
  344. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  345. package/dist/server/rsc-entry/ssr-renderer.d.ts +19 -4
  346. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  347. package/dist/server/safe-load.d.ts +46 -0
  348. package/dist/server/safe-load.d.ts.map +1 -0
  349. package/dist/server/sensitive-fields.d.ts +74 -0
  350. package/dist/server/sensitive-fields.d.ts.map +1 -0
  351. package/dist/server/sitemap-generator.d.ts +129 -0
  352. package/dist/server/sitemap-generator.d.ts.map +1 -0
  353. package/dist/server/sitemap-handler.d.ts +22 -0
  354. package/dist/server/sitemap-handler.d.ts.map +1 -0
  355. package/dist/server/slot-resolver.d.ts +1 -1
  356. package/dist/server/slot-resolver.d.ts.map +1 -1
  357. package/dist/server/ssr-entry.d.ts +23 -0
  358. package/dist/server/ssr-entry.d.ts.map +1 -1
  359. package/dist/server/ssr-render.d.ts +39 -21
  360. package/dist/server/ssr-render.d.ts.map +1 -1
  361. package/dist/server/ssr-wrappers.d.ts +50 -0
  362. package/dist/server/ssr-wrappers.d.ts.map +1 -0
  363. package/dist/server/status-code-resolver.d.ts +1 -1
  364. package/dist/server/status-code-resolver.d.ts.map +1 -1
  365. package/dist/server/stream-utils.d.ts +36 -0
  366. package/dist/server/stream-utils.d.ts.map +1 -0
  367. package/dist/server/tracing.d.ts +4 -4
  368. package/dist/server/tracing.d.ts.map +1 -1
  369. package/dist/server/tree-builder.d.ts +22 -19
  370. package/dist/server/tree-builder.d.ts.map +1 -1
  371. package/dist/server/types.d.ts +1 -4
  372. package/dist/server/types.d.ts.map +1 -1
  373. package/dist/server/version-skew.d.ts +61 -0
  374. package/dist/server/version-skew.d.ts.map +1 -0
  375. package/dist/shared/merge-search-params.d.ts +22 -0
  376. package/dist/shared/merge-search-params.d.ts.map +1 -0
  377. package/dist/shims/font-google.d.ts +1 -1
  378. package/dist/shims/font-google.d.ts.map +1 -1
  379. package/dist/shims/font-google.js +42 -0
  380. package/dist/shims/font-google.js.map +1 -0
  381. package/dist/shims/font-local.d.ts +26 -0
  382. package/dist/shims/font-local.d.ts.map +1 -0
  383. package/dist/shims/font-local.js +20 -0
  384. package/dist/shims/font-local.js.map +1 -0
  385. package/dist/shims/headers.d.ts +2 -1
  386. package/dist/shims/headers.d.ts.map +1 -1
  387. package/dist/shims/navigation-client.d.ts +1 -1
  388. package/dist/shims/navigation-client.d.ts.map +1 -1
  389. package/dist/shims/navigation.d.ts +3 -2
  390. package/dist/shims/navigation.d.ts.map +1 -1
  391. package/dist/utils/directive-parser.d.ts +5 -2
  392. package/dist/utils/directive-parser.d.ts.map +1 -1
  393. package/dist/utils/state-machine.d.ts +80 -0
  394. package/dist/utils/state-machine.d.ts.map +1 -0
  395. package/package.json +51 -16
  396. package/src/adapters/cloudflare-dev.ts +177 -0
  397. package/src/adapters/cloudflare-kv-cache.ts +142 -0
  398. package/src/adapters/cloudflare.ts +342 -28
  399. package/src/adapters/compress-module.ts +24 -4
  400. package/src/adapters/nitro.ts +52 -8
  401. package/src/adapters/wrangler.d.ts +7 -0
  402. package/src/cache/cache-api.ts +38 -0
  403. package/src/cache/handler-store.ts +68 -0
  404. package/src/cache/index.ts +81 -18
  405. package/src/cache/singleflight.ts +62 -4
  406. package/src/cache/sizeof.ts +31 -0
  407. package/src/cache/timber-cache.ts +24 -20
  408. package/src/cli.ts +16 -6
  409. package/src/client/browser-dev.ts +128 -1
  410. package/src/client/browser-entry/action-dispatch.ts +116 -0
  411. package/src/client/browser-entry/hmr.ts +81 -0
  412. package/src/client/browser-entry/hydrate.ts +145 -0
  413. package/src/client/browser-entry/index.ts +143 -0
  414. package/src/client/browser-entry/post-hydration.ts +119 -0
  415. package/src/client/browser-entry/router-init.ts +193 -0
  416. package/src/client/browser-entry/rsc-stream.ts +157 -0
  417. package/src/client/browser-entry/scroll.ts +27 -0
  418. package/src/client/error-boundary.tsx +48 -16
  419. package/src/client/error-reconstituter.tsx +65 -0
  420. package/src/client/form.tsx +14 -7
  421. package/src/client/history.ts +26 -4
  422. package/src/client/index.ts +65 -38
  423. package/src/client/internal.ts +57 -0
  424. package/src/client/link-pending-store.ts +111 -0
  425. package/src/client/link.tsx +342 -113
  426. package/src/client/nav-link-store.ts +47 -0
  427. package/src/client/navigation-api-types.ts +112 -0
  428. package/src/client/navigation-api.ts +332 -0
  429. package/src/client/navigation-context.ts +31 -6
  430. package/src/client/navigation-root.tsx +342 -0
  431. package/src/client/nuqs-adapter.tsx +16 -3
  432. package/src/client/router-ref.ts +1 -1
  433. package/src/client/router.ts +299 -72
  434. package/src/client/rsc-fetch.ts +97 -8
  435. package/src/client/segment-cache.ts +1 -1
  436. package/src/client/segment-outlet.tsx +86 -0
  437. package/src/client/ssr-data.ts +13 -5
  438. package/src/client/stale-reload.ts +72 -3
  439. package/src/client/top-loader.tsx +18 -6
  440. package/src/client/use-link-status.ts +7 -7
  441. package/src/client/use-params.ts +7 -5
  442. package/src/client/{use-navigation-pending.ts → use-pending-navigation.ts} +6 -6
  443. package/src/client/use-query-states.ts +9 -3
  444. package/src/client/use-router.ts +1 -1
  445. package/src/codec.ts +49 -0
  446. package/src/config-types.ts +264 -0
  447. package/src/config-validation.ts +303 -0
  448. package/src/content/index.ts +5 -13
  449. package/src/cookies/define-cookie.ts +78 -25
  450. package/src/cookies/index.ts +8 -0
  451. package/src/fonts/bundle.ts +142 -0
  452. package/src/fonts/css.ts +2 -1
  453. package/src/fonts/dev-middleware.ts +74 -0
  454. package/src/fonts/pipeline.ts +275 -0
  455. package/src/fonts/transform.ts +353 -0
  456. package/src/fonts/types.ts +50 -1
  457. package/src/fonts/virtual-modules.ts +159 -0
  458. package/src/index.ts +314 -355
  459. package/src/plugin-context.ts +240 -0
  460. package/src/plugins/adapter-build.ts +9 -3
  461. package/src/plugins/build-manifest.ts +13 -2
  462. package/src/plugins/build-report.ts +3 -3
  463. package/src/plugins/client-chunks.ts +65 -0
  464. package/src/plugins/content.ts +1 -1
  465. package/src/plugins/dev-404-page.ts +418 -0
  466. package/src/plugins/dev-browser-logs.ts +288 -0
  467. package/src/plugins/dev-error-overlay.ts +286 -42
  468. package/src/plugins/dev-error-page.ts +536 -0
  469. package/src/plugins/dev-logs.ts +1 -1
  470. package/src/plugins/dev-server.ts +146 -19
  471. package/src/plugins/dev-terminal-error.ts +217 -0
  472. package/src/plugins/entries.ts +111 -10
  473. package/src/plugins/fonts.ts +133 -638
  474. package/src/plugins/mdx.ts +1 -1
  475. package/src/plugins/routing.ts +213 -31
  476. package/src/plugins/server-action-exports.ts +1 -1
  477. package/src/plugins/server-bundle.ts +32 -1
  478. package/src/plugins/shims.ts +136 -35
  479. package/src/plugins/static-build.ts +17 -11
  480. package/src/routing/codegen.ts +273 -105
  481. package/src/routing/convention-lint.ts +356 -0
  482. package/src/routing/index.ts +2 -0
  483. package/src/routing/scanner.ts +93 -23
  484. package/src/routing/segment-classify.ts +89 -0
  485. package/src/routing/status-file-lint.ts +3 -2
  486. package/src/routing/types.ts +17 -4
  487. package/src/rsc-runtime/rsc.ts +2 -0
  488. package/src/rsc-runtime/ssr.ts +50 -0
  489. package/src/rsc-runtime/vendor-types.d.ts +7 -0
  490. package/src/{search-params/codecs.ts → schema-bridge.ts} +57 -20
  491. package/src/search-params/define.ts +482 -0
  492. package/src/search-params/index.ts +14 -20
  493. package/src/search-params/registry.ts +2 -2
  494. package/src/search-params/wrappers.ts +85 -0
  495. package/src/segment-params/define.ts +279 -0
  496. package/src/segment-params/index.ts +9 -0
  497. package/src/server/access-gate.tsx +70 -29
  498. package/src/server/action-client.ts +88 -15
  499. package/src/server/action-encryption.ts +144 -0
  500. package/src/server/action-handler.ts +53 -6
  501. package/src/server/actions.ts +10 -9
  502. package/src/server/als-registry.ts +34 -6
  503. package/src/server/build-manifest.ts +10 -4
  504. package/src/server/compress.ts +25 -7
  505. package/src/server/debug.ts +1 -1
  506. package/src/server/default-logger.ts +99 -0
  507. package/src/server/deny-page-resolver.ts +154 -0
  508. package/src/server/deny-renderer.ts +24 -38
  509. package/src/server/dev-holding-server.ts +185 -0
  510. package/src/server/dev-source-map.ts +31 -0
  511. package/src/server/dev-warnings.ts +4 -49
  512. package/src/server/early-hints.ts +36 -15
  513. package/src/server/error-boundary-wrapper.ts +74 -22
  514. package/src/server/fallback-error.ts +74 -102
  515. package/src/server/flight-injection-state.ts +113 -0
  516. package/src/server/flight-scripts.ts +62 -0
  517. package/src/server/flush.ts +2 -1
  518. package/src/server/form-data.ts +76 -0
  519. package/src/server/html-injectors.ts +280 -120
  520. package/src/server/index.ts +25 -177
  521. package/src/server/internal.ts +169 -0
  522. package/src/server/logger.ts +44 -36
  523. package/src/server/middleware-runner.ts +31 -4
  524. package/src/server/node-stream-transforms.ts +509 -0
  525. package/src/server/page-deny-boundary.tsx +56 -0
  526. package/src/server/pipeline-interception.ts +17 -16
  527. package/src/server/pipeline-metadata.ts +13 -0
  528. package/src/server/pipeline.ts +261 -66
  529. package/src/server/primitives.ts +111 -28
  530. package/src/server/render-timeout.ts +108 -0
  531. package/src/server/request-context.ts +293 -132
  532. package/src/server/route-element-builder.ts +283 -191
  533. package/src/server/route-handler.ts +24 -4
  534. package/src/server/route-matcher.ts +31 -20
  535. package/src/server/rsc-entry/api-handler.ts +15 -16
  536. package/src/server/rsc-entry/error-renderer.ts +305 -89
  537. package/src/server/rsc-entry/helpers.ts +134 -5
  538. package/src/server/rsc-entry/index.ts +304 -111
  539. package/src/server/rsc-entry/rsc-payload.ts +65 -18
  540. package/src/server/rsc-entry/rsc-stream.ts +81 -13
  541. package/src/server/rsc-entry/ssr-bridge.ts +14 -5
  542. package/src/server/rsc-entry/ssr-renderer.ts +171 -38
  543. package/src/server/safe-load.ts +60 -0
  544. package/src/server/sensitive-fields.ts +230 -0
  545. package/src/server/sitemap-generator.ts +338 -0
  546. package/src/server/sitemap-handler.ts +126 -0
  547. package/src/server/slot-resolver.ts +244 -229
  548. package/src/server/ssr-entry.ts +215 -32
  549. package/src/server/ssr-render.ts +289 -67
  550. package/src/server/ssr-wrappers.tsx +139 -0
  551. package/src/server/status-code-resolver.ts +1 -1
  552. package/src/server/stream-utils.ts +213 -0
  553. package/src/server/tracing.ts +20 -9
  554. package/src/server/tree-builder.ts +92 -58
  555. package/src/server/types.ts +3 -6
  556. package/src/server/version-skew.ts +104 -0
  557. package/src/shared/merge-search-params.ts +55 -0
  558. package/src/shims/font-google.ts +1 -1
  559. package/src/shims/font-local.ts +34 -0
  560. package/src/shims/headers.ts +5 -1
  561. package/src/shims/navigation-client.ts +1 -1
  562. package/src/shims/navigation.ts +7 -2
  563. package/src/utils/directive-parser.ts +5 -2
  564. package/src/utils/state-machine.ts +111 -0
  565. package/dist/_chunks/als-registry-B7DbZ2hS.js.map +0 -1
  566. package/dist/_chunks/debug-gwlJkDuf.js.map +0 -1
  567. package/dist/_chunks/format-DviM89f0.js.map +0 -1
  568. package/dist/_chunks/interception-BOoWmLUA.js.map +0 -1
  569. package/dist/_chunks/request-context-DIkVh_jG.js +0 -330
  570. package/dist/_chunks/request-context-DIkVh_jG.js.map +0 -1
  571. package/dist/_chunks/tracing-CemImE6h.js.map +0 -1
  572. package/dist/_chunks/use-cookie-DX-l1_5E.js +0 -91
  573. package/dist/_chunks/use-cookie-DX-l1_5E.js.map +0 -1
  574. package/dist/_chunks/use-query-states-D5KaffOK.js.map +0 -1
  575. package/dist/cache/register-cached-function.d.ts +0 -17
  576. package/dist/cache/register-cached-function.d.ts.map +0 -1
  577. package/dist/client/browser-entry.d.ts +0 -21
  578. package/dist/client/browser-entry.d.ts.map +0 -1
  579. package/dist/client/link-status-provider.d.ts +0 -11
  580. package/dist/client/link-status-provider.d.ts.map +0 -1
  581. package/dist/client/transition-root.d.ts.map +0 -1
  582. package/dist/client/use-navigation-pending.d.ts.map +0 -1
  583. package/dist/cookies/index.js.map +0 -1
  584. package/dist/plugins/cache-transform.d.ts +0 -36
  585. package/dist/plugins/cache-transform.d.ts.map +0 -1
  586. package/dist/plugins/dynamic-transform.d.ts +0 -72
  587. package/dist/plugins/dynamic-transform.d.ts.map +0 -1
  588. package/dist/search-params/analyze.d.ts +0 -54
  589. package/dist/search-params/analyze.d.ts.map +0 -1
  590. package/dist/search-params/builtin-codecs.d.ts +0 -105
  591. package/dist/search-params/builtin-codecs.d.ts.map +0 -1
  592. package/dist/search-params/codecs.d.ts +0 -53
  593. package/dist/search-params/codecs.d.ts.map +0 -1
  594. package/dist/search-params/create.d.ts +0 -106
  595. package/dist/search-params/create.d.ts.map +0 -1
  596. package/dist/server/prerender.d.ts +0 -77
  597. package/dist/server/prerender.d.ts.map +0 -1
  598. package/dist/server/response-cache.d.ts +0 -54
  599. package/dist/server/response-cache.d.ts.map +0 -1
  600. package/src/cache/register-cached-function.ts +0 -103
  601. package/src/client/browser-entry.ts +0 -678
  602. package/src/client/link-status-provider.tsx +0 -30
  603. package/src/client/transition-root.tsx +0 -166
  604. package/src/plugins/cache-transform.ts +0 -199
  605. package/src/plugins/dynamic-transform.ts +0 -161
  606. package/src/search-params/analyze.ts +0 -192
  607. package/src/search-params/builtin-codecs.ts +0 -228
  608. package/src/search-params/create.ts +0 -321
  609. package/src/server/prerender.ts +0 -139
  610. package/src/server/response-cache.ts +0 -410
@@ -0,0 +1,356 @@
1
+ /**
2
+ * Convention linter — validates common misconfigurations in the route tree.
3
+ *
4
+ * Runs at scan time (build and dev startup). Each check produces a warning
5
+ * with the file path, what's wrong, and what to do about it.
6
+ *
7
+ * These are warnings, not errors — they don't block the build. The goal is
8
+ * to catch issues that would otherwise produce cryptic runtime behavior
9
+ * (silent 404s, empty pages, confusing React errors).
10
+ *
11
+ * Design doc: 07-routing.md, 10-error-handling.md
12
+ */
13
+
14
+ import { readFileSync, existsSync } from 'node:fs';
15
+ import type { RouteTree, SegmentNode } from './types.js';
16
+
17
+ // ─── Types ──────────────────────────────────────────────────────────────────
18
+
19
+ export interface ConventionWarning {
20
+ /** Warning ID for deduplication and filtering. */
21
+ id: string;
22
+ /** Human-readable single-line summary. */
23
+ summary: string;
24
+ /** Multi-line details with file path and fix suggestion. */
25
+ details: string;
26
+ /** Severity: 'warn' for potential issues, 'error' for definite misconfigurations. */
27
+ level: 'warn' | 'error';
28
+ }
29
+
30
+ // ─── Lint Rules ─────────────────────────────────────────────────────────────
31
+
32
+ /**
33
+ * Run all convention lint checks on a route tree.
34
+ *
35
+ * Returns an array of warnings. Empty array means everything looks good.
36
+ */
37
+ export function lintConventions(tree: RouteTree, appDir: string): ConventionWarning[] {
38
+ const warnings: ConventionWarning[] = [];
39
+
40
+ // Check 1: app/ directory exists (caller should check before scanning,
41
+ // but we validate the root has at least one routable file)
42
+ checkEmptyApp(tree.root, appDir, warnings);
43
+
44
+ // Check 2: route.ts without recognized HTTP method exports
45
+ checkRouteExports(tree.root, warnings);
46
+
47
+ // Check 3: Segments with layout but no page/route anywhere in subtree
48
+ // (not a misconfiguration per se — layouts without pages are valid for
49
+ // route groups. Skip this check.)
50
+
51
+ // Check 4: Root segment has no layout.tsx (no HTML shell)
52
+ checkRootLayout(tree.root, warnings);
53
+
54
+ // Check 5: page.tsx / layout.tsx without default export
55
+ checkDefaultExports(tree.root, warnings);
56
+
57
+ return warnings;
58
+ }
59
+
60
+ // ─── Check: Empty App ───────────────────────────────────────────────────────
61
+
62
+ /**
63
+ * Warn when the app/ directory has no routable files at all.
64
+ *
65
+ * This catches the "I created app/ but didn't add any pages" case where
66
+ * every request silently 404s with no guidance.
67
+ */
68
+ function checkEmptyApp(root: SegmentNode, appDir: string, warnings: ConventionWarning[]): void {
69
+ if (hasAnyRoutable(root)) return;
70
+
71
+ warnings.push({
72
+ id: 'EMPTY_APP',
73
+ summary: 'No pages or route handlers found in app/',
74
+ details:
75
+ ` Directory: ${appDir}\n\n` +
76
+ ' Your app/ directory has no page.tsx or route.ts files.\n' +
77
+ ' Every request will return 404.\n\n' +
78
+ ' To fix: Create app/page.tsx with a default export:\n\n' +
79
+ ' export default function Home() {\n return <h1>Hello</h1>;\n }\n',
80
+ level: 'warn',
81
+ });
82
+ }
83
+
84
+ /**
85
+ * Check if a segment tree has any routable files (page or route) anywhere.
86
+ */
87
+ function hasAnyRoutable(node: SegmentNode): boolean {
88
+ if (node.page || node.route) return true;
89
+ for (const child of node.children) {
90
+ if (hasAnyRoutable(child)) return true;
91
+ }
92
+ for (const [, slot] of node.slots) {
93
+ if (hasAnyRoutable(slot)) return true;
94
+ }
95
+ return false;
96
+ }
97
+
98
+ /**
99
+ * Check if a segment tree has any page files (not just route handlers).
100
+ * Used by checkRootLayout to avoid false positives for API-only apps (TIM-794).
101
+ * API-only apps (just route.ts handlers) don't need a root layout.
102
+ */
103
+ function hasAnyPage(node: SegmentNode): boolean {
104
+ if (node.page) return true;
105
+ for (const child of node.children) {
106
+ if (hasAnyPage(child)) return true;
107
+ }
108
+ for (const [, slot] of node.slots) {
109
+ if (hasAnyPage(slot)) return true;
110
+ }
111
+ return false;
112
+ }
113
+
114
+ // ─── Check: Route Exports ───────────────────────────────────────────────────
115
+
116
+ /** HTTP methods that route.ts can export. */
117
+ const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];
118
+
119
+ /**
120
+ * Pattern to detect named exports that look like HTTP method handlers.
121
+ * Matches: export function GET, export const GET, export async function POST, etc.
122
+ * Also matches: export { GET } or re-exports like export { GET } from './handler'.
123
+ *
124
+ * The re-export branch uses word boundaries (\b) around method names to avoid
125
+ * matching substrings (e.g. TARGET should not match GET). See TIM-795.
126
+ */
127
+ const EXPORT_PATTERN = new RegExp(
128
+ `export\\s+(?:async\\s+)?(?:function|const|let|var)\\s+(${HTTP_METHODS.join('|')})\\b` +
129
+ `|export\\s*\\{[^}]*\\b(${HTTP_METHODS.join('|')})\\b[^}]*\\}`
130
+ );
131
+
132
+ /**
133
+ * Warn when a route.ts file doesn't appear to export any recognized HTTP methods.
134
+ *
135
+ * Uses static analysis (regex on source text) — not module loading.
136
+ * This is intentionally conservative: it may miss complex re-exports but
137
+ * catches the common case of an empty route.ts or one with wrong export names.
138
+ */
139
+ function checkRouteExports(node: SegmentNode, warnings: ConventionWarning[]): void {
140
+ if (node.route) {
141
+ const filePath = node.route.filePath;
142
+ try {
143
+ const source = readFileSync(filePath, 'utf-8');
144
+ if (!EXPORT_PATTERN.test(source)) {
145
+ // Check if there's a default export (common mistake)
146
+ const hasDefaultExport = /export\s+default\b/.test(source);
147
+ const hint = hasDefaultExport
148
+ ? ' It looks like you have a default export. route.ts uses named exports\n' +
149
+ ' for HTTP methods (GET, POST, etc.), not a default export.\n'
150
+ : '';
151
+
152
+ warnings.push({
153
+ id: 'ROUTE_NO_METHODS',
154
+ summary: `route.ts has no HTTP method exports: ${filePath}`,
155
+ details:
156
+ ` File: ${filePath}\n\n` +
157
+ ' route.ts files must export named HTTP method handlers.\n' +
158
+ ' Without them, the route matches but returns 405 Method Not Allowed.\n\n' +
159
+ hint +
160
+ ' Example:\n\n' +
161
+ ' export function GET(ctx: RouteContext) {\n' +
162
+ " return Response.json({ hello: 'world' });\n" +
163
+ ' }\n',
164
+ level: 'warn',
165
+ });
166
+ }
167
+ } catch {
168
+ // Can't read the file — skip silently
169
+ }
170
+ }
171
+
172
+ // Recurse
173
+ for (const child of node.children) {
174
+ checkRouteExports(child, warnings);
175
+ }
176
+ for (const [, slot] of node.slots) {
177
+ checkRouteExports(slot, warnings);
178
+ }
179
+ }
180
+
181
+ // ─── Check: Root Layout ─────────────────────────────────────────────────────
182
+
183
+ /**
184
+ * Warn when the root segment has no layout.tsx.
185
+ *
186
+ * Without a root layout, there's no HTML shell (<html>, <body>).
187
+ * The page will render but may have hydration issues or no proper document structure.
188
+ */
189
+ function checkRootLayout(root: SegmentNode, warnings: ConventionWarning[]): void {
190
+ if (root.layout) return;
191
+
192
+ // Only warn if there are pages — API-only apps (just route.ts handlers)
193
+ // don't need a root layout (TIM-794).
194
+ if (!hasAnyPage(root)) return;
195
+
196
+ warnings.push({
197
+ id: 'NO_ROOT_LAYOUT',
198
+ summary: 'No root layout.tsx found',
199
+ details:
200
+ ' Your app has pages but no root layout.\n' +
201
+ ' Without app/layout.tsx, pages have no <html> or <body> wrapper.\n\n' +
202
+ ' To fix: Create app/layout.tsx:\n\n' +
203
+ ' export default function RootLayout({ children }: { children: React.ReactNode }) {\n' +
204
+ ' return (\n' +
205
+ ' <html lang="en">\n' +
206
+ ' <body>{children}</body>\n' +
207
+ ' </html>\n' +
208
+ ' );\n' +
209
+ ' }\n',
210
+ level: 'warn',
211
+ });
212
+ }
213
+
214
+ // ─── Check: Default Exports ───────────────────────────────────────────
215
+
216
+ /**
217
+ * Pattern to detect a default export in source code.
218
+ * Matches: export default function, export default class, export default
219
+ * Also matches: export { X as default }, export { default } from './Impl'
220
+ *
221
+ * The third alternative catches bare `default` re-exports (TIM-790).
222
+ * The negative lookahead (?!\s+as\b) prevents matching `export { default as X }`
223
+ * which is a named export, not a default export (TIM-806).
224
+ */
225
+ const DEFAULT_EXPORT_PATTERN =
226
+ /export\s+default\b|export\s*\{[^}]*\bas\s+default\b|export\s*\{[^}]*\bdefault\b(?!\s+as\b)[^}]*\}/;
227
+
228
+ /**
229
+ * Warn when page.tsx or layout.tsx files don't have a default export.
230
+ *
231
+ * Without a default export:
232
+ * - page.tsx: the page renders nothing (empty content)
233
+ * - layout.tsx: the layout module loads but has no component to render
234
+ *
235
+ * Uses static analysis (regex on source text) — intentionally conservative.
236
+ */
237
+ function checkDefaultExports(node: SegmentNode, warnings: ConventionWarning[]): void {
238
+ // Check page files (tsx/ts/jsx/js only — not mdx, which is default-exported by the mdx compiler)
239
+ if (node.page && isScriptExtension(node.page.extension)) {
240
+ checkFileDefaultExport(node.page.filePath, 'page', warnings);
241
+ }
242
+
243
+ // Check layout files
244
+ if (node.layout && isScriptExtension(node.layout.extension)) {
245
+ checkFileDefaultExport(node.layout.filePath, 'layout', warnings);
246
+ }
247
+
248
+ // Recurse
249
+ for (const child of node.children) {
250
+ checkDefaultExports(child, warnings);
251
+ }
252
+ for (const [, slot] of node.slots) {
253
+ checkDefaultExports(slot, warnings);
254
+ }
255
+ }
256
+
257
+ function isScriptExtension(ext: string): boolean {
258
+ return ext === 'tsx' || ext === 'ts' || ext === 'jsx' || ext === 'js';
259
+ }
260
+
261
+ function checkFileDefaultExport(
262
+ filePath: string,
263
+ fileType: string,
264
+ warnings: ConventionWarning[]
265
+ ): void {
266
+ try {
267
+ const source = readFileSync(filePath, 'utf-8');
268
+ if (!DEFAULT_EXPORT_PATTERN.test(source)) {
269
+ warnings.push({
270
+ id: `NO_DEFAULT_EXPORT:${filePath}`,
271
+ summary: `${fileType}.tsx has no default export: ${filePath}`,
272
+ details:
273
+ ` File: ${filePath}\n\n` +
274
+ ` ${fileType}.tsx files must export a default React component.\n` +
275
+ ` Without a default export, the ${fileType === 'page' ? 'page renders nothing' : 'layout has no component to wrap children'}.\n\n` +
276
+ ` To fix: Add a default export:\n\n` +
277
+ ` export default function My${fileType === 'page' ? 'Page' : 'Layout'}(${fileType === 'layout' ? '{ children }' : ''}) {\n` +
278
+ ` return ${fileType === 'layout' ? '<div>{children}</div>' : '<h1>Hello</h1>'};\n` +
279
+ ` }\n`,
280
+ level: 'warn',
281
+ });
282
+ }
283
+ } catch {
284
+ // Can't read file — skip silently
285
+ }
286
+ }
287
+
288
+ // ─── Check: App Directory Exists ────────────────────────────────────────────
289
+
290
+ /**
291
+ * Check if the app/ directory exists. Called before scanning.
292
+ * Returns a warning if missing, or null if the directory exists.
293
+ */
294
+ export function checkAppDirExists(appDir: string): ConventionWarning | null {
295
+ if (existsSync(appDir)) return null;
296
+
297
+ return {
298
+ id: 'NO_APP_DIR',
299
+ summary: 'No app/ directory found',
300
+ details:
301
+ ` Expected: ${appDir}\n\n` +
302
+ ' timber.js requires an app/ directory for file-system routing.\n' +
303
+ ' Every request will return 404 until you create it.\n\n' +
304
+ ' To fix: Create the app/ directory with a page:\n\n' +
305
+ ' mkdir -p app\n' +
306
+ ' # Create app/layout.tsx and app/page.tsx\n',
307
+ level: 'error',
308
+ };
309
+ }
310
+
311
+ // ─── Formatting ─────────────────────────────────────────────────────────────
312
+
313
+ const YELLOW = '\x1b[33m';
314
+ const RED = '\x1b[31m';
315
+ const BOLD = '\x1b[1m';
316
+ const DIM = '\x1b[2m';
317
+ const RESET = '\x1b[0m';
318
+
319
+ /**
320
+ * Format warnings for terminal output.
321
+ *
322
+ * Groups by severity, uses colors, and includes fix suggestions.
323
+ */
324
+ export function formatConventionWarnings(warnings: ConventionWarning[]): string {
325
+ if (warnings.length === 0) return '';
326
+
327
+ const errors = warnings.filter((w) => w.level === 'error');
328
+ const warns = warnings.filter((w) => w.level === 'warn');
329
+
330
+ const lines: string[] = [];
331
+
332
+ if (errors.length > 0) {
333
+ lines.push(
334
+ `${RED}${BOLD}[timber]${RESET} ${RED}${errors.length} configuration error${errors.length !== 1 ? 's' : ''}:${RESET}`
335
+ );
336
+ for (const e of errors) {
337
+ lines.push('');
338
+ lines.push(` ${RED}✗${RESET} ${e.summary}`);
339
+ lines.push(`${DIM}${e.details}${RESET}`);
340
+ }
341
+ }
342
+
343
+ if (warns.length > 0) {
344
+ if (errors.length > 0) lines.push('');
345
+ lines.push(
346
+ `${YELLOW}${BOLD}[timber]${RESET} ${YELLOW}${warns.length} configuration warning${warns.length !== 1 ? 's' : ''}:${RESET}`
347
+ );
348
+ for (const w of warns) {
349
+ lines.push('');
350
+ lines.push(` ${YELLOW}⚠${RESET} ${w.summary}`);
351
+ lines.push(`${DIM}${w.details}${RESET}`);
352
+ }
353
+ }
354
+
355
+ return lines.join('\n');
356
+ }
@@ -12,3 +12,5 @@ export type {
12
12
  export { DEFAULT_PAGE_EXTENSIONS, INTERCEPTION_MARKERS } from './types.js';
13
13
  export { collectInterceptionRewrites } from './interception.js';
14
14
  export type { InterceptionRewrite } from './interception.js';
15
+ export { classifyUrlSegment } from './segment-classify.js';
16
+ export type { UrlSegment } from './segment-classify.js';
@@ -18,8 +18,9 @@ import type {
18
18
  ScannerConfig,
19
19
  InterceptionMarker,
20
20
  } from './types.js';
21
+ import { classifyUrlSegment } from './segment-classify.js';
21
22
  import { DEFAULT_PAGE_EXTENSIONS, INTERCEPTION_MARKERS } from './types.js';
22
- import { classifyMetadataRoute, isDynamicMetadataExtension } from '#/server/metadata-routes.js';
23
+ import { classifyMetadataRoute, isDynamicMetadataExtension } from '../server/metadata-routes.js';
23
24
 
24
25
  /**
25
26
  * Pattern matching encoded path delimiters that must be rejected during route discovery.
@@ -53,7 +54,7 @@ const LEGACY_STATUS_FILES: Record<string, number> = {
53
54
  /**
54
55
  * File convention names that are always .ts/.tsx (never .mdx etc.)
55
56
  */
56
- const FIXED_CONVENTIONS = new Set(['middleware', 'access', 'route', 'prerender', 'search-params']);
57
+ const FIXED_CONVENTIONS = new Set(['middleware', 'access', 'route', 'params']);
57
58
 
58
59
  /**
59
60
  * Status-code file patterns:
@@ -83,6 +84,14 @@ export function scanRoutes(appDir: string, config: ScannerConfig = {}): RouteTre
83
84
  tree.proxy = proxyFile;
84
85
  }
85
86
 
87
+ // Check for global-error.{tsx,ts,jsx,js} at app root.
88
+ // Tier 2 error page — renders standalone (no layouts) when no segment-level
89
+ // error file is found. See design/10-error-handling.md §"Tier 2".
90
+ const globalErrorFile = findPageExtFile(appDir, 'global-error', extSet);
91
+ if (globalErrorFile) {
92
+ tree.globalError = globalErrorFile;
93
+ }
94
+
86
95
  // Scan the root directory's files
87
96
  scanSegmentFiles(appDir, tree.root, extSet);
88
97
 
@@ -92,6 +101,10 @@ export function scanRoutes(appDir: string, config: ScannerConfig = {}): RouteTre
92
101
  // Validate: detect route group collisions (different groups producing pages at the same URL)
93
102
  validateRouteGroupCollisions(tree.root);
94
103
 
104
+ // Validate: detect duplicate param names in nested dynamic segments
105
+ // e.g., /[id]/items/[id] — same param name in ancestor and descendant
106
+ validateDuplicateParamNames(tree.root);
107
+
95
108
  return tree;
96
109
  }
97
110
 
@@ -153,22 +166,12 @@ export function classifySegment(dirName: string): {
153
166
  return { type: 'group' };
154
167
  }
155
168
 
156
- // Optional catch-all: [[...name]]
157
- if (dirName.startsWith('[[...') && dirName.endsWith(']]')) {
158
- const paramName = dirName.slice(5, -2);
159
- return { type: 'optional-catch-all', paramName };
160
- }
161
-
162
- // Catch-all: [...name]
163
- if (dirName.startsWith('[...') && dirName.endsWith(']')) {
164
- const paramName = dirName.slice(4, -1);
165
- return { type: 'catch-all', paramName };
166
- }
167
-
168
- // Dynamic: [name]
169
- if (dirName.startsWith('[') && dirName.endsWith(']')) {
170
- const paramName = dirName.slice(1, -1);
171
- return { type: 'dynamic', paramName };
169
+ // Bracket-syntax segments: [param], [...param], [[...param]]
170
+ // Delegated to the shared character-based classifier. If you change
171
+ // bracket syntax, update segment-classify.ts — not here.
172
+ const urlSeg = classifyUrlSegment(dirName);
173
+ if (urlSeg.kind !== 'static') {
174
+ return { type: urlSeg.kind, paramName: urlSeg.name };
172
175
  }
173
176
 
174
177
  return { type: 'static' };
@@ -278,11 +281,8 @@ function scanSegmentFiles(dirPath: string, node: SegmentNode, extSet: Set<string
278
281
  case 'route':
279
282
  node.route = file;
280
283
  break;
281
- case 'prerender':
282
- node.prerender = file;
283
- break;
284
- case 'search-params':
285
- node.searchParams = file;
284
+ case 'params':
285
+ node.params = file;
286
286
  break;
287
287
  }
288
288
  continue;
@@ -482,6 +482,54 @@ function collectRoutableLeaves(
482
482
  }
483
483
  }
484
484
 
485
+ /**
486
+ * Validate that no route chain contains duplicate dynamic param names.
487
+ *
488
+ * Example violation:
489
+ * app/[id]/items/[id]/page.tsx — 'id' appears twice in the ancestor chain.
490
+ *
491
+ * Route groups are transparent — params accumulate through them.
492
+ * Slots are independent — duplicate detection does NOT cross slot boundaries.
493
+ *
494
+ * See design/07-routing.md §"Duplicate Param Name Detection"
495
+ */
496
+ function validateDuplicateParamNames(root: SegmentNode): void {
497
+ walkForDuplicateParams(root, new Map());
498
+ }
499
+
500
+ /**
501
+ * Recursively walk the segment tree, tracking seen param names → segment paths.
502
+ * Throws on the first duplicate found.
503
+ */
504
+ function walkForDuplicateParams(node: SegmentNode, seen: Map<string, string>): void {
505
+ // If this node introduces a param name, check for duplicates
506
+ if (node.paramName) {
507
+ const existing = seen.get(node.paramName);
508
+ if (existing) {
509
+ throw new Error(
510
+ `[timber] Duplicate param name '${node.paramName}' in route chain.\n` +
511
+ ` First defined at: ${existing}\n` +
512
+ ` Duplicate at: ${node.urlPath || '/'}\n` +
513
+ ` Rename one of the segments to avoid ambiguity.`
514
+ );
515
+ }
516
+ // Add to seen for descendants (use a new Map to avoid polluting siblings)
517
+ seen = new Map(seen);
518
+ seen.set(node.paramName, node.urlPath || '/');
519
+ }
520
+
521
+ // Recurse into children (they inherit the accumulated params)
522
+ for (const child of node.children) {
523
+ walkForDuplicateParams(child, seen);
524
+ }
525
+
526
+ // Slots are independent parallel routes — start fresh param tracking
527
+ // (a slot's params don't conflict with the main route's params)
528
+ for (const [, slotNode] of node.slots) {
529
+ walkForDuplicateParams(slotNode, new Map(seen));
530
+ }
531
+ }
532
+
485
533
  /**
486
534
  * Find a fixed-extension file (proxy.ts) in a directory.
487
535
  */
@@ -498,3 +546,25 @@ function findFixedFile(dirPath: string, name: string): RouteFile | undefined {
498
546
  }
499
547
  return undefined;
500
548
  }
549
+
550
+ /**
551
+ * Find a file using the configured page extensions (tsx, ts, jsx, js, mdx, etc.).
552
+ * Used for app-root conventions like global-error that aren't per-segment.
553
+ */
554
+ function findPageExtFile(
555
+ dirPath: string,
556
+ name: string,
557
+ extSet: Set<string>
558
+ ): RouteFile | undefined {
559
+ for (const ext of extSet) {
560
+ const fullPath = join(dirPath, `${name}.${ext}`);
561
+ try {
562
+ if (statSync(fullPath).isFile()) {
563
+ return { filePath: fullPath, extension: ext };
564
+ }
565
+ } catch {
566
+ // File doesn't exist
567
+ }
568
+ }
569
+ return undefined;
570
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Shared URL segment classifier.
3
+ *
4
+ * Single-pass character parser that classifies a route segment token
5
+ * (e.g. "dashboard", "[id]", "[...slug]", "[[...path]]") into a typed
6
+ * discriminated union. Used by both server-side routing and client-side
7
+ * Link interpolation.
8
+ *
9
+ * NO regex. NO Node.js-only APIs. Safe to import from browser code.
10
+ *
11
+ * Malformed input (unclosed brackets, empty names, etc.) falls through
12
+ * to { kind: 'static' } — the safe default.
13
+ *
14
+ * If you change the bracket syntax, update ONLY this file. Every
15
+ * consumer imports from here.
16
+ *
17
+ * See design/07-routing.md §"Route Segments"
18
+ */
19
+
20
+ export type UrlSegment =
21
+ | { kind: 'static'; value: string }
22
+ | { kind: 'dynamic'; name: string }
23
+ | { kind: 'catch-all'; name: string }
24
+ | { kind: 'optional-catch-all'; name: string };
25
+
26
+ /**
27
+ * Classify a URL path segment token.
28
+ *
29
+ * Walks the string left-to-right in one pass:
30
+ * 1. If it doesn't start with '[', it's static.
31
+ * 2. Count opening brackets (1 or 2) to detect optional.
32
+ * 3. Check for '...' to detect catch-all.
33
+ * 4. Read the param name up to the closing bracket.
34
+ * 5. Validate the expected closing sequence (']' or ']]').
35
+ * 6. Reject if there are leftover characters after the close.
36
+ *
37
+ * Any structural violation → static (safe default).
38
+ */
39
+ export function classifyUrlSegment(token: string): UrlSegment {
40
+ const len = token.length;
41
+
42
+ // Must start with '[' to be dynamic
43
+ if (len === 0 || token[0] !== '[') {
44
+ return { kind: 'static', value: token };
45
+ }
46
+
47
+ let i = 1;
48
+
49
+ // Check for optional: '[[...'
50
+ const optional = token[i] === '[';
51
+ if (optional) i++;
52
+
53
+ // Check for catch-all: '...'
54
+ const catchAll = i + 2 < len && token[i] === '.' && token[i + 1] === '.' && token[i + 2] === '.';
55
+ if (catchAll) i += 3;
56
+
57
+ // Read param name — everything up to ']'
58
+ const nameStart = i;
59
+ while (i < len && token[i] !== ']') i++;
60
+
61
+ // Must have found a ']' and name must be non-empty
62
+ if (i >= len || i === nameStart) {
63
+ return { kind: 'static', value: token };
64
+ }
65
+
66
+ const name = token.slice(nameStart, i);
67
+ i++; // skip first ']'
68
+
69
+ // Optional requires a second ']'
70
+ if (optional) {
71
+ if (i >= len || token[i] !== ']') {
72
+ return { kind: 'static', value: token };
73
+ }
74
+ i++;
75
+ }
76
+
77
+ // Must be at end of string — no trailing characters
78
+ if (i !== len) {
79
+ return { kind: 'static', value: token };
80
+ }
81
+
82
+ if (optional && catchAll) return { kind: 'optional-catch-all', name };
83
+ if (catchAll) return { kind: 'catch-all', name };
84
+ if (optional) {
85
+ // '[[name]]' without '...' is malformed — not a valid segment syntax
86
+ return { kind: 'static', value: token };
87
+ }
88
+ return { kind: 'dynamic', name };
89
+ }
@@ -15,7 +15,7 @@
15
15
 
16
16
  import { readFileSync } from 'node:fs';
17
17
  import type { RouteTree, SegmentNode } from './types.js';
18
- import { detectFileDirective } from '#/utils/directive-parser.js';
18
+ import { detectFileDirective } from '../utils/directive-parser.js';
19
19
 
20
20
  /** Extensions that require 'use client' (component files, not MDX/JSON). */
21
21
  const CLIENT_REQUIRED_EXTENSIONS = new Set(['tsx', 'jsx', 'ts', 'js']);
@@ -31,7 +31,8 @@ export interface StatusFileLintWarning {
31
31
  * that are missing it.
32
32
  *
33
33
  * MDX and JSON status files are excluded — MDX files are server components
34
- * by design, and JSON files are data, not components.
34
+ * by design (pre-rendered as elements via fallbackElement, see TIM-503),
35
+ * and JSON files are data, not components.
35
36
  */
36
37
  export function lintStatusFileDirectives(tree: RouteTree): StatusFileLintWarning[] {
37
38
  const warnings: StatusFileLintWarning[] = [];
@@ -59,6 +59,12 @@ export interface SegmentNode {
59
59
  middleware?: RouteFile;
60
60
  access?: RouteFile;
61
61
  route?: RouteFile;
62
+ /**
63
+ * params.ts — isomorphic convention file exporting segmentParams and/or searchParams.
64
+ * Discovered by the scanner like middleware.ts and access.ts.
65
+ * See design/07-routing.md §"params.ts Convention File"
66
+ */
67
+ params?: RouteFile;
62
68
  error?: RouteFile;
63
69
  default?: RouteFile;
64
70
  /** Status-code files: 4xx.tsx, 5xx.tsx, {status}.tsx (component format) */
@@ -69,10 +75,7 @@ export interface SegmentNode {
69
75
  denied?: RouteFile;
70
76
  /** Legacy compat: not-found.tsx (maps to 404), forbidden.tsx (403), unauthorized.tsx (401) */
71
77
  legacyStatusFiles?: Map<string, RouteFile>;
72
- /** prerender.ts — signals build-time pre-rendering for this segment's shell */
73
- prerender?: RouteFile;
74
- /** search-params.ts — typed search params definition for this route */
75
- searchParams?: RouteFile;
78
+
76
79
  /** Metadata route files (sitemap.ts, robots.ts, icon.tsx, etc.) keyed by base name */
77
80
  metadataRoutes?: Map<string, RouteFile>;
78
81
 
@@ -88,6 +91,16 @@ export interface RouteTree {
88
91
  root: SegmentNode;
89
92
  /** All discovered proxy.ts files (should be at most one, in app/) */
90
93
  proxy?: RouteFile;
94
+ /**
95
+ * Global error page: app/global-error.{tsx,ts,jsx,js}
96
+ *
97
+ * Rendered as a standalone full-page replacement (no layout wrapping)
98
+ * when no segment-level error file is found. SSR-only render path.
99
+ * Must provide its own <html> and <body>.
100
+ *
101
+ * See design/10-error-handling.md §"Tier 2 — Global Error Page"
102
+ */
103
+ globalError?: RouteFile;
91
104
  }
92
105
 
93
106
  /** Configuration passed to the scanner */
@@ -16,4 +16,6 @@ export {
16
16
  loadServerAction,
17
17
  decodeReply,
18
18
  decodeAction,
19
+ encryptActionBoundArgs,
20
+ decryptActionBoundArgs,
19
21
  } from '@vitejs/plugin-rsc/rsc';