@timber-js/app 0.2.0-alpha.97 → 0.2.0-alpha.99

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 (372) hide show
  1. package/dist/_chunks/actions-CQ8Z8VGL.js +1061 -0
  2. package/dist/_chunks/actions-CQ8Z8VGL.js.map +1 -0
  3. package/dist/_chunks/build-output-helper-DXnW0qjz.js +61 -0
  4. package/dist/_chunks/build-output-helper-DXnW0qjz.js.map +1 -0
  5. package/dist/_chunks/{define-Itxvcd7F.js → define-B-Q_UMOD.js} +19 -23
  6. package/dist/_chunks/define-B-Q_UMOD.js.map +1 -0
  7. package/dist/_chunks/{define-C77ScO0m.js → define-CfBPoJb0.js} +24 -7
  8. package/dist/_chunks/define-CfBPoJb0.js.map +1 -0
  9. package/dist/_chunks/define-cookie-BjpIt4UC.js +194 -0
  10. package/dist/_chunks/define-cookie-BjpIt4UC.js.map +1 -0
  11. package/dist/_chunks/{format-CYBGxKtc.js → format-Bcn-Iv1x.js} +1 -1
  12. package/dist/_chunks/{format-CYBGxKtc.js.map → format-Bcn-Iv1x.js.map} +1 -1
  13. package/dist/_chunks/handler-store-B-lqaGyh.js +54 -0
  14. package/dist/_chunks/handler-store-B-lqaGyh.js.map +1 -0
  15. package/dist/_chunks/logger-0m8MsKdc.js +291 -0
  16. package/dist/_chunks/logger-0m8MsKdc.js.map +1 -0
  17. package/dist/_chunks/merge-search-params-BphMdht_.js +122 -0
  18. package/dist/_chunks/merge-search-params-BphMdht_.js.map +1 -0
  19. package/dist/_chunks/{metadata-routes-DS3eKNmf.js → metadata-routes-BU684ls2.js} +1 -1
  20. package/dist/_chunks/{metadata-routes-DS3eKNmf.js.map → metadata-routes-BU684ls2.js.map} +1 -1
  21. package/dist/_chunks/navigation-root-BCYczjml.js +96 -0
  22. package/dist/_chunks/navigation-root-BCYczjml.js.map +1 -0
  23. package/dist/_chunks/registry-I2ss-lvy.js +20 -0
  24. package/dist/_chunks/registry-I2ss-lvy.js.map +1 -0
  25. package/dist/_chunks/router-ref-h3-UaCQv.js +28 -0
  26. package/dist/_chunks/router-ref-h3-UaCQv.js.map +1 -0
  27. package/dist/_chunks/{schema-bridge-C3xl_vfb.js → schema-bridge-Cxu4l-7p.js} +1 -1
  28. package/dist/_chunks/{schema-bridge-C3xl_vfb.js.map → schema-bridge-Cxu4l-7p.js.map} +1 -1
  29. package/dist/_chunks/segment-classify-BjfuctV2.js +137 -0
  30. package/dist/_chunks/segment-classify-BjfuctV2.js.map +1 -0
  31. package/dist/_chunks/{segment-context-fHFLF1PE.js → segment-context-Dx_OizxD.js} +1 -1
  32. package/dist/_chunks/{segment-context-fHFLF1PE.js.map → segment-context-Dx_OizxD.js.map} +1 -1
  33. package/dist/_chunks/{router-ref-C8OCm7g7.js → ssr-data-B4CdH7rE.js} +2 -26
  34. package/dist/_chunks/ssr-data-B4CdH7rE.js.map +1 -0
  35. package/dist/_chunks/{stale-reload-BX5gL1r-.js → stale-reload-Bab885FO.js} +1 -1
  36. package/dist/_chunks/{stale-reload-BX5gL1r-.js.map → stale-reload-Bab885FO.js.map} +1 -1
  37. package/dist/_chunks/tracing-C8V-YGsP.js +329 -0
  38. package/dist/_chunks/tracing-C8V-YGsP.js.map +1 -0
  39. package/dist/_chunks/{use-query-states-BiV5GJgm.js → use-query-states-B2XTqxDR.js} +3 -19
  40. package/dist/_chunks/use-query-states-B2XTqxDR.js.map +1 -0
  41. package/dist/_chunks/{use-params-IOPu7E8t.js → use-segment-params-BkpKAQ7D.js} +9 -95
  42. package/dist/_chunks/use-segment-params-BkpKAQ7D.js.map +1 -0
  43. package/dist/_chunks/{interception-BbqMCVXa.js → walkers-Tg0Alwcg.js} +66 -87
  44. package/dist/_chunks/walkers-Tg0Alwcg.js.map +1 -0
  45. package/dist/_chunks/{dev-warnings-DpGRGoDi.js → warnings-Cg47l5sk.js} +3 -3
  46. package/dist/_chunks/warnings-Cg47l5sk.js.map +1 -0
  47. package/dist/adapters/build-output-helper.d.ts +28 -0
  48. package/dist/adapters/build-output-helper.d.ts.map +1 -0
  49. package/dist/adapters/cloudflare.d.ts.map +1 -1
  50. package/dist/adapters/cloudflare.js +8 -28
  51. package/dist/adapters/cloudflare.js.map +1 -1
  52. package/dist/adapters/nitro.d.ts.map +1 -1
  53. package/dist/adapters/nitro.js +63 -31
  54. package/dist/adapters/nitro.js.map +1 -1
  55. package/dist/adapters/shared.d.ts +16 -0
  56. package/dist/adapters/shared.d.ts.map +1 -0
  57. package/dist/cache/index.js +9 -2
  58. package/dist/cache/index.js.map +1 -1
  59. package/dist/cache/timber-cache.d.ts.map +1 -1
  60. package/dist/client/error-boundary.js +2 -1
  61. package/dist/client/error-boundary.js.map +1 -1
  62. package/dist/client/form.d.ts +10 -24
  63. package/dist/client/form.d.ts.map +1 -1
  64. package/dist/client/index.d.ts +1 -5
  65. package/dist/client/index.d.ts.map +1 -1
  66. package/dist/client/index.js +41 -91
  67. package/dist/client/index.js.map +1 -1
  68. package/dist/client/internal.d.ts +2 -1
  69. package/dist/client/internal.d.ts.map +1 -1
  70. package/dist/client/internal.js +81 -7
  71. package/dist/client/internal.js.map +1 -1
  72. package/dist/client/rsc-fetch.d.ts.map +1 -1
  73. package/dist/client/state.d.ts +1 -1
  74. package/dist/client/use-cookie.d.ts +8 -0
  75. package/dist/client/use-cookie.d.ts.map +1 -1
  76. package/dist/client/{use-params.d.ts → use-segment-params.d.ts} +1 -1
  77. package/dist/client/use-segment-params.d.ts.map +1 -0
  78. package/dist/codec.d.ts +1 -1
  79. package/dist/codec.d.ts.map +1 -1
  80. package/dist/codec.js +2 -2
  81. package/dist/config-types.d.ts +28 -0
  82. package/dist/config-types.d.ts.map +1 -1
  83. package/dist/cookies/define-cookie.d.ts +87 -35
  84. package/dist/cookies/define-cookie.d.ts.map +1 -1
  85. package/dist/cookies/index.d.ts +2 -1
  86. package/dist/cookies/index.d.ts.map +1 -1
  87. package/dist/cookies/index.js +48 -2
  88. package/dist/cookies/index.js.map +1 -0
  89. package/dist/cookies/json-cookie.d.ts +64 -0
  90. package/dist/cookies/json-cookie.d.ts.map +1 -0
  91. package/dist/cookies/validation.d.ts +46 -0
  92. package/dist/cookies/validation.d.ts.map +1 -0
  93. package/dist/{plugins/dev-404-page.d.ts → dev-tools/404-page.d.ts} +9 -19
  94. package/dist/dev-tools/404-page.d.ts.map +1 -0
  95. package/dist/{plugins/dev-browser-logs.d.ts → dev-tools/browser-logs.d.ts} +1 -1
  96. package/dist/dev-tools/browser-logs.d.ts.map +1 -0
  97. package/dist/{plugins/dev-error-page.d.ts → dev-tools/error-page.d.ts} +2 -2
  98. package/dist/dev-tools/error-page.d.ts.map +1 -0
  99. package/dist/{server/dev-holding-server.d.ts → dev-tools/holding-server.d.ts} +5 -3
  100. package/dist/dev-tools/holding-server.d.ts.map +1 -0
  101. package/dist/dev-tools/index.d.ts +31 -0
  102. package/dist/dev-tools/index.d.ts.map +1 -0
  103. package/dist/{server/dev-span-processor.d.ts → dev-tools/instrumentation.d.ts} +26 -6
  104. package/dist/dev-tools/instrumentation.d.ts.map +1 -0
  105. package/dist/{server/dev-logger.d.ts → dev-tools/logger.d.ts} +1 -1
  106. package/dist/dev-tools/logger.d.ts.map +1 -0
  107. package/dist/{plugins/dev-logs.d.ts → dev-tools/logs.d.ts} +1 -1
  108. package/dist/dev-tools/logs.d.ts.map +1 -0
  109. package/dist/{plugins/dev-error-overlay.d.ts → dev-tools/overlay.d.ts} +3 -12
  110. package/dist/dev-tools/overlay.d.ts.map +1 -0
  111. package/dist/dev-tools/stack-classifier.d.ts +34 -0
  112. package/dist/dev-tools/stack-classifier.d.ts.map +1 -0
  113. package/dist/{plugins/dev-terminal-error.d.ts → dev-tools/terminal.d.ts} +2 -2
  114. package/dist/dev-tools/terminal.d.ts.map +1 -0
  115. package/dist/{server/dev-warnings.d.ts → dev-tools/warnings.d.ts} +1 -1
  116. package/dist/dev-tools/warnings.d.ts.map +1 -0
  117. package/dist/index.d.ts +1 -0
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/index.js +285 -133
  120. package/dist/index.js.map +1 -1
  121. package/dist/plugin-context.d.ts +1 -1
  122. package/dist/plugin-context.d.ts.map +1 -1
  123. package/dist/plugins/adapter-build.d.ts.map +1 -1
  124. package/dist/plugins/build-report.d.ts +6 -4
  125. package/dist/plugins/build-report.d.ts.map +1 -1
  126. package/dist/routing/convention-lint.d.ts.map +1 -1
  127. package/dist/routing/index.d.ts +5 -3
  128. package/dist/routing/index.d.ts.map +1 -1
  129. package/dist/routing/index.js +3 -3
  130. package/dist/routing/scanner.d.ts +1 -10
  131. package/dist/routing/scanner.d.ts.map +1 -1
  132. package/dist/routing/segment-classify.d.ts +37 -8
  133. package/dist/routing/segment-classify.d.ts.map +1 -1
  134. package/dist/routing/status-file-lint.d.ts.map +1 -1
  135. package/dist/routing/types.d.ts +63 -23
  136. package/dist/routing/types.d.ts.map +1 -1
  137. package/dist/routing/walkers.d.ts +51 -0
  138. package/dist/routing/walkers.d.ts.map +1 -0
  139. package/dist/search-params/define.d.ts +25 -7
  140. package/dist/search-params/define.d.ts.map +1 -1
  141. package/dist/search-params/index.js +5 -3
  142. package/dist/search-params/index.js.map +1 -1
  143. package/dist/search-params/wrappers.d.ts +2 -2
  144. package/dist/search-params/wrappers.d.ts.map +1 -1
  145. package/dist/segment-params/define.d.ts +23 -6
  146. package/dist/segment-params/define.d.ts.map +1 -1
  147. package/dist/segment-params/index.js +1 -1
  148. package/dist/server/access-gate.d.ts +4 -3
  149. package/dist/server/access-gate.d.ts.map +1 -1
  150. package/dist/server/action-handler.d.ts +15 -6
  151. package/dist/server/action-handler.d.ts.map +1 -1
  152. package/dist/server/als-registry.d.ts +5 -5
  153. package/dist/server/als-registry.d.ts.map +1 -1
  154. package/dist/server/asset-headers.d.ts +1 -15
  155. package/dist/server/asset-headers.d.ts.map +1 -1
  156. package/dist/server/cookie-context.d.ts +170 -0
  157. package/dist/server/cookie-context.d.ts.map +1 -0
  158. package/dist/server/cookie-parsing.d.ts +51 -0
  159. package/dist/server/cookie-parsing.d.ts.map +1 -0
  160. package/dist/server/deny-boundary.d.ts +90 -0
  161. package/dist/server/deny-boundary.d.ts.map +1 -0
  162. package/dist/server/deny-renderer.d.ts.map +1 -1
  163. package/dist/server/early-hints-sender.d.ts.map +1 -1
  164. package/dist/server/html-injector-core.d.ts +212 -0
  165. package/dist/server/html-injector-core.d.ts.map +1 -0
  166. package/dist/server/html-injectors.d.ts +59 -59
  167. package/dist/server/html-injectors.d.ts.map +1 -1
  168. package/dist/server/index.d.ts +5 -4
  169. package/dist/server/index.d.ts.map +1 -1
  170. package/dist/server/index.js +4 -149
  171. package/dist/server/index.js.map +1 -1
  172. package/dist/server/internal.d.ts +6 -4
  173. package/dist/server/internal.d.ts.map +1 -1
  174. package/dist/server/internal.js +852 -852
  175. package/dist/server/internal.js.map +1 -1
  176. package/dist/server/logger.d.ts +14 -0
  177. package/dist/server/logger.d.ts.map +1 -1
  178. package/dist/server/middleware-runner.d.ts +17 -0
  179. package/dist/server/middleware-runner.d.ts.map +1 -1
  180. package/dist/server/node-stream-transforms.d.ts +46 -49
  181. package/dist/server/node-stream-transforms.d.ts.map +1 -1
  182. package/dist/server/param-coercion.d.ts +26 -0
  183. package/dist/server/param-coercion.d.ts.map +1 -0
  184. package/dist/server/pipeline-helpers.d.ts +95 -0
  185. package/dist/server/pipeline-helpers.d.ts.map +1 -0
  186. package/dist/server/pipeline-outcome.d.ts +49 -0
  187. package/dist/server/pipeline-outcome.d.ts.map +1 -0
  188. package/dist/server/pipeline-phases.d.ts +52 -0
  189. package/dist/server/pipeline-phases.d.ts.map +1 -0
  190. package/dist/server/pipeline.d.ts +51 -32
  191. package/dist/server/pipeline.d.ts.map +1 -1
  192. package/dist/server/port-resolution.d.ts +117 -0
  193. package/dist/server/port-resolution.d.ts.map +1 -0
  194. package/dist/server/request-context.d.ts +22 -159
  195. package/dist/server/request-context.d.ts.map +1 -1
  196. package/dist/server/route-element-builder.d.ts.map +1 -1
  197. package/dist/server/route-matcher.d.ts +20 -47
  198. package/dist/server/route-matcher.d.ts.map +1 -1
  199. package/dist/server/rsc-entry/action-middleware-runner.d.ts +66 -0
  200. package/dist/server/rsc-entry/action-middleware-runner.d.ts.map +1 -0
  201. package/dist/server/rsc-entry/helpers.d.ts +1 -1
  202. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  203. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  204. package/dist/server/rsc-entry/render-route.d.ts +50 -0
  205. package/dist/server/rsc-entry/render-route.d.ts.map +1 -0
  206. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +119 -0
  207. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts.map +1 -0
  208. package/dist/server/state-tree-diff.d.ts.map +1 -1
  209. package/dist/server/status-code-resolver.d.ts +16 -11
  210. package/dist/server/status-code-resolver.d.ts.map +1 -1
  211. package/dist/server/tracing.d.ts +1 -1
  212. package/dist/server/tracing.d.ts.map +1 -1
  213. package/dist/server/tree-builder.d.ts +45 -16
  214. package/dist/server/tree-builder.d.ts.map +1 -1
  215. package/dist/server/types.d.ts +48 -0
  216. package/dist/server/types.d.ts.map +1 -1
  217. package/dist/server/utils/escape-html.d.ts +14 -0
  218. package/dist/server/utils/escape-html.d.ts.map +1 -0
  219. package/dist/shims/headers.d.ts +2 -2
  220. package/dist/shims/headers.d.ts.map +1 -1
  221. package/dist/shims/navigation-client.d.ts +3 -1
  222. package/dist/shims/navigation-client.d.ts.map +1 -1
  223. package/dist/shims/navigation.d.ts +9 -4
  224. package/dist/shims/navigation.d.ts.map +1 -1
  225. package/dist/utils/directive-parser.d.ts +0 -45
  226. package/dist/utils/directive-parser.d.ts.map +1 -1
  227. package/package.json +1 -1
  228. package/src/adapters/build-output-helper.ts +77 -0
  229. package/src/adapters/cloudflare.ts +10 -50
  230. package/src/adapters/nitro.ts +66 -50
  231. package/src/adapters/shared.ts +40 -0
  232. package/src/cache/timber-cache.ts +3 -2
  233. package/src/client/form.tsx +17 -25
  234. package/src/client/index.ts +16 -9
  235. package/src/client/internal.ts +3 -2
  236. package/src/client/router.ts +1 -1
  237. package/src/client/rsc-fetch.ts +15 -0
  238. package/src/client/state.ts +2 -2
  239. package/src/client/use-cookie.ts +29 -0
  240. package/src/codec.ts +3 -7
  241. package/src/config-types.ts +28 -0
  242. package/src/cookies/define-cookie.ts +271 -78
  243. package/src/cookies/index.ts +11 -8
  244. package/src/cookies/json-cookie.ts +105 -0
  245. package/src/cookies/validation.ts +134 -0
  246. package/src/{plugins/dev-404-page.ts → dev-tools/404-page.ts} +17 -48
  247. package/src/{plugins/dev-error-page.ts → dev-tools/error-page.ts} +5 -32
  248. package/src/{server/dev-holding-server.ts → dev-tools/holding-server.ts} +4 -2
  249. package/src/dev-tools/index.ts +90 -0
  250. package/src/dev-tools/instrumentation.ts +176 -0
  251. package/src/{plugins/dev-logs.ts → dev-tools/logs.ts} +2 -2
  252. package/src/{plugins/dev-error-overlay.ts → dev-tools/overlay.ts} +5 -23
  253. package/src/dev-tools/stack-classifier.ts +75 -0
  254. package/src/{plugins/dev-terminal-error.ts → dev-tools/terminal.ts} +4 -38
  255. package/src/{server/dev-warnings.ts → dev-tools/warnings.ts} +1 -1
  256. package/src/index.ts +95 -34
  257. package/src/plugin-context.ts +1 -1
  258. package/src/plugins/adapter-build.ts +3 -1
  259. package/src/plugins/build-report.ts +13 -22
  260. package/src/plugins/dev-server.ts +3 -3
  261. package/src/plugins/routing.ts +14 -12
  262. package/src/plugins/shims.ts +1 -1
  263. package/src/plugins/static-build.ts +1 -1
  264. package/src/routing/codegen.ts +1 -1
  265. package/src/routing/convention-lint.ts +9 -8
  266. package/src/routing/index.ts +5 -3
  267. package/src/routing/interception.ts +1 -1
  268. package/src/routing/scanner.ts +22 -95
  269. package/src/routing/segment-classify.ts +107 -8
  270. package/src/routing/status-file-lint.ts +7 -5
  271. package/src/routing/types.ts +63 -23
  272. package/src/routing/walkers.ts +90 -0
  273. package/src/search-params/define.ts +71 -15
  274. package/src/search-params/wrappers.ts +9 -2
  275. package/src/segment-params/define.ts +66 -13
  276. package/src/server/access-gate.tsx +9 -8
  277. package/src/server/action-handler.ts +34 -38
  278. package/src/server/als-registry.ts +5 -5
  279. package/src/server/asset-headers.ts +8 -34
  280. package/src/server/cookie-context.ts +468 -0
  281. package/src/server/cookie-parsing.ts +135 -0
  282. package/src/server/{deny-page-resolver.ts → deny-boundary.ts} +78 -14
  283. package/src/server/deny-renderer.ts +7 -12
  284. package/src/server/early-hints-sender.ts +3 -2
  285. package/src/server/fallback-error.ts +2 -2
  286. package/src/server/html-injector-core.ts +403 -0
  287. package/src/server/html-injectors.ts +158 -297
  288. package/src/server/index.ts +13 -14
  289. package/src/server/internal.ts +10 -3
  290. package/src/server/logger.ts +23 -0
  291. package/src/server/middleware-runner.ts +44 -0
  292. package/src/server/node-stream-transforms.ts +108 -248
  293. package/src/server/param-coercion.ts +76 -0
  294. package/src/server/pipeline-helpers.ts +204 -0
  295. package/src/server/pipeline-outcome.ts +167 -0
  296. package/src/server/pipeline-phases.ts +409 -0
  297. package/src/server/pipeline.ts +70 -540
  298. package/src/server/port-resolution.ts +215 -0
  299. package/src/server/request-context.ts +46 -451
  300. package/src/server/route-element-builder.ts +8 -4
  301. package/src/server/route-matcher.ts +28 -60
  302. package/src/server/rsc-entry/action-middleware-runner.ts +167 -0
  303. package/src/server/rsc-entry/api-handler.ts +2 -2
  304. package/src/server/rsc-entry/error-renderer.ts +2 -2
  305. package/src/server/rsc-entry/helpers.ts +2 -7
  306. package/src/server/rsc-entry/index.ts +81 -366
  307. package/src/server/rsc-entry/render-route.ts +304 -0
  308. package/src/server/rsc-entry/rsc-payload.ts +1 -1
  309. package/src/server/rsc-entry/ssr-renderer.ts +2 -2
  310. package/src/server/rsc-entry/wrap-action-dispatch.ts +449 -0
  311. package/src/server/sitemap-generator.ts +1 -1
  312. package/src/server/slot-resolver.ts +1 -1
  313. package/src/server/ssr-entry.ts +1 -1
  314. package/src/server/state-tree-diff.ts +4 -1
  315. package/src/server/status-code-resolver.ts +112 -128
  316. package/src/server/tracing.ts +3 -3
  317. package/src/server/tree-builder.ts +134 -56
  318. package/src/server/types.ts +52 -0
  319. package/src/server/utils/escape-html.ts +20 -0
  320. package/src/shims/headers.ts +3 -3
  321. package/src/shims/navigation-client.ts +4 -3
  322. package/src/shims/navigation.ts +9 -7
  323. package/src/utils/directive-parser.ts +0 -392
  324. package/dist/_chunks/actions-DLnUaR65.js +0 -421
  325. package/dist/_chunks/actions-DLnUaR65.js.map +0 -1
  326. package/dist/_chunks/als-registry-HS0LGUl2.js +0 -41
  327. package/dist/_chunks/als-registry-HS0LGUl2.js.map +0 -1
  328. package/dist/_chunks/debug-ECi_61pb.js +0 -108
  329. package/dist/_chunks/debug-ECi_61pb.js.map +0 -1
  330. package/dist/_chunks/define-C77ScO0m.js.map +0 -1
  331. package/dist/_chunks/define-Itxvcd7F.js.map +0 -1
  332. package/dist/_chunks/define-cookie-BowvzoP0.js +0 -94
  333. package/dist/_chunks/define-cookie-BowvzoP0.js.map +0 -1
  334. package/dist/_chunks/dev-warnings-DpGRGoDi.js.map +0 -1
  335. package/dist/_chunks/interception-BbqMCVXa.js.map +0 -1
  336. package/dist/_chunks/merge-search-params-Cm_KIWDX.js +0 -41
  337. package/dist/_chunks/merge-search-params-Cm_KIWDX.js.map +0 -1
  338. package/dist/_chunks/request-context-CK5tZqIP.js +0 -478
  339. package/dist/_chunks/request-context-CK5tZqIP.js.map +0 -1
  340. package/dist/_chunks/router-ref-C8OCm7g7.js.map +0 -1
  341. package/dist/_chunks/segment-classify-BDNn6EzD.js +0 -65
  342. package/dist/_chunks/segment-classify-BDNn6EzD.js.map +0 -1
  343. package/dist/_chunks/tracing-CCYbKn5n.js +0 -238
  344. package/dist/_chunks/tracing-CCYbKn5n.js.map +0 -1
  345. package/dist/_chunks/use-params-IOPu7E8t.js.map +0 -1
  346. package/dist/_chunks/use-query-states-BiV5GJgm.js.map +0 -1
  347. package/dist/client/use-params.d.ts.map +0 -1
  348. package/dist/plugins/dev-404-page.d.ts.map +0 -1
  349. package/dist/plugins/dev-browser-logs.d.ts.map +0 -1
  350. package/dist/plugins/dev-error-overlay.d.ts.map +0 -1
  351. package/dist/plugins/dev-error-page.d.ts.map +0 -1
  352. package/dist/plugins/dev-logs.d.ts.map +0 -1
  353. package/dist/plugins/dev-terminal-error.d.ts.map +0 -1
  354. package/dist/server/deny-page-resolver.d.ts +0 -52
  355. package/dist/server/deny-page-resolver.d.ts.map +0 -1
  356. package/dist/server/dev-fetch-instrumentation.d.ts +0 -22
  357. package/dist/server/dev-fetch-instrumentation.d.ts.map +0 -1
  358. package/dist/server/dev-holding-server.d.ts.map +0 -1
  359. package/dist/server/dev-logger.d.ts.map +0 -1
  360. package/dist/server/dev-span-processor.d.ts.map +0 -1
  361. package/dist/server/dev-warnings.d.ts.map +0 -1
  362. package/dist/server/manifest-status-resolver.d.ts +0 -58
  363. package/dist/server/manifest-status-resolver.d.ts.map +0 -1
  364. package/dist/server/page-deny-boundary.d.ts +0 -31
  365. package/dist/server/page-deny-boundary.d.ts.map +0 -1
  366. package/src/server/dev-fetch-instrumentation.ts +0 -96
  367. package/src/server/dev-span-processor.ts +0 -78
  368. package/src/server/manifest-status-resolver.ts +0 -215
  369. package/src/server/page-deny-boundary.tsx +0 -56
  370. /package/src/client/{use-params.ts → use-segment-params.ts} +0 -0
  371. /package/src/{plugins/dev-browser-logs.ts → dev-tools/browser-logs.ts} +0 -0
  372. /package/src/{server/dev-logger.ts → dev-tools/logger.ts} +0 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Cookie name and value validation per RFC 6265 §4.1.1.
3
+ *
4
+ * This module is pure — no server or client imports — so it can be loaded
5
+ * by both `server/request-context.ts` (which guards `getCookies().set()`)
6
+ * and `client/use-cookie.ts` (which guards `useCookie()`'s setter). The
7
+ * shared validator gives both sides identical encoding contracts:
8
+ * **the framework never silently encodes — callers emit `cookie-octet`
9
+ * bytes or get a developer-facing error.**
10
+ *
11
+ * Why this matters: see ONGOING_SECURITY.md H-3 (TIM-868) and
12
+ * design/29-cookies.md §"Cookie Name and Value Validation".
13
+ */
14
+
15
+ // ─── RFC 6265 cookie-octet ────────────────────────────────────────────────
16
+ //
17
+ // cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
18
+ //
19
+ // Equivalently: US-ASCII printable bytes excluding whitespace, `"` (0x22),
20
+ // `,` (0x2C), `;` (0x3B), `\` (0x5C), and DEL (0x7F).
21
+
22
+ /**
23
+ * RFC 7230 §3.2.6 token characters used as the cookie-name production in
24
+ * RFC 6265 §4.1.1. Anchored, non-empty match.
25
+ *
26
+ * Allowed: US-ASCII letters, digits, and `!#$%&'*+-.^_` `` ` `` `|~`.
27
+ * Disallowed: whitespace, controls, delimiters
28
+ * (`(` `)` `<` `>` `@` `,` `;` `:` `\` `"` `/` `[` `]` `?` `=` `{` `}`).
29
+ */
30
+ const COOKIE_NAME_RE = /^[!#$%&'*+\-.0-9A-Z^_`a-z|~]+$/;
31
+
32
+ /**
33
+ * Format a single byte for a clear error message — escape control bytes
34
+ * and non-ASCII as `0x..` and quote printables.
35
+ */
36
+ function describeChar(value: string, index: number): string {
37
+ const code = value.charCodeAt(index);
38
+ if (code < 0x20 || code === 0x7f || code > 0x7e) {
39
+ return `0x${code.toString(16).padStart(2, '0')}`;
40
+ }
41
+ return JSON.stringify(value[index]);
42
+ }
43
+
44
+ /**
45
+ * Validate a cookie name against RFC 6265 §4.1.1 / RFC 7230 token rules.
46
+ * Throws a developer-facing error naming the offending byte and its index.
47
+ */
48
+ export function assertValidCookieName(name: string): void {
49
+ if (typeof name !== 'string' || name.length === 0) {
50
+ throw new Error('[timber] cookie name must be a non-empty string.');
51
+ }
52
+ if (!COOKIE_NAME_RE.test(name)) {
53
+ for (let i = 0; i < name.length; i++) {
54
+ if (!COOKIE_NAME_RE.test(name[i])) {
55
+ throw new Error(
56
+ `[timber] invalid cookie name ${JSON.stringify(name)} — ` +
57
+ `disallowed character ${describeChar(name, i)} at index ${i}. ` +
58
+ `Cookie names must match the RFC 6265 §4.1.1 token grammar (US-ASCII letters, digits, ` +
59
+ `and \`!#$%&'*+-.^_\`|~\`; no whitespace, controls, or delimiters).`
60
+ );
61
+ }
62
+ }
63
+ throw new Error(
64
+ `[timber] invalid cookie name ${JSON.stringify(name)} — ` +
65
+ `must match RFC 6265 §4.1.1 token grammar.`
66
+ );
67
+ }
68
+ }
69
+
70
+ /** Single-byte test for RFC 6265 §4.1.1 cookie-octet. */
71
+ function isCookieOctet(code: number): boolean {
72
+ return (
73
+ code === 0x21 ||
74
+ (code >= 0x23 && code <= 0x2b) ||
75
+ (code >= 0x2d && code <= 0x3a) ||
76
+ (code >= 0x3c && code <= 0x5b) ||
77
+ (code >= 0x5d && code <= 0x7e)
78
+ );
79
+ }
80
+
81
+ /**
82
+ * Validate a cookie value against the RFC 6265 §4.1.1 `cookie-value`
83
+ * production:
84
+ *
85
+ * cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
86
+ * cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
87
+ *
88
+ * Both the bare `*cookie-octet` form and the DQUOTE-wrapped form are
89
+ * valid. The wrapped form is common in upstream `Set-Cookie` headers
90
+ * (e.g. `sid="abc"; Path=/`) and must be forwardable through
91
+ * `setFromHeaders` verbatim — stripping or rejecting the surrounding
92
+ * quotes would corrupt the on-the-wire bytes and break value semantics
93
+ * for the upstream service.
94
+ *
95
+ * Excluded bytes (in either form): CTL, whitespace (CR/LF/TAB/SP),
96
+ * interior DQUOTE, comma, semicolon, backslash, DEL, and anything
97
+ * non-ASCII. The smuggling primitive (`;`) is rejected regardless of
98
+ * wrapping.
99
+ *
100
+ * Throws a developer-facing error naming the offending byte and its
101
+ * index. Callers passing user-controlled data through the default
102
+ * `set()` path don't need to call this — `set()` auto-encodes via
103
+ * `encodeURIComponent`, whose output is always valid cookie-octet.
104
+ * This validator is for the `{ raw: true }` opt-out and for
105
+ * `setFromHeaders` forwarding.
106
+ */
107
+ export function assertValidCookieValue(name: string, value: string): void {
108
+ if (typeof value !== 'string') {
109
+ throw new Error(`[timber] cookie ${JSON.stringify(name)}: cookie value must be a string.`);
110
+ }
111
+ // Detect the DQUOTE-wrapped form: at least two characters and both
112
+ // endpoints are `"`. The interior must be pure cookie-octet (no
113
+ // interior DQUOTEs allowed — the grammar says *cookie-octet, and
114
+ // cookie-octet excludes 0x22).
115
+ const wrapped =
116
+ value.length >= 2 &&
117
+ value.charCodeAt(0) === 0x22 &&
118
+ value.charCodeAt(value.length - 1) === 0x22;
119
+ const start = wrapped ? 1 : 0;
120
+ const end = wrapped ? value.length - 1 : value.length;
121
+ for (let i = start; i < end; i++) {
122
+ const code = value.charCodeAt(i);
123
+ if (!isCookieOctet(code)) {
124
+ throw new Error(
125
+ `[timber] cookie ${JSON.stringify(name)}: invalid cookie value — ` +
126
+ `disallowed character ${describeChar(value, i)} at index ${i}. ` +
127
+ `Cookie values must contain only RFC 6265 §4.1.1 cookie-octet bytes ` +
128
+ `(US-ASCII printable, excluding whitespace, \`"\`, \`,\`, \`;\`, and \`\\\`), ` +
129
+ `optionally enclosed in a single DQUOTE pair. ` +
130
+ `Encode the value (e.g. encodeURIComponent or jsonCookieCodec) before storing it.`
131
+ );
132
+ }
133
+ }
134
+ }
@@ -13,6 +13,10 @@
13
13
  * Design doc: 21-dev-server.md, 07-routing.md
14
14
  */
15
15
 
16
+ import type { SegmentNode } from '../routing/types.js';
17
+ import { collectLeafRoutes } from '../routing/walkers.js';
18
+ import { escapeHtml } from '../server/utils/escape-html.js';
19
+
16
20
  // ─── Types ──────────────────────────────────────────────────────────────────
17
21
 
18
22
  interface RouteInfo {
@@ -22,54 +26,25 @@ interface RouteInfo {
22
26
  type: 'page' | 'route';
23
27
  }
24
28
 
25
- /** Minimal segment node shape — matches ManifestSegmentNode. */
26
- interface SegmentNode {
27
- segmentName: string;
28
- segmentType: string;
29
- urlPath: string;
30
- page?: { filePath: string };
31
- route?: { filePath: string };
32
- children: SegmentNode[];
33
- slots: Record<string, SegmentNode> | Map<string, SegmentNode>;
34
- }
35
-
36
29
  // ─── Route Collection ───────────────────────────────────────────────────────
37
30
 
38
31
  /**
39
- * Collect all routable paths from the manifest tree.
32
+ * Collect all routable paths from a route tree (build-time scanner output
33
+ * or runtime route manifest).
40
34
  *
41
- * Walks the segment tree and collects paths for segments that have
42
- * a page or route handler.
35
+ * Wraps the shared `collectLeafRoutes` walker (TIM-848). Includes parallel
36
+ * slots so the dev 404 page can list slot pages too — they aren't
37
+ * separately addressable, but they're still useful to know about when
38
+ * debugging a missing route.
43
39
  */
44
- export function collectRoutes(root: SegmentNode): RouteInfo[] {
40
+ export function collectRoutes<TFile>(root: SegmentNode<TFile>): RouteInfo[] {
41
+ const leaves = collectLeafRoutes(root, { includeSlots: true });
45
42
  const routes: RouteInfo[] = [];
46
- walkRoutes(root, routes);
47
- return routes.sort((a, b) => a.path.localeCompare(b.path));
48
- }
49
-
50
- function walkRoutes(node: SegmentNode, routes: RouteInfo[]): void {
51
- if (node.page) {
52
- routes.push({ path: node.urlPath || '/', type: 'page' });
53
- }
54
- if (node.route) {
55
- routes.push({ path: node.urlPath || '/', type: 'route' });
56
- }
57
-
58
- for (const child of node.children) {
59
- walkRoutes(child, routes);
60
- }
61
-
62
- // Handle both Map and plain object for slots
63
- const slots = node.slots;
64
- if (slots instanceof Map) {
65
- for (const [, slotNode] of slots) {
66
- walkRoutes(slotNode, routes);
67
- }
68
- } else if (slots && typeof slots === 'object') {
69
- for (const key of Object.keys(slots)) {
70
- walkRoutes((slots as Record<string, SegmentNode>)[key]!, routes);
71
- }
43
+ for (const leaf of leaves) {
44
+ if (leaf.page) routes.push({ path: leaf.urlPath, type: 'page' });
45
+ if (leaf.route) routes.push({ path: leaf.urlPath, type: 'route' });
72
46
  }
47
+ return routes;
73
48
  }
74
49
 
75
50
  // ─── String Similarity ──────────────────────────────────────────────────────
@@ -130,13 +105,7 @@ export function findSimilarRoutes(requestedPath: string, routes: RouteInfo[]): R
130
105
 
131
106
  // ─── HTML Escaping ──────────────────────────────────────────────────────────
132
107
 
133
- function esc(str: string): string {
134
- return str
135
- .replace(/&/g, '&amp;')
136
- .replace(/</g, '&lt;')
137
- .replace(/>/g, '&gt;')
138
- .replace(/"/g, '&quot;');
139
- }
108
+ const esc = escapeHtml;
140
109
 
141
110
  // ─── HTML Generation ────────────────────────────────────────────────────────
142
111
 
@@ -15,19 +15,12 @@
15
15
  */
16
16
 
17
17
  import {
18
- classifyFrame,
19
18
  extractComponentStack,
20
19
  parseFirstAppFrame,
21
20
  type ErrorPhase,
22
- type FrameType,
23
- } from './dev-error-overlay.js';
24
-
25
- // ─── Types ──────────────────────────────────────────────────────────────────
26
-
27
- interface ClassifiedFrame {
28
- raw: string;
29
- type: FrameType;
30
- }
21
+ } from './overlay.js';
22
+ import { classifyStack } from './stack-classifier.js';
23
+ import { escapeHtml } from '../server/utils/escape-html.js';
31
24
 
32
25
  // ─── Phase Labels ───────────────────────────────────────────────────────────
33
26
 
@@ -52,19 +45,6 @@ const PHASE_HINTS: Record<ErrorPhase, string> = {
52
45
  'handler': 'This error occurred in a route handler (route.ts). Check the handler function.',
53
46
  };
54
47
 
55
- // ─── Stack Trace Processing ─────────────────────────────────────────────────
56
-
57
- function classifyStack(stack: string, projectRoot: string): ClassifiedFrame[] {
58
- return stack
59
- .split('\n')
60
- .slice(1) // skip first line (error message)
61
- .filter((line) => line.trim().startsWith('at '))
62
- .map((line) => ({
63
- raw: line,
64
- type: classifyFrame(line, projectRoot),
65
- }));
66
- }
67
-
68
48
  // ─── Source Context ─────────────────────────────────────────────────────────
69
49
 
70
50
  /**
@@ -97,15 +77,8 @@ function readSourceContext(
97
77
  }
98
78
  }
99
79
 
100
- // ─── HTML Escaping ──────────────────────────────────────────────────────────
101
-
102
- function esc(str: string): string {
103
- return str
104
- .replace(/&/g, '&amp;')
105
- .replace(/</g, '&lt;')
106
- .replace(/>/g, '&gt;')
107
- .replace(/"/g, '&quot;');
108
- }
80
+ // HTML escaping provided by server/utils/escape-html.ts
81
+ const esc = escapeHtml;
109
82
 
110
83
  /**
111
84
  * Escape a JSON string for safe embedding in an HTML `<script>` block.
@@ -119,9 +119,11 @@ const HOLDING_PAGE_HTML = [
119
119
  *
120
120
  * Usage (inside Vite plugin):
121
121
  * ```ts
122
- * // In config() hook — earliest point where port is known
122
+ * // In config() hook — earliest point where port is known.
123
+ * // Use bindWithBump() to honor the default-3000 + auto-bump policy
124
+ * // (see ../server/port-resolution.ts and TIM-842).
123
125
  * const holding = createHoldingServer();
124
- * holding.listen(config.server?.port ?? 5173);
126
+ * await bindWithBump((p) => holding.listen(p), { startPort: 3000, autoBump: true });
125
127
  *
126
128
  * // In last plugin's configureServer() — wrap listen for seamless handoff
127
129
  * const originalListen = server.listen.bind(server);
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Dev tools barrel — re-exports all dev-only modules.
3
+ *
4
+ * Organized by concern, not by Vite plugin vs server module:
5
+ * - stack-classifier: frame classification for error display
6
+ * - overlay: Vite browser error overlay integration
7
+ * - error-page: self-contained HTML 500 page
8
+ * - 404-page: self-contained HTML 404 page
9
+ * - terminal: boxed terminal error output
10
+ * - logger: structured request tree logger
11
+ * - warnings: dev-mode footgun warnings
12
+ * - browser-logs: forward browser console to server
13
+ * - logs: forward server console to browser
14
+ * - holding-server: startup holding server
15
+ * - instrumentation: fetch tracing + OTEL span processor
16
+ *
17
+ * Dev-only: all modules in this subtree are only active during `vite dev`.
18
+ * They are never included in production builds.
19
+ */
20
+
21
+ // Stack trace classification
22
+ export {
23
+ classifyFrame,
24
+ classifyStack,
25
+ type FrameType,
26
+ type ClassifiedFrame,
27
+ } from './stack-classifier.js';
28
+
29
+ // Error overlay (Vite integration)
30
+ export {
31
+ sendErrorToOverlay,
32
+ fixErrorStacktrace,
33
+ classifyErrorPhase,
34
+ extractComponentStack,
35
+ parseFirstAppFrame,
36
+ calculateModuleRunnerOffset,
37
+ formatRscDebugContext,
38
+ formatTerminalError,
39
+ PHASE_LABELS,
40
+ type ErrorPhase,
41
+ type RscDebugComponentInfo,
42
+ } from './overlay.js';
43
+
44
+ // HTML error pages
45
+ export { generateDevErrorPage, extractHmrOptions, type DevErrorHmrOptions } from './error-page.js';
46
+ export { generateDev404Page, collectRoutes, findSimilarRoutes } from './404-page.js';
47
+
48
+ // Terminal error formatting
49
+ export { formatTerminalError as formatTerminalErrorDirect } from './terminal.js';
50
+
51
+ // Request tree logger
52
+ export {
53
+ formatSpanTree,
54
+ formatSpanSummary,
55
+ formatJson,
56
+ resolveLogMode,
57
+ type DevLogMode,
58
+ type DevLoggerConfig,
59
+ } from './logger.js';
60
+
61
+ // Dev-mode warnings
62
+ export {
63
+ warnSuspenseWrappingChildren,
64
+ warnDenyInSuspense,
65
+ warnRedirectInSuspense,
66
+ warnRedirectInAccess,
67
+ warnStaticRequestApi,
68
+ warnSlowSlotWithoutSuspense,
69
+ setViteServer,
70
+ WarningId,
71
+ type DevWarningConfig,
72
+ _resetWarnings,
73
+ _getEmitted,
74
+ } from './warnings.js';
75
+
76
+ // Browser log forwarding
77
+ export {
78
+ timberDevBrowserLogs,
79
+ type BrowserLogLevel,
80
+ type DevBrowserLogsConfig,
81
+ } from './browser-logs.js';
82
+
83
+ // Server log forwarding
84
+ export { timberDevLogs } from './logs.js';
85
+
86
+ // Holding server
87
+ export { createHoldingServer, type HoldingServer } from './holding-server.js';
88
+
89
+ // OTEL instrumentation
90
+ export { instrumentDevFetch, DevSpanProcessor, type DevFetchCleanup } from './instrumentation.js';
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Dev-mode OTEL instrumentation — fetch tracing and span processing.
3
+ *
4
+ * Combines two concerns:
5
+ * 1. Fetch instrumentation: patches globalThis.fetch to create OTEL spans
6
+ * for every fetch call, giving visibility into async data fetching in
7
+ * the dev request log tree.
8
+ * 2. Span processing: collects completed spans per-request and drives
9
+ * dev log output when the root span ends.
10
+ *
11
+ * Only activated in dev mode — zero overhead in production.
12
+ *
13
+ * Design ref: 17-logging.md §"Dev Logging", 21-dev-server.md §"Dev Logging"
14
+ */
15
+
16
+ import * as api from '@opentelemetry/api';
17
+ import type { SpanProcessor, ReadableSpan } from '@opentelemetry/sdk-trace-base';
18
+ import type { Span, Context } from '@opentelemetry/api';
19
+ import {
20
+ formatSpanTree,
21
+ formatSpanSummary,
22
+ formatJson,
23
+ type DevLogMode,
24
+ type DevLoggerConfig,
25
+ } from './logger.js';
26
+
27
+ // ─── Fetch Instrumentation ──────────────────────────────────────────────────
28
+
29
+ export type DevFetchCleanup = () => void;
30
+
31
+ /**
32
+ * Patch globalThis.fetch to wrap every call in an OTEL span.
33
+ *
34
+ * Returns a cleanup function that restores the original fetch.
35
+ * Only call this in dev mode.
36
+ */
37
+ export function instrumentDevFetch(): DevFetchCleanup {
38
+ const originalFetch = globalThis.fetch;
39
+ const tracer = api.trace.getTracer('timber.js');
40
+
41
+ globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
42
+ const { method, url } = extractFetchInfo(input, init);
43
+
44
+ return tracer.startActiveSpan(
45
+ 'timber.fetch',
46
+ {
47
+ attributes: {
48
+ 'http.request.method': method,
49
+ 'http.url': url,
50
+ },
51
+ },
52
+ async (span) => {
53
+ try {
54
+ const response = await originalFetch(input, init);
55
+
56
+ span.setAttribute('http.response.status_code', response.status);
57
+
58
+ // Surface cache status from standard headers
59
+ const cacheStatus =
60
+ response.headers.get('X-Cache') ?? response.headers.get('CF-Cache-Status');
61
+ if (cacheStatus) {
62
+ span.setAttribute('timber.cache_status', cacheStatus);
63
+ }
64
+
65
+ span.setStatus({ code: api.SpanStatusCode.OK });
66
+ span.end();
67
+ return response;
68
+ } catch (error) {
69
+ span.setStatus({ code: api.SpanStatusCode.ERROR });
70
+ if (error instanceof Error) {
71
+ span.setAttribute('timber.fetch_error', error.message);
72
+ span.recordException(error);
73
+ }
74
+ span.end();
75
+ throw error;
76
+ }
77
+ }
78
+ );
79
+ };
80
+
81
+ return () => {
82
+ globalThis.fetch = originalFetch;
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Extract method and URL from the various fetch() call signatures.
88
+ */
89
+ function extractFetchInfo(
90
+ input: RequestInfo | URL,
91
+ init?: RequestInit
92
+ ): { method: string; url: string } {
93
+ let method = init?.method ?? 'GET';
94
+ let url: string;
95
+
96
+ if (input instanceof Request) {
97
+ url = input.url;
98
+ if (!init?.method) {
99
+ method = input.method;
100
+ }
101
+ } else if (input instanceof URL) {
102
+ url = input.toString();
103
+ } else {
104
+ url = input;
105
+ }
106
+
107
+ return { method: method.toUpperCase(), url };
108
+ }
109
+
110
+ // ─── Span Processor ─────────────────────────────────────────────────────────
111
+
112
+ /**
113
+ * DevSpanProcessor — Custom OTEL SpanProcessor that drives dev log output.
114
+ *
115
+ * Collects completed spans per-request (correlated by trace ID). When the
116
+ * root span (http.server.request) ends, all child spans are already collected
117
+ * (child spans end before parent in OTEL). The processor formats the span
118
+ * tree and writes it to stderr.
119
+ *
120
+ * This replaces the old DevLogEmitter/DevLogEvents system. OTEL spans are
121
+ * now the single source of truth for dev logging — no more parallel event
122
+ * systems that can drift.
123
+ */
124
+ export class DevSpanProcessor implements SpanProcessor {
125
+ private spansByTrace = new Map<string, ReadableSpan[]>();
126
+ private mode: DevLogMode;
127
+ private config: DevLoggerConfig;
128
+
129
+ constructor(config: DevLoggerConfig) {
130
+ this.config = config;
131
+ this.mode = config.mode ?? 'tree';
132
+ }
133
+
134
+ onStart(_span: Span, _context: Context): void {
135
+ // No action needed on span start — we collect on end.
136
+ }
137
+
138
+ onEnd(span: ReadableSpan): void {
139
+ const traceId = span.spanContext().traceId;
140
+
141
+ let spans = this.spansByTrace.get(traceId);
142
+ if (!spans) {
143
+ spans = [];
144
+ this.spansByTrace.set(traceId, spans);
145
+ }
146
+ spans.push(span);
147
+
148
+ // Root span signals request completion — all child spans are already
149
+ // collected because OTEL ends child spans before parent spans.
150
+ if (span.name === 'http.server.request') {
151
+ const output = this.format(spans);
152
+ if (output) {
153
+ process.stderr.write(output);
154
+ }
155
+ this.spansByTrace.delete(traceId);
156
+ }
157
+ }
158
+
159
+ private format(spans: ReadableSpan[]): string {
160
+ if (this.mode === 'quiet') return '';
161
+ if (this.mode === 'json') return formatJson(spans);
162
+ if (this.mode === 'summary') return formatSpanSummary(spans, this.config);
163
+ // Both 'tree' and 'verbose' use the tree formatter.
164
+ // verbose will show additional detail (every component render) once
165
+ // component-level spans are wired.
166
+ return formatSpanTree(spans, this.config);
167
+ }
168
+
169
+ async shutdown(): Promise<void> {
170
+ this.spansByTrace.clear();
171
+ }
172
+
173
+ async forceFlush(): Promise<void> {
174
+ // Nothing to flush — output happens synchronously in onEnd.
175
+ }
176
+ }
@@ -149,7 +149,7 @@ function extractCallerLocation(projectRoot: string): string | null {
149
149
  for (let i = 1; i < lines.length; i++) {
150
150
  const line = lines[i].trim();
151
151
  // Skip our own patching frames
152
- if (line.includes('dev-logs')) continue;
152
+ if (line.includes('dev-tools/logs')) continue;
153
153
  // Skip node internals
154
154
  if (line.includes('node:') || line.includes('node_modules')) continue;
155
155
 
@@ -189,7 +189,7 @@ export function isFrameworkInternalCaller(): boolean {
189
189
  for (let i = 1; i < lines.length; i++) {
190
190
  const line = lines[i].trim();
191
191
  // Skip our own patching frames
192
- if (line.includes('dev-logs')) continue;
192
+ if (line.includes('dev-tools/logs')) continue;
193
193
  // Skip node internals (but NOT node_modules — we need to inspect those)
194
194
  if (line.includes('node:')) continue;
195
195
 
@@ -18,6 +18,7 @@
18
18
  import type { ViteDevServer, DevEnvironment } from 'vite';
19
19
  import { createRequire } from 'node:module';
20
20
  import { resolve, dirname } from 'node:path';
21
+ import { classifyFrame, type FrameType } from './stack-classifier.js';
21
22
 
22
23
  // ─── Trace Mapping (lazy-loaded) ─────────────────────────────────────────────
23
24
 
@@ -70,28 +71,9 @@ export const PHASE_LABELS: Record<ErrorPhase, string> = {
70
71
  'handler': 'Route Handler',
71
72
  };
72
73
 
73
- // ─── Frame Classification ───────────────────────────────────────────────────
74
+ // ─── Frame Classification (re-exported from stack-classifier) ───────────────
74
75
 
75
- export type FrameType = 'app' | 'framework' | 'internal';
76
-
77
- /**
78
- * Classify a stack frame line by origin.
79
- *
80
- * - 'app': user application code (in project root, not node_modules)
81
- * - 'framework': timber-app internal code
82
- * - 'internal': node_modules, Node.js internals
83
- */
84
- export function classifyFrame(frameLine: string, projectRoot: string): FrameType {
85
- // Strip leading whitespace and "at "
86
- const trimmed = frameLine.trim();
87
-
88
- if (trimmed.includes('packages/timber-app/')) return 'framework';
89
- if (trimmed.includes('node_modules/')) return 'internal';
90
- if (trimmed.startsWith('at node:') || trimmed.includes('(node:')) return 'internal';
91
- if (trimmed.includes(projectRoot)) return 'app';
92
-
93
- return 'internal';
94
- }
76
+ export { classifyFrame, classifyStack, type FrameType, type ClassifiedFrame } from './stack-classifier.js';
95
77
 
96
78
  // ─── Component Stack Extraction ─────────────────────────────────────────────
97
79
 
@@ -172,9 +154,9 @@ export function classifyErrorPhase(error: Error, projectRoot: string): ErrorPhas
172
154
  // ─── Terminal Formatting ────────────────────────────────────────────────────
173
155
 
174
156
  // formatTerminalError is implemented in the dedicated terminal formatter module
175
- // (dev-terminal-error.ts) to keep this file under 500 lines.
157
+ // (terminal.ts) to keep this file under 500 lines.
176
158
  // Import for use in sendErrorToOverlay, and re-export for external consumers.
177
- import { formatTerminalError as _formatTerminalError } from './dev-terminal-error.js';
159
+ import { formatTerminalError as _formatTerminalError } from './terminal.js';
178
160
  export const formatTerminalError = _formatTerminalError;
179
161
 
180
162
  // ─── RSC Debug Context ──────────────────────────────────────────────────────