@timber-js/app 0.2.0-alpha.191 → 0.2.0-alpha.194

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 (672) hide show
  1. package/agent-skill.md +2 -0
  2. package/dist/_chunks/{actions-BjbbNRFN.js → actions-CWYtq6ii.js} +3 -3
  3. package/dist/_chunks/actions-CWYtq6ii.js.map +1 -0
  4. package/dist/_chunks/als-registry-C6kcfprT.js.map +1 -1
  5. package/dist/_chunks/als-slots-BEEIPKYm.js.map +1 -1
  6. package/dist/_chunks/{build-output-helper-C3DrfzZR.js → build-output-helper-9dqCv1pZ.js} +3 -2
  7. package/dist/_chunks/build-output-helper-9dqCv1pZ.js.map +1 -0
  8. package/dist/_chunks/{cache-api-DllJ-Lyw.js → cache-api-CQeYzA5g.js} +6 -8
  9. package/dist/_chunks/cache-api-CQeYzA5g.js.map +1 -0
  10. package/dist/_chunks/chains-h7EO-u3n.js +412 -0
  11. package/dist/_chunks/chains-h7EO-u3n.js.map +1 -0
  12. package/dist/_chunks/{cli-check-DJZDc22E.js → cli-check-BVthpfLS.js} +43 -6
  13. package/dist/_chunks/cli-check-BVthpfLS.js.map +1 -0
  14. package/dist/_chunks/{cli-schema-sync-D4_AZVUb.js → cli-schema-sync-ZwM9u_ob.js} +6 -5
  15. package/dist/_chunks/{cli-schema-sync-D4_AZVUb.js.map → cli-schema-sync-ZwM9u_ob.js.map} +1 -1
  16. package/dist/_chunks/{cloudflare-CGP6BZKO.js → cloudflare-BKJC3SC_.js} +28 -22
  17. package/dist/_chunks/{cloudflare-CGP6BZKO.js.map → cloudflare-BKJC3SC_.js.map} +1 -1
  18. package/dist/_chunks/codec-registry-oOUxugz3.js.map +1 -1
  19. package/dist/_chunks/{convention-lint-CpteIpTm.js → convention-lint-DO10_pVl.js} +93 -7
  20. package/dist/_chunks/convention-lint-DO10_pVl.js.map +1 -0
  21. package/dist/_chunks/dist-DtrJyBbw.js +386 -0
  22. package/dist/_chunks/dist-DtrJyBbw.js.map +1 -0
  23. package/dist/_chunks/error-boundary-D-ODYX41.js.map +1 -1
  24. package/dist/_chunks/{file-cache-DmX7OqZP.js → file-cache-Dw6BJPG7.js} +5 -1
  25. package/dist/_chunks/{file-cache-DmX7OqZP.js.map → file-cache-Dw6BJPG7.js.map} +1 -1
  26. package/dist/_chunks/{format-CfwjgPz9.js → format-BKclgVbk.js} +3 -3
  27. package/dist/_chunks/{format-CfwjgPz9.js.map → format-BKclgVbk.js.map} +1 -1
  28. package/dist/_chunks/graph-cache-CP4GEmf9.js +304 -0
  29. package/dist/_chunks/graph-cache-CP4GEmf9.js.map +1 -0
  30. package/dist/_chunks/href-validation-CMc5JRls.js.map +1 -1
  31. package/dist/_chunks/live-graph-Bx4HodF1.js +150 -0
  32. package/dist/_chunks/live-graph-Bx4HodF1.js.map +1 -0
  33. package/dist/_chunks/{logger-CH7IcMmg.js → logger-pumCm3Il.js} +25 -7
  34. package/dist/_chunks/{logger-CH7IcMmg.js.map → logger-pumCm3Il.js.map} +1 -1
  35. package/dist/_chunks/{mdx-file-C005ay-P.js → mdx-file-CXyHGUpS.js} +3 -3
  36. package/dist/_chunks/mdx-file-CXyHGUpS.js.map +1 -0
  37. package/dist/_chunks/{plugin-context-rCinWLiE.js → plugin-context-8idfR3UZ.js} +2 -2
  38. package/dist/_chunks/plugin-context-8idfR3UZ.js.map +1 -0
  39. package/dist/_chunks/poison-rules-DoEhbqaY.js +110 -0
  40. package/dist/_chunks/poison-rules-DoEhbqaY.js.map +1 -0
  41. package/dist/_chunks/poison-scan-BAxfTT5L.js +101 -0
  42. package/dist/_chunks/poison-scan-BAxfTT5L.js.map +1 -0
  43. package/dist/_chunks/resolve-schema-CBR6Lm4i.js.map +1 -1
  44. package/dist/_chunks/rolldown-runtime-D7D4PA-g.js +13 -0
  45. package/dist/_chunks/router-ref-DuYuV_0Q.js.map +1 -1
  46. package/dist/_chunks/{rsc-media-type-DRqE_lD_.js → rsc-media-type-DDc7duTD.js} +17 -2
  47. package/dist/_chunks/{rsc-media-type-DRqE_lD_.js.map → rsc-media-type-DDc7duTD.js.map} +1 -1
  48. package/dist/_chunks/scan-BoP17W3w.js +140 -0
  49. package/dist/_chunks/scan-BoP17W3w.js.map +1 -0
  50. package/dist/_chunks/{scanner-CAietmj4.js → scanner-BRIOmHE2.js} +43 -4
  51. package/dist/_chunks/scanner-BRIOmHE2.js.map +1 -0
  52. package/dist/_chunks/schema-bridge-C83xa9lT.js.map +1 -1
  53. package/dist/_chunks/segment-classify-C539Pa2O.js.map +1 -1
  54. package/dist/_chunks/{segment-keys-BawYuNFO.js → segment-keys-BhqoHiLc.js} +14 -2
  55. package/dist/_chunks/{segment-keys-BawYuNFO.js.map → segment-keys-BhqoHiLc.js.map} +1 -1
  56. package/dist/_chunks/slot-params-BCTmZkQB.js.map +1 -1
  57. package/dist/_chunks/ssr-data-14MXm7Pj.js.map +1 -1
  58. package/dist/_chunks/use-query-states-I3JMng6J.js.map +1 -1
  59. package/dist/_chunks/use-segment-params-C4r4BD9T.js.map +1 -1
  60. package/dist/_chunks/{walkers-BsVLmD1S.js → walkers-uCu3WW6_.js} +9 -6
  61. package/dist/_chunks/{walkers-BsVLmD1S.js.map → walkers-uCu3WW6_.js.map} +1 -1
  62. package/dist/adapters/build-output-helper.d.ts +1 -1
  63. package/dist/adapters/build-output-helper.d.ts.map +1 -1
  64. package/dist/adapters/cloudflare-dev.d.ts.map +1 -1
  65. package/dist/adapters/cloudflare-dev.js +2 -1
  66. package/dist/adapters/cloudflare-dev.js.map +1 -1
  67. package/dist/adapters/cloudflare-kv-cache.d.ts +1 -1
  68. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -1
  69. package/dist/adapters/cloudflare-kv-cache.js +7 -8
  70. package/dist/adapters/cloudflare-kv-cache.js.map +1 -1
  71. package/dist/adapters/cloudflare.d.ts +1 -1
  72. package/dist/adapters/cloudflare.d.ts.map +1 -1
  73. package/dist/adapters/cloudflare.js +1 -1
  74. package/dist/adapters/nitro-presets.d.ts +37 -0
  75. package/dist/adapters/nitro-presets.d.ts.map +1 -0
  76. package/dist/adapters/nitro-preview.d.ts +32 -0
  77. package/dist/adapters/nitro-preview.d.ts.map +1 -0
  78. package/dist/adapters/nitro.d.ts +28 -51
  79. package/dist/adapters/nitro.d.ts.map +1 -1
  80. package/dist/adapters/nitro.js +224 -171
  81. package/dist/adapters/nitro.js.map +1 -1
  82. package/dist/analyze/chains.d.ts +124 -0
  83. package/dist/analyze/chains.d.ts.map +1 -0
  84. package/dist/analyze/classify.d.ts +150 -0
  85. package/dist/analyze/classify.d.ts.map +1 -0
  86. package/dist/analyze/crawl-entry.d.ts +17 -0
  87. package/dist/analyze/crawl-entry.d.ts.map +1 -0
  88. package/dist/analyze/crawl-entry.js +313 -0
  89. package/dist/analyze/crawl-entry.js.map +1 -0
  90. package/dist/analyze/crawl.d.ts +134 -0
  91. package/dist/analyze/crawl.d.ts.map +1 -0
  92. package/dist/analyze/graph-cache.d.ts +104 -0
  93. package/dist/analyze/graph-cache.d.ts.map +1 -0
  94. package/dist/analyze/graph-command.d.ts +43 -0
  95. package/dist/analyze/graph-command.d.ts.map +1 -0
  96. package/dist/analyze/graph-command.js +472 -0
  97. package/dist/analyze/graph-command.js.map +1 -0
  98. package/dist/analyze/live-graph.d.ts +81 -0
  99. package/dist/analyze/live-graph.d.ts.map +1 -0
  100. package/dist/analyze/poison-rules.d.ts +72 -0
  101. package/dist/analyze/poison-rules.d.ts.map +1 -0
  102. package/dist/analyze/poison-scan.d.ts +48 -0
  103. package/dist/analyze/poison-scan.d.ts.map +1 -0
  104. package/dist/analyze/scan.d.ts +73 -0
  105. package/dist/analyze/scan.d.ts.map +1 -0
  106. package/dist/cache/cache-api.d.ts +2 -2
  107. package/dist/cache/cache-api.d.ts.map +1 -1
  108. package/dist/cache/index.d.ts +8 -8
  109. package/dist/cache/index.d.ts.map +1 -1
  110. package/dist/cache/index.js +1 -1
  111. package/dist/cache/redis-handler.d.ts +1 -1
  112. package/dist/cache/redis-handler.d.ts.map +1 -1
  113. package/dist/cache/stores/cloudflare-kv.d.ts +1 -1
  114. package/dist/cache/stores/cloudflare-kv.d.ts.map +1 -1
  115. package/dist/cache/stores/cloudflare-kv.js.map +1 -1
  116. package/dist/cache/stores/memory.d.ts +1 -1
  117. package/dist/cache/stores/memory.d.ts.map +1 -1
  118. package/dist/cache/stores/memory.js.map +1 -1
  119. package/dist/cache/stores/redis.d.ts +1 -1
  120. package/dist/cache/stores/redis.d.ts.map +1 -1
  121. package/dist/cache/stores/redis.js.map +1 -1
  122. package/dist/cache/stores/vercel.d.ts +1 -1
  123. package/dist/cache/stores/vercel.d.ts.map +1 -1
  124. package/dist/cache/stores/vercel.js.map +1 -1
  125. package/dist/cache/tag-aware-handler.d.ts +2 -2
  126. package/dist/cache/tag-aware-handler.d.ts.map +1 -1
  127. package/dist/cache/timber-cache.d.ts +1 -1
  128. package/dist/cache/timber-cache.d.ts.map +1 -1
  129. package/dist/cdn/cloudflare-purge.d.ts +1 -1
  130. package/dist/cdn/cloudflare-purge.d.ts.map +1 -1
  131. package/dist/cdn/cloudflare-purge.js.map +1 -1
  132. package/dist/cdn/fastly-purge.d.ts +1 -1
  133. package/dist/cdn/fastly-purge.d.ts.map +1 -1
  134. package/dist/cdn/fastly-purge.js.map +1 -1
  135. package/dist/cdn/index.d.ts +4 -4
  136. package/dist/cdn/index.d.ts.map +1 -1
  137. package/dist/cdn/workers-cache-purge.d.ts +5 -1
  138. package/dist/cdn/workers-cache-purge.d.ts.map +1 -1
  139. package/dist/cdn/workers-cache-purge.js.map +1 -1
  140. package/dist/cli-check.d.ts +10 -0
  141. package/dist/cli-check.d.ts.map +1 -1
  142. package/dist/cli.d.ts +12 -4
  143. package/dist/cli.d.ts.map +1 -1
  144. package/dist/cli.js +30 -6
  145. package/dist/cli.js.map +1 -1
  146. package/dist/client/browser-entry/hydrate.d.ts +2 -2
  147. package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
  148. package/dist/client/browser-entry/post-hydration.d.ts +2 -2
  149. package/dist/client/browser-entry/router-init.d.ts +2 -2
  150. package/dist/client/browser-entry/rsc-stream.d.ts +1 -1
  151. package/dist/client/form.d.ts +2 -2
  152. package/dist/client/form.d.ts.map +1 -1
  153. package/dist/client/history.d.ts +2 -2
  154. package/dist/client/index.d.ts +18 -18
  155. package/dist/client/index.d.ts.map +1 -1
  156. package/dist/client/index.js.map +1 -1
  157. package/dist/client/internal.d.ts +19 -19
  158. package/dist/client/internal.d.ts.map +1 -1
  159. package/dist/client/internal.js +11 -15
  160. package/dist/client/internal.js.map +1 -1
  161. package/dist/client/link.d.ts +3 -3
  162. package/dist/client/navigation-commit.d.ts +5 -5
  163. package/dist/client/navigation-root.d.ts +1 -1
  164. package/dist/client/navigation-root.d.ts.map +1 -1
  165. package/dist/client/params-context.d.ts +3 -3
  166. package/dist/client/router-pipeline.d.ts +7 -7
  167. package/dist/client/router-ref.d.ts +1 -1
  168. package/dist/client/router-types.d.ts +6 -6
  169. package/dist/client/router-types.d.ts.map +1 -1
  170. package/dist/client/router.d.ts +1 -1
  171. package/dist/client/rsc-fetch.d.ts +4 -4
  172. package/dist/client/rsc-fetch.d.ts.map +1 -1
  173. package/dist/client/segment-cache.d.ts +2 -2
  174. package/dist/client/slot-provider.d.ts +1 -1
  175. package/dist/client/ssr-data.d.ts +2 -2
  176. package/dist/client/state.d.ts +4 -4
  177. package/dist/client/use-query-states.d.ts +1 -1
  178. package/dist/client/use-segment-params.d.ts +3 -3
  179. package/dist/codec.d.ts +2 -2
  180. package/dist/codec.js.map +1 -1
  181. package/dist/config-types.d.ts +24 -6
  182. package/dist/config-types.d.ts.map +1 -1
  183. package/dist/config-validation.d.ts +1 -1
  184. package/dist/cookies/define-cookie.d.ts +3 -3
  185. package/dist/cookies/index.d.ts +3 -3
  186. package/dist/cookies/index.js +3 -4
  187. package/dist/cookies/index.js.map +1 -1
  188. package/dist/cookies/json-cookie.d.ts +1 -1
  189. package/dist/dev-tools/404-page.d.ts +2 -2
  190. package/dist/dev-tools/error-page.d.ts +2 -2
  191. package/dist/dev-tools/index.d.ts +12 -12
  192. package/dist/dev-tools/instrumentation.d.ts +1 -1
  193. package/dist/dev-tools/logs.d.ts +1 -1
  194. package/dist/dev-tools/overlay.d.ts +2 -2
  195. package/dist/dev-tools/terminal.d.ts +1 -1
  196. package/dist/fonts/ast.d.ts +4 -4
  197. package/dist/fonts/bundle.d.ts +3 -3
  198. package/dist/fonts/css.d.ts +1 -1
  199. package/dist/fonts/dev-middleware.d.ts +1 -1
  200. package/dist/fonts/google.d.ts +1 -1
  201. package/dist/fonts/local.d.ts +1 -1
  202. package/dist/fonts/pipeline.d.ts +3 -3
  203. package/dist/fonts/transform.d.ts +2 -2
  204. package/dist/fonts/types.d.ts +1 -1
  205. package/dist/fonts/virtual-modules.d.ts +1 -1
  206. package/dist/index.d.ts +3 -3
  207. package/dist/index.d.ts.map +1 -1
  208. package/dist/index.js +816 -310
  209. package/dist/index.js.map +1 -1
  210. package/dist/params/codec-registry.d.ts +1 -1
  211. package/dist/params/define-schema.d.ts +2 -2
  212. package/dist/params/index.d.ts +4 -4
  213. package/dist/params/index.js.map +1 -1
  214. package/dist/params/resolve-schema.d.ts +1 -1
  215. package/dist/plugin-context.d.ts +9 -9
  216. package/dist/plugin-context.d.ts.map +1 -1
  217. package/dist/plugins/adapter-build.d.ts +2 -2
  218. package/dist/plugins/build-manifest.d.ts +2 -2
  219. package/dist/plugins/build-report.d.ts +5 -5
  220. package/dist/plugins/cache.d.ts +1 -1
  221. package/dist/plugins/callsite-jsx.d.ts +2 -2
  222. package/dist/plugins/chunks.d.ts +1 -1
  223. package/dist/plugins/chunks.d.ts.map +1 -1
  224. package/dist/plugins/cloudflare-wasm.d.ts +1 -1
  225. package/dist/plugins/content.d.ts +1 -1
  226. package/dist/plugins/content.d.ts.map +1 -1
  227. package/dist/plugins/dev-discovery.d.ts +123 -0
  228. package/dist/plugins/dev-discovery.d.ts.map +1 -0
  229. package/dist/plugins/dev-server.d.ts +1 -1
  230. package/dist/plugins/dev-server.d.ts.map +1 -1
  231. package/dist/plugins/entries.d.ts +1 -1
  232. package/dist/plugins/fonts.d.ts +3 -3
  233. package/dist/plugins/fonts.d.ts.map +1 -1
  234. package/dist/plugins/graph-endpoint.d.ts +112 -0
  235. package/dist/plugins/graph-endpoint.d.ts.map +1 -0
  236. package/dist/plugins/mdx.d.ts +18 -5
  237. package/dist/plugins/mdx.d.ts.map +1 -1
  238. package/dist/plugins/prebuilt-capture.d.ts +2 -2
  239. package/dist/plugins/prebuilt-options-analysis.d.ts +1 -1
  240. package/dist/plugins/prebuilt.d.ts +1 -1
  241. package/dist/plugins/prerender-sugar.d.ts +11 -14
  242. package/dist/plugins/prerender-sugar.d.ts.map +1 -1
  243. package/dist/plugins/request-dep/analysis.d.ts +1 -1
  244. package/dist/plugins/request-dep/index.d.ts +5 -5
  245. package/dist/plugins/request-dep/origin.d.ts +1 -1
  246. package/dist/plugins/routing.d.ts +1 -1
  247. package/dist/plugins/routing.d.ts.map +1 -1
  248. package/dist/plugins/server-bundle.d.ts.map +1 -1
  249. package/dist/plugins/shims.d.ts +1 -1
  250. package/dist/plugins/shims.d.ts.map +1 -1
  251. package/dist/plugins/static-build.d.ts +5 -5
  252. package/dist/routing/codegen-shared.d.ts +1 -1
  253. package/dist/routing/codegen-write.d.ts +1 -1
  254. package/dist/routing/codegen.d.ts +1 -1
  255. package/dist/routing/collision-probe.d.ts +1 -1
  256. package/dist/routing/collision-spaces.d.ts +1 -1
  257. package/dist/routing/convention-lint.d.ts +1 -1
  258. package/dist/routing/convention-lint.d.ts.map +1 -1
  259. package/dist/routing/index.d.ts +13 -13
  260. package/dist/routing/index.js +3 -3
  261. package/dist/routing/interception.d.ts +1 -1
  262. package/dist/routing/interception.d.ts.map +1 -1
  263. package/dist/routing/link-codegen.d.ts +1 -1
  264. package/dist/routing/manifest-codegen.d.ts +1 -1
  265. package/dist/routing/scanner.d.ts +14 -1
  266. package/dist/routing/scanner.d.ts.map +1 -1
  267. package/dist/routing/schema-validation.d.ts +1 -1
  268. package/dist/routing/segment-classify.d.ts +1 -1
  269. package/dist/routing/segment-codegen.d.ts +1 -1
  270. package/dist/routing/segment-keys.d.ts +1 -1
  271. package/dist/routing/slot-placement.d.ts +1 -1
  272. package/dist/routing/walkers.d.ts +1 -1
  273. package/dist/rsc-runtime/transforms.d.ts +13 -0
  274. package/dist/rsc-runtime/transforms.d.ts.map +1 -0
  275. package/dist/schema-bridge.d.ts +1 -1
  276. package/dist/search-params/define.d.ts +3 -3
  277. package/dist/search-params/index.d.ts +3 -3
  278. package/dist/search-params/index.js.map +1 -1
  279. package/dist/search-params/wrappers.d.ts +1 -1
  280. package/dist/server/access-gate.d.ts +1 -1
  281. package/dist/server/action-client.d.ts +1 -1
  282. package/dist/server/action-handler.d.ts +5 -5
  283. package/dist/server/actions.d.ts +2 -2
  284. package/dist/server/als-registry.d.ts +8 -8
  285. package/dist/server/asset-headers.d.ts +1 -1
  286. package/dist/server/chain-url-parts.d.ts +3 -3
  287. package/dist/server/children-interception.d.ts +2 -2
  288. package/dist/server/cookie-context.d.ts +1 -1
  289. package/dist/server/cookie-parsing.d.ts +2 -2
  290. package/dist/server/default-logger.d.ts +1 -1
  291. package/dist/server/deny-boundary.d.ts +2 -2
  292. package/dist/server/deny-renderer.d.ts +5 -5
  293. package/dist/server/early-hints.d.ts +1 -1
  294. package/dist/server/error-boundary-wrapper.d.ts +2 -4
  295. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  296. package/dist/server/fallback-error.d.ts +5 -5
  297. package/dist/server/flight-injection-state.d.ts +1 -1
  298. package/dist/server/form-flash.d.ts +1 -1
  299. package/dist/server/html-injector-core.d.ts +2 -2
  300. package/dist/server/html-injectors.d.ts +1 -1
  301. package/dist/server/index.d.ts +18 -18
  302. package/dist/server/index.d.ts.map +1 -1
  303. package/dist/server/index.js +33 -32
  304. package/dist/server/index.js.map +1 -1
  305. package/dist/server/instrumentation.d.ts +1 -1
  306. package/dist/server/internal.d.ts +50 -50
  307. package/dist/server/internal.d.ts.map +1 -1
  308. package/dist/server/internal.js +1023 -1025
  309. package/dist/server/internal.js.map +1 -1
  310. package/dist/server/metadata-collector.d.ts +2 -2
  311. package/dist/server/metadata-platform.d.ts +2 -2
  312. package/dist/server/metadata-render.d.ts +2 -2
  313. package/dist/server/metadata-routes.d.ts +3 -3
  314. package/dist/server/metadata-social.d.ts +2 -2
  315. package/dist/server/metadata.d.ts +2 -2
  316. package/dist/server/middleware-runner.d.ts +1 -1
  317. package/dist/server/node-stream-transforms.d.ts +1 -1
  318. package/dist/server/param-coercion.d.ts +4 -4
  319. package/dist/server/pipeline-helpers.d.ts +3 -3
  320. package/dist/server/pipeline-interception.d.ts +1 -1
  321. package/dist/server/pipeline-metadata.d.ts +1 -1
  322. package/dist/server/pipeline-outcome.d.ts +2 -2
  323. package/dist/server/pipeline-phases.d.ts +3 -3
  324. package/dist/server/pipeline-phases.d.ts.map +1 -1
  325. package/dist/server/pipeline.d.ts +9 -9
  326. package/dist/server/prebuilt/cache-key.d.ts +1 -1
  327. package/dist/server/prebuilt/capture-state.d.ts +1 -1
  328. package/dist/server/prebuilt/key-discipline.d.ts +1 -1
  329. package/dist/server/prebuilt/manifest-tag-index.d.ts +1 -1
  330. package/dist/server/prebuilt/overlay.d.ts +2 -2
  331. package/dist/server/prebuilt/payload-source.d.ts +1 -1
  332. package/dist/server/prebuilt/slots.d.ts +1 -1
  333. package/dist/server/prebuilt/synthetic-store.d.ts +2 -2
  334. package/dist/server/prebuilt-builder.d.ts +2 -2
  335. package/dist/server/primitives.d.ts +2 -2
  336. package/dist/server/publish-params.d.ts +1 -1
  337. package/dist/server/request-context.d.ts +3 -3
  338. package/dist/server/route-element-builder.d.ts +16 -6
  339. package/dist/server/route-element-builder.d.ts.map +1 -1
  340. package/dist/server/route-handler.d.ts +1 -1
  341. package/dist/server/route-matcher.d.ts +4 -4
  342. package/dist/server/rsc-cache-key-guard.d.ts.map +1 -1
  343. package/dist/server/rsc-entry/action-middleware-runner.d.ts +2 -2
  344. package/dist/server/rsc-entry/api-handler.d.ts +1 -1
  345. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  346. package/dist/server/rsc-entry/deny-fallback.d.ts +3 -3
  347. package/dist/server/rsc-entry/error-renderer.d.ts +4 -4
  348. package/dist/server/rsc-entry/helpers.d.ts +6 -6
  349. package/dist/server/rsc-entry/index.d.ts +7 -6
  350. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  351. package/dist/server/rsc-entry/render-route.d.ts +4 -4
  352. package/dist/server/rsc-entry/revalidate-renderer.d.ts +4 -4
  353. package/dist/server/rsc-entry/rsc-payload.d.ts +4 -4
  354. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  355. package/dist/server/rsc-entry/rsc-stream.d.ts +3 -3
  356. package/dist/server/rsc-entry/ssr-bridge.d.ts +1 -1
  357. package/dist/server/rsc-entry/ssr-renderer.d.ts +7 -7
  358. package/dist/server/rsc-entry/wrap-action-dispatch.d.ts +5 -5
  359. package/dist/server/sitemap-generator.d.ts +2 -2
  360. package/dist/server/sitemap-handler.d.ts +1 -1
  361. package/dist/server/skippable-prefix.d.ts +3 -3
  362. package/dist/server/slot-interception.d.ts +2 -2
  363. package/dist/server/slot-resolver.d.ts +3 -7
  364. package/dist/server/slot-resolver.d.ts.map +1 -1
  365. package/dist/server/ssr-bridge-types.d.ts +2 -2
  366. package/dist/server/ssr-entry.d.ts +1 -1
  367. package/dist/server/static-generator.d.ts +1 -1
  368. package/dist/server/static-not-found.d.ts +1 -1
  369. package/dist/server/status-code-resolver.d.ts +1 -1
  370. package/dist/server/tracing.d.ts +3 -3
  371. package/dist/server/tree-builder.d.ts +3 -3
  372. package/dist/server/tree-match.d.ts +1 -1
  373. package/dist/server/types.d.ts +2 -2
  374. package/dist/server/utils/mdx-file.d.ts +2 -0
  375. package/dist/server/utils/mdx-file.d.ts.map +1 -1
  376. package/dist/server/workers-cache-bridge.d.ts +1 -1
  377. package/dist/shared/als-slots.d.ts +1 -1
  378. package/dist/shared/payload-root.d.ts +2 -2
  379. package/dist/shared/rsc-media-type.d.ts +12 -0
  380. package/dist/shared/rsc-media-type.d.ts.map +1 -1
  381. package/dist/shared/slot-params.d.ts +1 -1
  382. package/dist/shims/font-google.d.ts +1 -1
  383. package/dist/shims/font-google.js.map +1 -1
  384. package/dist/shims/font-local.d.ts +1 -1
  385. package/dist/shims/font-local.js.map +1 -1
  386. package/dist/shims/navigation-client.d.ts +4 -4
  387. package/dist/shims/navigation.d.ts +2 -2
  388. package/docs/api/34-api-config.mdx +9 -8
  389. package/docs/api/36-cli.mdx +23 -3
  390. package/docs/learn/11-error-handling.mdx +11 -0
  391. package/docs/more/01-advanced-routing.mdx +1 -0
  392. package/docs/more/04b-mdx.mdx +38 -18
  393. package/package.json +23 -18
  394. package/src/adapters/build-output-helper.ts +4 -4
  395. package/src/adapters/cloudflare-dev.ts +7 -1
  396. package/src/adapters/cloudflare-kv-cache.ts +11 -8
  397. package/src/adapters/cloudflare.ts +21 -15
  398. package/src/adapters/compress-module.ts +2 -2
  399. package/src/adapters/nitro-presets.ts +139 -0
  400. package/src/adapters/nitro-preview.ts +340 -0
  401. package/src/adapters/nitro.ts +100 -465
  402. package/src/adapters/shared.ts +1 -1
  403. package/src/analyze/chains.ts +411 -0
  404. package/src/analyze/classify.ts +258 -0
  405. package/src/analyze/crawl-entry.ts +68 -0
  406. package/src/analyze/crawl.ts +500 -0
  407. package/src/analyze/graph-cache.ts +332 -0
  408. package/src/analyze/graph-command.ts +762 -0
  409. package/src/analyze/live-graph.ts +232 -0
  410. package/src/analyze/poison-rules.ts +165 -0
  411. package/src/analyze/poison-scan.ts +162 -0
  412. package/src/analyze/scan.ts +149 -0
  413. package/src/cache/cache-api.ts +7 -7
  414. package/src/cache/index.ts +9 -9
  415. package/src/cache/redis-handler.ts +2 -2
  416. package/src/cache/stores/cloudflare-kv.ts +1 -1
  417. package/src/cache/stores/memory.ts +2 -2
  418. package/src/cache/stores/redis.ts +1 -1
  419. package/src/cache/stores/vercel.ts +1 -1
  420. package/src/cache/tag-aware-handler.ts +2 -2
  421. package/src/cache/timber-cache.ts +8 -8
  422. package/src/cdn/cloudflare-purge.ts +1 -1
  423. package/src/cdn/fastly-purge.ts +1 -1
  424. package/src/cdn/index.ts +10 -4
  425. package/src/cdn/workers-cache-purge.ts +6 -2
  426. package/src/cli-check.ts +53 -4
  427. package/src/cli-schema-sync.ts +3 -3
  428. package/src/cli.ts +50 -11
  429. package/src/client/browser-dev.ts +1 -1
  430. package/src/client/browser-entry/action-dispatch.ts +5 -5
  431. package/src/client/browser-entry/hmr.ts +1 -1
  432. package/src/client/browser-entry/hydrate.ts +9 -9
  433. package/src/client/browser-entry/index.ts +10 -10
  434. package/src/client/browser-entry/post-hydration.ts +5 -5
  435. package/src/client/browser-entry/router-init.ts +9 -9
  436. package/src/client/browser-entry/rsc-stream.ts +3 -3
  437. package/src/client/error-boundary.tsx +4 -4
  438. package/src/client/form.tsx +7 -2
  439. package/src/client/history.ts +2 -2
  440. package/src/client/index.ts +21 -18
  441. package/src/client/internal.ts +19 -19
  442. package/src/client/link.tsx +9 -9
  443. package/src/client/navigation-api.ts +1 -1
  444. package/src/client/navigation-commit.ts +5 -5
  445. package/src/client/navigation-context.ts +1 -1
  446. package/src/client/navigation-root.tsx +1 -1
  447. package/src/client/nuqs-adapter.tsx +2 -2
  448. package/src/client/params-context.ts +4 -4
  449. package/src/client/router-effects.ts +3 -3
  450. package/src/client/router-lifecycle.ts +2 -2
  451. package/src/client/router-pipeline.ts +10 -10
  452. package/src/client/router-ref.ts +2 -2
  453. package/src/client/router-skew.ts +2 -2
  454. package/src/client/router-types.ts +6 -6
  455. package/src/client/router.ts +13 -13
  456. package/src/client/rsc-fetch.ts +11 -16
  457. package/src/client/segment-cache.ts +2 -2
  458. package/src/client/segment-outlet.tsx +1 -1
  459. package/src/client/shallow-url.ts +1 -1
  460. package/src/client/slot-outlet.tsx +1 -1
  461. package/src/client/slot-provider.tsx +1 -1
  462. package/src/client/ssr-data.ts +3 -3
  463. package/src/client/stale-client.ts +1 -1
  464. package/src/client/state.ts +4 -4
  465. package/src/client/top-loader.tsx +1 -1
  466. package/src/client/unload-guard.ts +1 -1
  467. package/src/client/use-cookie.ts +2 -2
  468. package/src/client/use-pathname.ts +2 -2
  469. package/src/client/use-pending-navigation.ts +1 -1
  470. package/src/client/use-query-states.ts +3 -3
  471. package/src/client/use-router.ts +2 -2
  472. package/src/client/use-search-params.ts +3 -3
  473. package/src/client/use-segment-params.ts +6 -6
  474. package/src/client/use-selected-layout-segment.ts +2 -2
  475. package/src/codec.ts +2 -2
  476. package/src/config-types.ts +27 -7
  477. package/src/config-validation.ts +1 -1
  478. package/src/cookies/define-cookie.ts +6 -6
  479. package/src/cookies/index.ts +3 -3
  480. package/src/cookies/json-cookie.ts +1 -1
  481. package/src/dev-tools/404-page.ts +4 -4
  482. package/src/dev-tools/dev-page-shell.ts +1 -1
  483. package/src/dev-tools/error-page.ts +4 -4
  484. package/src/dev-tools/index.ts +12 -12
  485. package/src/dev-tools/instrumentation.ts +1 -1
  486. package/src/dev-tools/logs.ts +1 -1
  487. package/src/dev-tools/overlay.ts +3 -3
  488. package/src/dev-tools/terminal.ts +2 -2
  489. package/src/fonts/ast.ts +5 -5
  490. package/src/fonts/bundle.ts +5 -5
  491. package/src/fonts/css.ts +1 -1
  492. package/src/fonts/dev-middleware.ts +2 -2
  493. package/src/fonts/google.ts +2 -2
  494. package/src/fonts/local.ts +4 -4
  495. package/src/fonts/pipeline.ts +8 -8
  496. package/src/fonts/transform.ts +5 -5
  497. package/src/fonts/types.ts +1 -1
  498. package/src/fonts/virtual-modules.ts +1 -1
  499. package/src/index.ts +46 -37
  500. package/src/params/codec-registry.ts +1 -1
  501. package/src/params/define-schema.ts +2 -2
  502. package/src/params/index.ts +4 -4
  503. package/src/params/resolve-schema.ts +2 -2
  504. package/src/plugin-context.ts +10 -10
  505. package/src/plugins/adapter-build.ts +5 -5
  506. package/src/plugins/build-manifest.ts +4 -4
  507. package/src/plugins/build-report.ts +6 -6
  508. package/src/plugins/cache.ts +3 -3
  509. package/src/plugins/callsite-ast.ts +1 -1
  510. package/src/plugins/callsite-jsx.ts +2 -2
  511. package/src/plugins/chunks.ts +1 -1
  512. package/src/plugins/cloudflare-wasm.ts +1 -1
  513. package/src/plugins/content.ts +5 -1
  514. package/src/plugins/dev-discovery.ts +218 -0
  515. package/src/plugins/dev-server.ts +97 -12
  516. package/src/plugins/entries.ts +1 -1
  517. package/src/plugins/fonts.ts +17 -10
  518. package/src/plugins/graph-endpoint.ts +532 -0
  519. package/src/plugins/mdx.ts +73 -38
  520. package/src/plugins/prebuilt-capture.ts +3 -3
  521. package/src/plugins/prebuilt-options-analysis.ts +1 -1
  522. package/src/plugins/prebuilt.ts +7 -7
  523. package/src/plugins/prerender-sugar.ts +11 -19
  524. package/src/plugins/request-dep/analysis.ts +1 -1
  525. package/src/plugins/request-dep/index.ts +8 -8
  526. package/src/plugins/request-dep/origin.ts +1 -1
  527. package/src/plugins/routing.ts +12 -7
  528. package/src/plugins/server-bundle.ts +11 -3
  529. package/src/plugins/shims.ts +16 -31
  530. package/src/plugins/static-build.ts +10 -10
  531. package/src/routing/codegen-shared.ts +1 -1
  532. package/src/routing/codegen-write.ts +3 -3
  533. package/src/routing/codegen.ts +14 -5
  534. package/src/routing/collision-probe.ts +3 -3
  535. package/src/routing/collision-spaces.ts +3 -3
  536. package/src/routing/convention-lint.ts +136 -6
  537. package/src/routing/export-detect.ts +1 -1
  538. package/src/routing/index.ts +13 -13
  539. package/src/routing/interception.ts +41 -4
  540. package/src/routing/link-codegen.ts +3 -3
  541. package/src/routing/manifest-codegen.ts +2 -2
  542. package/src/routing/scanner.ts +33 -9
  543. package/src/routing/schema-validation.ts +4 -4
  544. package/src/routing/segment-classify.ts +2 -2
  545. package/src/routing/segment-codegen.ts +1 -1
  546. package/src/routing/segment-keys.ts +1 -1
  547. package/src/routing/slot-placement.ts +1 -1
  548. package/src/routing/walkers.ts +1 -1
  549. package/src/rsc-runtime/transforms.ts +13 -0
  550. package/src/rsc-runtime/vendor-types.d.ts +12 -0
  551. package/src/schema-bridge.ts +1 -1
  552. package/src/search-params/define.ts +8 -8
  553. package/src/search-params/index.ts +3 -3
  554. package/src/search-params/wrappers.ts +3 -3
  555. package/src/server/access-gate.tsx +6 -6
  556. package/src/server/action-client.ts +5 -5
  557. package/src/server/action-handler.ts +16 -16
  558. package/src/server/actions.ts +5 -5
  559. package/src/server/als-registry.ts +8 -8
  560. package/src/server/asset-headers.ts +2 -2
  561. package/src/server/chain-url-parts.ts +5 -5
  562. package/src/server/children-interception.ts +4 -4
  563. package/src/server/compress.ts +1 -1
  564. package/src/server/cookie-context.ts +4 -4
  565. package/src/server/cookie-parsing.ts +2 -2
  566. package/src/server/default-logger.ts +3 -3
  567. package/src/server/deny-boundary.ts +10 -10
  568. package/src/server/deny-renderer.ts +38 -25
  569. package/src/server/early-hints-sender.ts +2 -2
  570. package/src/server/early-hints.ts +2 -2
  571. package/src/server/error-boundary-wrapper.ts +4 -12
  572. package/src/server/fallback-error.ts +13 -13
  573. package/src/server/flight-injection-state.ts +1 -1
  574. package/src/server/form-flash.ts +2 -2
  575. package/src/server/html-injector-core.ts +4 -4
  576. package/src/server/html-injectors.ts +5 -5
  577. package/src/server/index.ts +18 -18
  578. package/src/server/instrumentation.ts +1 -1
  579. package/src/server/internal.ts +50 -50
  580. package/src/server/logger.ts +4 -4
  581. package/src/server/metadata-collector.ts +7 -7
  582. package/src/server/metadata-platform.ts +2 -2
  583. package/src/server/metadata-render.ts +4 -4
  584. package/src/server/metadata-routes.ts +3 -3
  585. package/src/server/metadata-social.ts +2 -2
  586. package/src/server/metadata.ts +2 -2
  587. package/src/server/middleware-runner.ts +1 -1
  588. package/src/server/node-stream-transforms.ts +4 -4
  589. package/src/server/param-coercion.ts +8 -8
  590. package/src/server/pipeline-helpers.ts +7 -7
  591. package/src/server/pipeline-interception.ts +2 -2
  592. package/src/server/pipeline-metadata.ts +1 -1
  593. package/src/server/pipeline-outcome.ts +8 -8
  594. package/src/server/pipeline-phases.ts +24 -28
  595. package/src/server/pipeline.ts +22 -22
  596. package/src/server/prebuilt/cache-key.ts +1 -1
  597. package/src/server/prebuilt/capture-state.ts +1 -1
  598. package/src/server/prebuilt/key-discipline.ts +1 -1
  599. package/src/server/prebuilt/manifest-tag-index.ts +1 -1
  600. package/src/server/prebuilt/overlay.ts +6 -6
  601. package/src/server/prebuilt/payload-source.ts +2 -2
  602. package/src/server/prebuilt/slots.ts +5 -5
  603. package/src/server/prebuilt/synthetic-store.ts +2 -2
  604. package/src/server/prebuilt-builder.ts +16 -16
  605. package/src/server/prebuilt-runtime.ts +12 -12
  606. package/src/server/primitives.ts +7 -7
  607. package/src/server/publish-params.ts +3 -3
  608. package/src/server/request-context.ts +7 -7
  609. package/src/server/route-element-builder.ts +108 -50
  610. package/src/server/route-handler.ts +4 -4
  611. package/src/server/route-matcher.ts +5 -5
  612. package/src/server/rsc-cache-key-guard.ts +3 -5
  613. package/src/server/rsc-entry/action-middleware-runner.ts +7 -7
  614. package/src/server/rsc-entry/api-handler.ts +18 -9
  615. package/src/server/rsc-entry/deny-fallback.ts +10 -10
  616. package/src/server/rsc-entry/error-renderer.ts +27 -27
  617. package/src/server/rsc-entry/helpers.ts +10 -10
  618. package/src/server/rsc-entry/index.ts +51 -47
  619. package/src/server/rsc-entry/render-route.ts +20 -20
  620. package/src/server/rsc-entry/revalidate-renderer.ts +12 -12
  621. package/src/server/rsc-entry/rsc-payload.ts +19 -15
  622. package/src/server/rsc-entry/rsc-stream.ts +8 -8
  623. package/src/server/rsc-entry/ssr-bridge.ts +3 -3
  624. package/src/server/rsc-entry/ssr-renderer.ts +23 -23
  625. package/src/server/rsc-entry/wrap-action-dispatch.ts +9 -9
  626. package/src/server/rsc-prop-warnings.ts +1 -1
  627. package/src/server/sensitive-fields.ts +1 -1
  628. package/src/server/server-timing.ts +1 -1
  629. package/src/server/sitemap-generator.ts +3 -3
  630. package/src/server/sitemap-handler.ts +3 -3
  631. package/src/server/skippable-prefix.ts +7 -7
  632. package/src/server/slot-interception.ts +5 -5
  633. package/src/server/slot-resolver.ts +20 -28
  634. package/src/server/ssr-bridge-types.ts +2 -2
  635. package/src/server/ssr-entry.ts +18 -18
  636. package/src/server/ssr-render.ts +4 -4
  637. package/src/server/ssr-wrappers.tsx +1 -1
  638. package/src/server/state-tree-diff.ts +1 -1
  639. package/src/server/static-generator.ts +6 -6
  640. package/src/server/static-not-found.ts +3 -3
  641. package/src/server/status-code-resolver.ts +1 -1
  642. package/src/server/tracing.ts +5 -5
  643. package/src/server/tree-builder.ts +4 -4
  644. package/src/server/tree-match.ts +1 -1
  645. package/src/server/types.ts +2 -2
  646. package/src/server/utils/mdx-file.ts +2 -2
  647. package/src/server/waituntil-bridge.ts +1 -1
  648. package/src/server/workers-cache-bridge.ts +2 -2
  649. package/src/shared/als-slots.ts +1 -1
  650. package/src/shared/payload-root.ts +2 -2
  651. package/src/shared/rsc-media-type.ts +16 -0
  652. package/src/shared/slot-params.ts +1 -1
  653. package/src/shims/font-google.ts +1 -1
  654. package/src/shims/font-local.ts +1 -1
  655. package/src/shims/navigation-client.ts +5 -5
  656. package/src/shims/navigation.ts +2 -2
  657. package/LICENSE +0 -8
  658. package/dist/_chunks/actions-BjbbNRFN.js.map +0 -1
  659. package/dist/_chunks/build-output-helper-C3DrfzZR.js.map +0 -1
  660. package/dist/_chunks/cache-api-DllJ-Lyw.js.map +0 -1
  661. package/dist/_chunks/cli-check-DJZDc22E.js.map +0 -1
  662. package/dist/_chunks/convention-lint-CpteIpTm.js.map +0 -1
  663. package/dist/_chunks/dist-BA3u1z3W.js +0 -423
  664. package/dist/_chunks/dist-BA3u1z3W.js.map +0 -1
  665. package/dist/_chunks/mdx-file-C005ay-P.js.map +0 -1
  666. package/dist/_chunks/plugin-context-rCinWLiE.js.map +0 -1
  667. package/dist/_chunks/scanner-CAietmj4.js.map +0 -1
  668. package/dist/content/index.d.ts +0 -2
  669. package/dist/content/index.d.ts.map +0 -1
  670. package/dist/content/index.js +0 -0
  671. package/src/content/index.ts +0 -5
  672. package/src/shims/server-only-noop.js +0 -6
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * See design/10-error-handling.md §"Status-Code File Variants".
11
11
  */
12
- /** MDX/markdown extensions — server components by default. */
12
+ /** MDX/markdown extensions (dotted) — the canonical list, also used by plugins/mdx.ts. */
13
13
  var MDX_EXTENSIONS = /* @__PURE__ */ new Set([".mdx", ".md"]);
14
14
  /**
15
15
  * Check if a file path ends with an MDX/markdown extension.
@@ -20,6 +20,6 @@ function isMdxFilePath(filePath) {
20
20
  return MDX_EXTENSIONS.has(filePath.slice(dotIndex));
21
21
  }
22
22
  //#endregion
23
- export { isMdxFilePath as t };
23
+ export { isMdxFilePath as n, MDX_EXTENSIONS as t };
24
24
 
25
- //# sourceMappingURL=mdx-file-C005ay-P.js.map
25
+ //# sourceMappingURL=mdx-file-CXyHGUpS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mdx-file-CXyHGUpS.js","names":[],"sources":["../../src/server/utils/mdx-file.ts"],"sourcesContent":["/**\n * MDX file-path detection shared by error/deny rendering paths.\n *\n * MDX status and error files are server components — they cannot be passed\n * as function props across the RSC→client boundary (e.g. to\n * TimberErrorBoundary or ErrorReconstituter) and must be pre-rendered as\n * elements with plain props instead.\n *\n * See design/10-error-handling.md §\"Status-Code File Variants\".\n */\n\n/** MDX/markdown extensions (dotted) — the canonical list, also used by plugins/mdx.ts. */\nexport const MDX_EXTENSIONS = new Set(['.mdx', '.md']);\n\n/**\n * Check if a file path ends with an MDX/markdown extension.\n */\nexport function isMdxFilePath(filePath: string): boolean {\n const dotIndex = filePath.lastIndexOf('.');\n if (dotIndex === -1) return false;\n return MDX_EXTENSIONS.has(filePath.slice(dotIndex));\n}\n"],"mappings":";;;;;;;;;;;;AAYA,IAAa,iCAAiB,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC;;;;AAKrD,SAAgB,cAAc,UAA2B;CACvD,MAAM,WAAW,SAAS,YAAY,GAAG;CACzC,IAAI,aAAa,IAAI,OAAO;CAC5B,OAAO,eAAe,IAAI,SAAS,MAAM,QAAQ,CAAC;AACpD"}
@@ -1,4 +1,4 @@
1
- import { o as __exportAll } from "./dist-BA3u1z3W.js";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
2
  import { parseAst } from "vite";
3
3
  import { join, resolve } from "node:path";
4
4
  import { createRequire } from "node:module";
@@ -318,4 +318,4 @@ function mergeFileConfig(inline, fileConfig) {
318
318
  //#endregion
319
319
  export { plugin_context_exports as a, resolveClientJavascript as c, mergeFileConfig as i, createNoopTimer as l, isTimberPluginApi as n, resolveAppDir as o, loadTimberConfigFile as r, resolveBuildDir as s, createPluginContext as t };
320
320
 
321
- //# sourceMappingURL=plugin-context-rCinWLiE.js.map
321
+ //# sourceMappingURL=plugin-context-8idfR3UZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-context-8idfR3UZ.js","names":[],"sources":["../../src/utils/startup-timer.ts","../../src/plugin-context.ts"],"sourcesContent":["/**\n * Startup timer — records named phases with their durations.\n *\n * Used by the plugin system to instrument cold start and report a\n * timing breakdown in dev mode. Zero overhead in production (disabled).\n *\n * See design/18-build-system.md, TIM-155.\n */\n\nimport { performance } from 'node:perf_hooks';\n\nexport interface PhaseRecord {\n name: string;\n startMs: number;\n durationMs: number;\n}\n\nexport interface StartupTimer {\n /** Mark the beginning of a named phase. */\n start(phase: string): void;\n /** Mark the end of a named phase. Returns duration in ms. */\n end(phase: string): number;\n /** Get all completed phase records, ordered by start time. */\n getPhases(): PhaseRecord[];\n /** Total elapsed time from first start() to last end(). */\n totalMs(): number;\n /** Format a human-readable summary string. */\n formatSummary(): string;\n}\n\n/**\n * Create a startup timer that records phase durations.\n */\nexport function createStartupTimer(): StartupTimer {\n const pending = new Map<string, number>();\n const phases: PhaseRecord[] = [];\n\n return {\n start(phase: string): void {\n pending.set(phase, performance.now());\n },\n\n end(phase: string): number {\n const startMs = pending.get(phase);\n if (startMs === undefined) {\n return 0;\n }\n pending.delete(phase);\n const durationMs = performance.now() - startMs;\n phases.push({ name: phase, startMs, durationMs });\n return durationMs;\n },\n\n getPhases(): PhaseRecord[] {\n return [...phases].sort((a, b) => a.startMs - b.startMs);\n },\n\n totalMs(): number {\n if (phases.length === 0) return 0;\n const sorted = this.getPhases();\n const first = sorted[0];\n const last = sorted[sorted.length - 1];\n return last.startMs + last.durationMs - first.startMs;\n },\n\n formatSummary(): string {\n const sorted = this.getPhases();\n if (sorted.length === 0) return 'No phases recorded.';\n\n const lines = sorted.map((p) => {\n const ms = p.durationMs.toFixed(1);\n return ` ${p.name.padEnd(30)} ${ms.padStart(8)}ms`;\n });\n\n const total = this.totalMs().toFixed(1);\n lines.push(` ${'total'.padEnd(30)} ${total.padStart(8)}ms`);\n\n return ['[timber] startup timing:', ...lines].join('\\n');\n },\n };\n}\n\n/**\n * No-op timer for production builds — all methods are empty.\n */\nexport function createNoopTimer(): StartupTimer {\n return {\n start() {},\n end() {\n return 0;\n },\n getPhases() {\n return [];\n },\n totalMs() {\n return 0;\n },\n formatSummary() {\n return '';\n },\n };\n}\n","/**\n * Plugin context — internal types and helpers for timber sub-plugins.\n *\n * These are NOT part of the user-facing API. They are consumed by\n * sub-plugins (routing, entries, shims, etc.) via relative imports.\n * The root entry point (index.ts) does not re-export them.\n *\n * Design doc: 18-build-system.md §\"Shared Plugin Context\"\n */\n\nimport { existsSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { createRequire } from 'node:module';\nimport { parseAst } from 'vite';\nimport type { RouteTree } from './routing/types.ts';\nimport type { BuildManifest } from './server/build-manifest.ts';\nimport type { CaptureSummary } from './server/prebuilt-builder.ts';\nimport type { StartupTimer } from './utils/startup-timer.ts';\nimport { createStartupTimer } from './utils/startup-timer.ts';\nimport type { TimberUserConfig, ClientJavascriptConfig } from './config-types.ts';\nimport type { RscManifest } from './plugins/static-build.ts';\nimport type { HoldingServer } from './dev-tools/holding-server.ts';\nimport type { ProgramNode } from './plugins/callsite-ast.ts';\n\n// Re-export for sub-plugin convenience — they import from plugin-context.ts\nexport type { TimberUserConfig, ClientJavascriptConfig } from './config-types.ts';\n\n// ── Client JavaScript config ─────────────────────────────────────────────\n\n/** Fully resolved client JavaScript configuration (no optionals). */\nexport interface ResolvedClientJavascript {\n disabled: boolean;\n enableHMRInDev: boolean;\n}\n\n/**\n * Resolve `clientJavascript` into a fully resolved config.\n */\nexport function resolveClientJavascript(config: TimberUserConfig): ResolvedClientJavascript {\n if (config.clientJavascript !== undefined) {\n if (typeof config.clientJavascript === 'boolean') {\n return {\n disabled: !config.clientJavascript,\n enableHMRInDev: !config.clientJavascript,\n };\n }\n return {\n disabled: config.clientJavascript.disabled,\n enableHMRInDev: config.clientJavascript.enableHMRInDev ?? config.clientJavascript.disabled,\n };\n }\n return { disabled: false, enableHMRInDev: false };\n}\n\n// ── Plugin Context ────────────────────────────────────────────────────────\n\n/**\n * Shared context object passed to all sub-plugins via closure.\n *\n * Sub-plugins communicate through this context — not through Vite's\n * plugin API or global state.\n * See design/18-build-system.md §\"Shared Plugin Context\".\n */\nexport interface PluginContext {\n config: TimberUserConfig;\n /** Resolved client JavaScript configuration */\n clientJavascript: ResolvedClientJavascript;\n /** The scanned route tree (populated by timber-routing, consumed by timber-entries) */\n routeTree: RouteTree | null;\n /** Absolute path to the app/ directory */\n appDir: string;\n /** Absolute path to the project root */\n root: string;\n /** Whether the dev server is running (set by timber-root-sync in configResolved) */\n dev: boolean;\n /**\n * Vite's resolved `base` (set by timber-root-sync in configResolved).\n * Always has a trailing slash; `'/'` unless the app is deployed under a\n * sub-path. Every URL the framework emits — assets, fonts, RSC payloads —\n * carries this prefix. This is the single copy: sub-plugins read it here\n * rather than capturing `config.base` in their own configResolved.\n *\n * **Availability:** written by timber-root-sync, which has no `enforce`, so\n * it is populated from `buildStart`/`load`/`generateBundle`/`configureServer`\n * onward — but NOT during the `configResolved` of an `enforce: 'pre'`\n * plugin, which Vite runs first. A pre plugin that needs the base inside\n * its own `configResolved` must read `config.base` there (timber-fonts\n * does). See TIM-1261.\n */\n base: string;\n /** CSS build manifest (populated by adapter after client build, null in dev) */\n buildManifest: BuildManifest | null;\n /** Per-build deployment ID for version skew detection (null in dev) */\n deploymentId: string | null;\n /** Startup timer for profiling cold start phases (active in dev, no-op in prod) */\n timer: StartupTimer;\n /** Holding server that binds the port during dev startup (closed in timber-dev-server) */\n holdingServer?: HoldingServer | null;\n /**\n * Resolved absolute path to the build output directory.\n *\n * Defaults to `<root>/.timber/dist`. Can be overridden via\n * `timber.config.ts` `buildDir` or Vite's `build.outDir`.\n * Timber config takes precedence when both are set.\n *\n * Used by adapter-build and cli preview.\n */\n buildDir: string;\n /**\n * Per-route client reference keys captured during the RSC build.\n * Maps absolute route file paths to the set of client reference\n * hash keys they transitively import. Used by adapter-build to\n * populate per-route modulepreload entries from clientReferenceDeps.\n */\n routeClientRefKeys?: Map<string, Set<string>>;\n /**\n * Static request-dependency verdict per segment entry file, keyed by the\n * absolute `filePath` the route scanner produced. Computed once by\n * `timber-request-dep`'s RSC `buildEnd` and serialized into\n * `buildManifest.requestDep` by `timber-build-manifest` (build only — dev\n * answers the same question through the `Symbol.for('timber:request-dep')`\n * bridge instead).\n *\n * `undefined` and `{}` are different states and the difference is the whole\n * of TIM-1300: an empty object means the analysis ran and found no segments,\n * `undefined` means it never ran, and the runtime cannot tell them apart —\n * every key is absent either way, so every segment falls to the conservative\n * `true` and nothing is ever skipped. The build fails loudly on `undefined`\n * rather than shipping that silently.\n */\n requestDepMap?: Record<string, boolean>;\n /**\n * Maps absolute module IDs of client references in non-facade RSC\n * chunks to the absolute paths of their consuming facade modules.\n * Built during the RSC `generateBundle` phase by timber-chunks,\n * consumed by `clientChunkGroup` to reclassify `shared:` modules\n * that are only used by a single route boundary.\n * See design/27-chunking-strategy.md, TIM-1107.\n */\n sharedModuleFacades?: Map<string, string[]>;\n /**\n * Module ID → prebuilt component IDs declared in it. Recorded by the\n * timber-prebuilt transform (RSC environment, production builds only),\n * consumed by the RSC `generateBundle` module-graph walk that computes\n * `routePrebuiltComponents`. See design/44-render-at-build-time.md.\n */\n prebuiltModuleComponents?: Map<string, string[]>;\n /**\n * Module ID → mapping of variable name to component ID for the prebuilt\n * components declared in that module. Used at `generateBundle` time to\n * trace imports from other modules back to specific component IDs.\n */\n prebuiltBindingNames?: Map<string, Map<string, string>>;\n /**\n * Component ID → distinct static call-site prop objects captured from\n * JSX usage sites during the transform and generateBundle phases.\n * Consumed by the post-build capture pass to render with actual props\n * instead of empty `{}`. See design/44 §Props Derivation.\n */\n prebuiltCallSiteProps?: Map<string, Record<string, unknown>[]>;\n /**\n * Route file path (page or layout, absolute) → prebuilt component IDs\n * transitively reachable from it. Computed during RSC `generateBundle`,\n * consumed by the post-build capture pass (TIM-1119) to decide which\n * components to render under which route's param combos.\n */\n routePrebuiltComponents?: Map<string, string[]>;\n /**\n * Page file paths that were desugared from `export const prerender` by\n * timber-prerender-sugar. The prebuilt transform uses this to verify\n * the generated `cache.component(...)` call was picked up.\n */\n prerenderSugarPages?: Set<string>;\n /**\n * Component ID → built chunk file name for prebuilt-declaring modules\n * that are only reachable via dynamic imports (import.meta.glob, lazy\n * routes). The capture pass imports these chunks to trigger\n * cache.component() registration before rendering. Populated during\n * RSC generateBundle alongside routePrebuiltComponents.\n */\n prebuiltLazyChunks?: Map<string, string>;\n /** Post-build prebuilt capture summary (populated by timber-prebuilt, consumed by build-report). */\n captureSummary?: CaptureSummary;\n /**\n * Content-keyed AST parse memo shared across cache/prebuilt/prerender-sugar\n * transforms. Collapses both cross-plugin and cross-environment duplicate\n * parses: identical code hits, rewritten code misses (correct because Vite\n * transforms chain — a rewrite produces different code). Bounded LRU (32\n * entries) so it doesn't hold programs for the whole build.\n *\n * Consumers MUST treat the returned ProgramNode as read-only — they collect\n * ranges and rewrite CODE via MagicString; the AST itself is never mutated.\n */\n parseCached?: ParseMemo;\n /**\n * Content-Type mappings for extensionless static API route outputs.\n * Populated during static generation, consumed by adapter-build to\n * write per-path Content-Type rules in _headers. See TIM-1241.\n */\n staticContentTypes?: Record<string, string>;\n /**\n * RSC flight payload manifest mapping unhashed → hashed URLs.\n * Populated during static generation, consumed by adapters to set\n * immutable cache headers for `_rsc/` files. See TIM-1254.\n */\n rscManifest?: RscManifest;\n}\n\n// ── AST parse memo ───────────────────────────────────────────────────────\n\nconst PARSE_MEMO_CAPACITY = 32;\n\n/**\n * Content-keyed LRU memo for `parseAst`. Transforms for the same module run\n * back-to-back across plugins and environments, so a tiny window captures the\n * wins. The returned ProgramNode is shared — callers MUST NOT mutate it.\n */\nexport class ParseMemo {\n private cache = new Map<string, ProgramNode>();\n\n /**\n * Parse code, returning a cached ProgramNode if the same code was parsed\n * before. The returned AST MUST NOT be mutated — it may be shared across\n * multiple consumers.\n */\n parse(code: string): ProgramNode {\n const existing = this.cache.get(code);\n if (existing) {\n // LRU refresh: move to end\n this.cache.delete(code);\n this.cache.set(code, existing);\n return existing;\n }\n const program = parseAst(code, { lang: 'tsx' }) as unknown as ProgramNode;\n if (this.cache.size >= PARSE_MEMO_CAPACITY) {\n // Evict oldest (first inserted)\n const firstKey = this.cache.keys().next().value!;\n this.cache.delete(firstKey);\n }\n this.cache.set(code, program);\n return program;\n }\n\n get size(): number {\n return this.cache.size;\n }\n}\n\n// ── App directory resolution ──────────────────────────────────────────────\n\n// ── Plugin API (Vite `plugin.api`) ────────────────────────────────────────\n\n/**\n * What `timber-root-sync` publishes on its Vite `plugin.api`.\n *\n * The single supported way to read timber's *resolved* configuration from\n * outside the plugin pipeline. Re-reading `timber.config.ts` is not equivalent:\n * config passed inline as `timber({ ... })` in `vite.config.ts` exists only in\n * the plugin's closure, and `root`/`appDir` are resolved against Vite's root\n * rather than the caller's cwd.\n */\nexport interface TimberPluginApi {\n /** The live plugin context. Fully populated from `configResolved` onward. */\n getContext(): PluginContext;\n}\n\n/** Narrow an unknown Vite `plugin.api` to timber's. */\nexport function isTimberPluginApi(api: unknown): api is TimberPluginApi {\n return (\n typeof api === 'object' &&\n api !== null &&\n 'getContext' in api &&\n typeof api.getContext === 'function'\n );\n}\n\n/**\n * Resolve the app directory. Checks (in order):\n * 1. Explicit `configAppDir` from timber.config.ts\n * 2. `<root>/app`\n * 3. `<root>/src/app`\n *\n * Throws if none exist.\n */\nexport function resolveAppDir(root: string, configAppDir?: string): string {\n if (configAppDir) {\n const explicit = join(root, configAppDir);\n if (!existsSync(explicit)) {\n throw new Error(`[timber] Configured appDir \"${configAppDir}\" does not exist at ${explicit}`);\n }\n return explicit;\n }\n\n const rootApp = join(root, 'app');\n if (existsSync(rootApp)) return rootApp;\n\n const srcApp = join(root, 'src', 'app');\n if (existsSync(srcApp)) return srcApp;\n\n throw new Error(\n `[timber] Could not find app directory. Expected \"app/\" or \"src/app/\" in ${root}. ` +\n `You can set appDir in timber.config.ts to specify a custom location.`\n );\n}\n\n// ── Plugin context factory ────────────────────────────────────────────────\n\nexport function createPluginContext(config?: TimberUserConfig, root?: string): PluginContext {\n const projectRoot = root ?? process.cwd();\n const resolvedConfig: TimberUserConfig = { ...config };\n return {\n config: resolvedConfig,\n clientJavascript: resolveClientJavascript(resolvedConfig),\n routeTree: null,\n appDir: join(projectRoot, 'app'),\n root: projectRoot,\n dev: false,\n base: '/',\n buildManifest: null,\n deploymentId: null,\n timer: createStartupTimer(),\n holdingServer: null,\n buildDir: resolveBuildDir(projectRoot, resolvedConfig.buildDir),\n parseCached: new ParseMemo(),\n };\n}\n\n// ── Build directory resolution ────────────────────────────────────────────\n\n/** Default build output directory (relative to root). */\nexport const DEFAULT_BUILD_DIR = join('.timber', 'dist');\n\n/**\n * Resolve the build output directory.\n *\n * Priority:\n * 1. Explicit `timberBuildDir` from timber.config.ts\n * 2. Explicit `viteBuildOutDir` from Vite's build.outDir (if not the default 'dist')\n * 3. Default: `.timber/dist`\n *\n * Returns an absolute path.\n */\nexport function resolveBuildDir(\n root: string,\n timberBuildDir?: string,\n viteBuildOutDir?: string\n): string {\n if (timberBuildDir) {\n return resolve(root, timberBuildDir);\n }\n if (viteBuildOutDir && viteBuildOutDir !== 'dist') {\n return resolve(root, viteBuildOutDir);\n }\n return join(root, DEFAULT_BUILD_DIR);\n}\n\n// ── Config file loading ───────────────────────────────────────────────────\n\n/**\n * Map known timber.config load failures to actionable hints (TIM-1040).\n * Returns null when the error has no known remedy beyond its own message.\n *\n * Known failure modes of loading timber.config.ts via native require():\n * - Node < 22.18 has no default type stripping → ERR_UNKNOWN_FILE_EXTENSION\n * - Non-erasable TS syntax (enums, namespaces, parameter properties)\n * → ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX / ERR_INVALID_TYPESCRIPT_SYNTAX\n * - ESM syntax in a `\"type\": \"commonjs\"` package → the stripped .ts is\n * parsed as CJS and throws SyntaxError: \"Unexpected token 'export'\"\n * (export statements) or \"Cannot use import statement outside a\n * module\" (import statements)\n */\nexport function configLoadHint(configName: string, err: unknown): string | null {\n const code = (err as NodeJS.ErrnoException | null)?.code;\n const isTs = configName.endsWith('.ts');\n\n if (isTs && code === 'ERR_UNKNOWN_FILE_EXTENSION') {\n return (\n 'Loading a TypeScript config requires Node.js 22.18+ (built-in type stripping). ' +\n 'Upgrade Node.js or rewrite the config as timber.config.js.'\n );\n }\n if (code === 'ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX' || code === 'ERR_INVALID_TYPESCRIPT_SYNTAX') {\n return (\n 'Node.js loads the config with type stripping, which only supports erasable TypeScript syntax — ' +\n 'replace enums, namespaces, and constructor parameter properties with plain objects and types.'\n );\n }\n if (\n isTs &&\n err instanceof SyntaxError &&\n /Unexpected token '(export|import)'|Cannot use import statement outside a module/.test(\n err.message\n )\n ) {\n return (\n 'The config uses ESM syntax but Node.js parsed it as CommonJS — ' +\n 'set \"type\": \"module\" in package.json, or use module.exports instead of export default.'\n );\n }\n return null;\n}\n\n/**\n * Load timber.config.ts (or .js, .mjs) from the project root.\n * Returns the config object or null if no config file is found.\n * Throws a descriptive error naming the file when a config file exists\n * but fails to load — a broken config must fail loudly, never silently\n * degrade (see TIM-1066). Known failure modes get an actionable hint\n * appended (see configLoadHint, TIM-1040).\n *\n * Uses require() — Node 22.12+ can require() ESM modules, and Node\n * 22.18+ strips types from .ts files by default (hence the engines\n * field requiring >=22.18.0). This keeps timber() synchronous — no\n * async config loading needed.\n * This is the single config loader — dev, build, and preview all use it.\n */\nexport function loadTimberConfigFile(root: string): TimberUserConfig | null {\n const configNames = ['timber.config.ts', 'timber.config.js', 'timber.config.mjs'];\n const req = createRequire(join(root, 'package.json'));\n\n for (const name of configNames) {\n const configPath = join(root, name);\n if (existsSync(configPath)) {\n try {\n const mod = req(configPath);\n return (mod.default ?? mod) as TimberUserConfig;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const hint = configLoadHint(name, err);\n throw new Error(\n `[timber] Failed to load ${configPath}: ${message}${hint ? `\\n${hint}` : ''}`,\n { cause: err }\n );\n }\n }\n }\n return null;\n}\n\n/**\n * Detect config keys set in both inline (vite.config.ts) and file (timber.config.ts)\n * and warn the user. The `output` key is excluded because it defaults to 'server'\n * in createPluginContext and would always appear as an inline key.\n *\n * Returns the list of conflicting key names (for testing).\n */\nexport function warnConfigConflicts(\n inline: TimberUserConfig,\n fileConfig: TimberUserConfig\n): string[] {\n const conflicts: string[] = [];\n for (const key of Object.keys(fileConfig) as (keyof TimberUserConfig)[]) {\n if (key in inline && inline[key] !== undefined) {\n conflicts.push(key);\n }\n }\n if (conflicts.length > 0) {\n console.warn(\n `[timber] Config conflict: ${conflicts.map((k) => `\"${k}\"`).join(', ')} set in both ` +\n `vite.config.ts (inline) and timber.config.ts. ` +\n `Move all config to timber.config.ts to avoid confusion. ` +\n `The inline value from vite.config.ts will be used.`\n );\n }\n return conflicts;\n}\n\n/**\n * Drop own keys whose value is `undefined` so they don't clobber file\n * config during spread merging. `timber({ buildDir: process.env.BUILD_DIR })`\n * with the var unset must not erase the timber.config.ts value.\n */\nfunction stripUndefined<T extends object>(obj: T): T {\n return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined)) as T;\n}\n\n/**\n * Merge file-based config (timber.config.ts) with inline config (vite.config.ts).\n * Inline config takes precedence — file config only fills in missing fields.\n * Inline keys explicitly set to `undefined` are treated as absent, matching\n * the `!== undefined` check in warnConfigConflicts.\n */\nexport function mergeFileConfig(\n inline: TimberUserConfig,\n fileConfig: TimberUserConfig\n): TimberUserConfig {\n warnConfigConflicts(inline, fileConfig);\n const definedInline = stripUndefined(inline);\n\n return {\n ...fileConfig,\n ...definedInline,\n ...(fileConfig.limits && definedInline.limits\n ? { limits: { ...fileConfig.limits, ...stripUndefined(definedInline.limits) } }\n : {}),\n ...(fileConfig.dev && definedInline.dev\n ? { dev: { ...fileConfig.dev, ...stripUndefined(definedInline.dev) } }\n : {}),\n ...(fileConfig.mdx && definedInline.mdx\n ? { mdx: { ...fileConfig.mdx, ...stripUndefined(definedInline.mdx) } }\n : {}),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiCA,SAAgB,qBAAmC;CACjD,MAAM,0BAAU,IAAI,IAAoB;CACxC,MAAM,SAAwB,CAAC;CAE/B,OAAO;EACL,MAAM,OAAqB;GACzB,QAAQ,IAAI,OAAO,YAAY,IAAI,CAAC;EACtC;EAEA,IAAI,OAAuB;GACzB,MAAM,UAAU,QAAQ,IAAI,KAAK;GACjC,IAAI,YAAY,KAAA,GACd,OAAO;GAET,QAAQ,OAAO,KAAK;GACpB,MAAM,aAAa,YAAY,IAAI,IAAI;GACvC,OAAO,KAAK;IAAE,MAAM;IAAO;IAAS;GAAW,CAAC;GAChD,OAAO;EACT;EAEA,YAA2B;GACzB,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO;EACzD;EAEA,UAAkB;GAChB,IAAI,OAAO,WAAW,GAAG,OAAO;GAChC,MAAM,SAAS,KAAK,UAAU;GAC9B,MAAM,QAAQ,OAAO;GACrB,MAAM,OAAO,OAAO,OAAO,SAAS;GACpC,OAAO,KAAK,UAAU,KAAK,aAAa,MAAM;EAChD;EAEA,gBAAwB;GACtB,MAAM,SAAS,KAAK,UAAU;GAC9B,IAAI,OAAO,WAAW,GAAG,OAAO;GAEhC,MAAM,QAAQ,OAAO,KAAK,MAAM;IAC9B,MAAM,KAAK,EAAE,WAAW,QAAQ,CAAC;IACjC,OAAO,KAAK,EAAE,KAAK,OAAO,EAAE,EAAE,GAAG,GAAG,SAAS,CAAC,EAAE;GAClD,CAAC;GAED,MAAM,QAAQ,KAAK,QAAQ,CAAC,CAAC,QAAQ,CAAC;GACtC,MAAM,KAAK,KAAK,QAAQ,OAAO,EAAE,EAAE,GAAG,MAAM,SAAS,CAAC,EAAE,GAAG;GAE3D,OAAO,CAAC,4BAA4B,GAAG,KAAK,CAAC,CAAC,KAAK,IAAI;EACzD;CACF;AACF;;;;AAKA,SAAgB,kBAAgC;CAC9C,OAAO;EACL,QAAQ,CAAC;EACT,MAAM;GACJ,OAAO;EACT;EACA,YAAY;GACV,OAAO,CAAC;EACV;EACA,UAAU;GACR,OAAO;EACT;EACA,gBAAgB;GACd,OAAO;EACT;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/DA,SAAgB,wBAAwB,QAAoD;CAC1F,IAAI,OAAO,qBAAqB,KAAA,GAAW;EACzC,IAAI,OAAO,OAAO,qBAAqB,WACrC,OAAO;GACL,UAAU,CAAC,OAAO;GAClB,gBAAgB,CAAC,OAAO;EAC1B;EAEF,OAAO;GACL,UAAU,OAAO,iBAAiB;GAClC,gBAAgB,OAAO,iBAAiB,kBAAkB,OAAO,iBAAiB;EACpF;CACF;CACA,OAAO;EAAE,UAAU;EAAO,gBAAgB;CAAM;AAClD;AA8JA,IAAM,sBAAsB;;;;;;AAO5B,IAAa,YAAb,MAAuB;CACrB,wBAAgB,IAAI,IAAyB;;;;;;CAO7C,MAAM,MAA2B;EAC/B,MAAM,WAAW,KAAK,MAAM,IAAI,IAAI;EACpC,IAAI,UAAU;GAEZ,KAAK,MAAM,OAAO,IAAI;GACtB,KAAK,MAAM,IAAI,MAAM,QAAQ;GAC7B,OAAO;EACT;EACA,MAAM,UAAU,SAAS,MAAM,EAAE,MAAM,MAAM,CAAC;EAC9C,IAAI,KAAK,MAAM,QAAQ,qBAAqB;GAE1C,MAAM,WAAW,KAAK,MAAM,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;GAC1C,KAAK,MAAM,OAAO,QAAQ;EAC5B;EACA,KAAK,MAAM,IAAI,MAAM,OAAO;EAC5B,OAAO;CACT;CAEA,IAAI,OAAe;EACjB,OAAO,KAAK,MAAM;CACpB;AACF;;AAqBA,SAAgB,kBAAkB,KAAsC;CACtE,OACE,OAAO,QAAQ,YACf,QAAQ,QACR,gBAAgB,OAChB,OAAO,IAAI,eAAe;AAE9B;;;;;;;;;AAUA,SAAgB,cAAc,MAAc,cAA+B;CACzE,IAAI,cAAc;EAChB,MAAM,WAAW,KAAK,MAAM,YAAY;EACxC,IAAI,CAAC,WAAW,QAAQ,GACtB,MAAM,IAAI,MAAM,+BAA+B,aAAa,sBAAsB,UAAU;EAE9F,OAAO;CACT;CAEA,MAAM,UAAU,KAAK,MAAM,KAAK;CAChC,IAAI,WAAW,OAAO,GAAG,OAAO;CAEhC,MAAM,SAAS,KAAK,MAAM,OAAO,KAAK;CACtC,IAAI,WAAW,MAAM,GAAG,OAAO;CAE/B,MAAM,IAAI,MACR,2EAA2E,KAAK,uEAElF;AACF;AAIA,SAAgB,oBAAoB,QAA2B,MAA8B;CAC3F,MAAM,cAAc,QAAQ,QAAQ,IAAI;CACxC,MAAM,iBAAmC,EAAE,GAAG,OAAO;CACrD,OAAO;EACL,QAAQ;EACR,kBAAkB,wBAAwB,cAAc;EACxD,WAAW;EACX,QAAQ,KAAK,aAAa,KAAK;EAC/B,MAAM;EACN,KAAK;EACL,MAAM;EACN,eAAe;EACf,cAAc;EACd,OAAO,mBAAmB;EAC1B,eAAe;EACf,UAAU,gBAAgB,aAAa,eAAe,QAAQ;EAC9D,aAAa,IAAI,UAAU;CAC7B;AACF;;AAKA,IAAa,oBAAoB,KAAK,WAAW,MAAM;;;;;;;;;;;AAYvD,SAAgB,gBACd,MACA,gBACA,iBACQ;CACR,IAAI,gBACF,OAAO,QAAQ,MAAM,cAAc;CAErC,IAAI,mBAAmB,oBAAoB,QACzC,OAAO,QAAQ,MAAM,eAAe;CAEtC,OAAO,KAAK,MAAM,iBAAiB;AACrC;;;;;;;;;;;;;;AAiBA,SAAgB,eAAe,YAAoB,KAA6B;CAC9E,MAAM,OAAQ,KAAsC;CACpD,MAAM,OAAO,WAAW,SAAS,KAAK;CAEtC,IAAI,QAAQ,SAAS,8BACnB,OACE;CAIJ,IAAI,SAAS,uCAAuC,SAAS,iCAC3D,OACE;CAIJ,IACE,QACA,eAAe,eACf,kFAAkF,KAChF,IAAI,OACN,GAEA,OACE;CAIJ,OAAO;AACT;;;;;;;;;;;;;;;AAgBA,SAAgB,qBAAqB,MAAuC;CAC1E,MAAM,cAAc;EAAC;EAAoB;EAAoB;CAAmB;CAChF,MAAM,MAAM,cAAc,KAAK,MAAM,cAAc,CAAC;CAEpD,KAAK,MAAM,QAAQ,aAAa;EAC9B,MAAM,aAAa,KAAK,MAAM,IAAI;EAClC,IAAI,WAAW,UAAU,GACvB,IAAI;GACF,MAAM,MAAM,IAAI,UAAU;GAC1B,OAAQ,IAAI,WAAW;EACzB,SAAS,KAAK;GACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAC/D,MAAM,OAAO,eAAe,MAAM,GAAG;GACrC,MAAM,IAAI,MACR,2BAA2B,WAAW,IAAI,UAAU,OAAO,KAAK,SAAS,MACzE,EAAE,OAAO,IAAI,CACf;EACF;CAEJ;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,oBACd,QACA,YACU;CACV,MAAM,YAAsB,CAAC;CAC7B,KAAK,MAAM,OAAO,OAAO,KAAK,UAAU,GACtC,IAAI,OAAO,UAAU,OAAO,SAAS,KAAA,GACnC,UAAU,KAAK,GAAG;CAGtB,IAAI,UAAU,SAAS,GACrB,QAAQ,KACN,6BAA6B,UAAU,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,sKAIzE;CAEF,OAAO;AACT;;;;;;AAOA,SAAS,eAAiC,KAAW;CACnD,OAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,CAAC,CAAC,QAAQ,GAAG,OAAO,MAAM,KAAA,CAAS,CAAC;AAClF;;;;;;;AAQA,SAAgB,gBACd,QACA,YACkB;CAClB,oBAAoB,QAAQ,UAAU;CACtC,MAAM,gBAAgB,eAAe,MAAM;CAE3C,OAAO;EACL,GAAG;EACH,GAAG;EACH,GAAI,WAAW,UAAU,cAAc,SACnC,EAAE,QAAQ;GAAE,GAAG,WAAW;GAAQ,GAAG,eAAe,cAAc,MAAM;EAAE,EAAE,IAC5E,CAAC;EACL,GAAI,WAAW,OAAO,cAAc,MAChC,EAAE,KAAK;GAAE,GAAG,WAAW;GAAK,GAAG,eAAe,cAAc,GAAG;EAAE,EAAE,IACnE,CAAC;EACL,GAAI,WAAW,OAAO,cAAc,MAChC,EAAE,KAAK;GAAE,GAAG,WAAW;GAAK,GAAG,eAAe,cAAc,GAAG;EAAE,EAAE,IACnE,CAAC;CACP;AACF"}
@@ -0,0 +1,110 @@
1
+ import { isBuiltin } from "node:module";
2
+ //#region src/analyze/poison-rules.ts
3
+ /**
4
+ * poison-rules — single source of truth for server-only / client-only
5
+ * module rules.
6
+ *
7
+ * Two tiers with different enforcement policies (design/47 §3):
8
+ *
9
+ * 1. **Explicit markers** (`server-only`, `client-only`) — evaluation-time
10
+ * poison pills. `plugins/shims.ts` resolves them to virtual modules
11
+ * whose body is a top-level `throw` in the wrong environment and a
12
+ * silent no-op in the right one. The error fires when the module is
13
+ * evaluated, not at resolve time.
14
+ *
15
+ * 2. **Inferred rules** (`node:*` imports, timber's ALS modules, browser
16
+ * globals) — report-only. They have legitimate false positives
17
+ * (`import.meta.env.SSR`-guarded `node:*` use, conditionally-imported
18
+ * packages), so erroring the build on them would refuse working apps.
19
+ * The `timber graph` reporter surfaces them as hints.
20
+ *
21
+ * Both shims.ts and the reporter consume this module so the two surfaces
22
+ * can never disagree. Promoting inferred rules to build errors is a
23
+ * policy flip on this list, never a new rule set.
24
+ *
25
+ * Design doc: 47-module-environment-tooling.md §3.
26
+ */
27
+ var EXPLICIT_MARKERS = [{
28
+ specifier: "server-only",
29
+ virtualId: "\0timber:server-only",
30
+ violatesIn: (env) => env === "client",
31
+ errorMessage: "This module cannot be imported from a Client Component module. It should only be used from a Server Component.",
32
+ enforcement: "poison-pill"
33
+ }, {
34
+ specifier: "client-only",
35
+ virtualId: "\0timber:client-only",
36
+ violatesIn: (env) => env !== "client",
37
+ errorMessage: "This module cannot be imported from a Server Component module. It should only be used from a Client Component.",
38
+ enforcement: "poison-pill"
39
+ }];
40
+ /**
41
+ * Look up an explicit marker by its import specifier. Throws on an
42
+ * unknown specifier — callers reference rules that must exist, and a
43
+ * silent undefined would just defer the failure.
44
+ */
45
+ function markerFor(specifier) {
46
+ const marker = EXPLICIT_MARKERS.find((m) => m.specifier === specifier);
47
+ if (!marker) throw new Error(`[timber] unknown poison marker: ${specifier}`);
48
+ return marker;
49
+ }
50
+ /**
51
+ * Generate the virtual module body for an explicit marker in `env`:
52
+ * a top-level throw in the wrong environment, a no-op otherwise.
53
+ */
54
+ function poisonPillSource(marker, env) {
55
+ if (marker.violatesIn(env)) return `throw new Error(${JSON.stringify(marker.errorMessage)});`;
56
+ return "export {};";
57
+ }
58
+ /**
59
+ * Timber modules that hold per-request AsyncLocalStorage state. Importing
60
+ * one from client-reachable code is a strong server-only signal — cf. the
61
+ * no-server-imports-in-isomorphic-define-modules rule.
62
+ */
63
+ var ALS_MODULE_SPECIFIERS = /* @__PURE__ */ new Set([
64
+ "@timber-js/app/server",
65
+ "@timber-js/app/server/internal",
66
+ "#server-internal"
67
+ ]);
68
+ /**
69
+ * The ALS registry module itself, as it appears in import sources.
70
+ * Framework code imports it ESM-style with a `.js` specifier — both
71
+ * `../server/als-registry.js` and sibling `./als-registry.js` forms
72
+ * exist throughout src/server — while resolved module ids carry `.ts`.
73
+ * Matching any path ending in the basename is deliberate: the rule is
74
+ * report-only, and a user file coincidentally named als-registry is a
75
+ * far rarer event than a missed hint on the real one.
76
+ */
77
+ var ALS_REGISTRY_SUFFIX = /(?:^|\/)als-registry\.(?:ts|js)$/;
78
+ var INFERRED_RULES = [
79
+ {
80
+ id: "node-builtin-import",
81
+ implies: "server-only",
82
+ enforcement: "report-only",
83
+ description: "imports a node:* built-in module",
84
+ matchesImport: (specifier) => specifier.startsWith("node:") && isBuiltin(specifier)
85
+ },
86
+ {
87
+ id: "timber-als-module",
88
+ implies: "server-only",
89
+ enforcement: "report-only",
90
+ description: "imports timber's per-request AsyncLocalStorage modules",
91
+ matchesImport: (specifier) => ALS_MODULE_SPECIFIERS.has(specifier) || ALS_REGISTRY_SUFFIX.test(specifier)
92
+ },
93
+ {
94
+ id: "browser-global",
95
+ implies: "client-only",
96
+ enforcement: "report-only",
97
+ description: "references a browser-only global",
98
+ identifiers: [
99
+ "window",
100
+ "document",
101
+ "navigator",
102
+ "localStorage",
103
+ "sessionStorage"
104
+ ]
105
+ }
106
+ ];
107
+ //#endregion
108
+ export { poisonPillSource as i, INFERRED_RULES as n, markerFor as r, EXPLICIT_MARKERS as t };
109
+
110
+ //# sourceMappingURL=poison-rules-DoEhbqaY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poison-rules-DoEhbqaY.js","names":[],"sources":["../../src/analyze/poison-rules.ts"],"sourcesContent":["/**\n * poison-rules — single source of truth for server-only / client-only\n * module rules.\n *\n * Two tiers with different enforcement policies (design/47 §3):\n *\n * 1. **Explicit markers** (`server-only`, `client-only`) — evaluation-time\n * poison pills. `plugins/shims.ts` resolves them to virtual modules\n * whose body is a top-level `throw` in the wrong environment and a\n * silent no-op in the right one. The error fires when the module is\n * evaluated, not at resolve time.\n *\n * 2. **Inferred rules** (`node:*` imports, timber's ALS modules, browser\n * globals) — report-only. They have legitimate false positives\n * (`import.meta.env.SSR`-guarded `node:*` use, conditionally-imported\n * packages), so erroring the build on them would refuse working apps.\n * The `timber graph` reporter surfaces them as hints.\n *\n * Both shims.ts and the reporter consume this module so the two surfaces\n * can never disagree. Promoting inferred rules to build errors is a\n * policy flip on this list, never a new rule set.\n *\n * Design doc: 47-module-environment-tooling.md §3.\n */\n\nimport { isBuiltin } from 'node:module';\n\n/** Vite environment names the dev server / build run. */\nexport type EnvironmentName = 'rsc' | 'ssr' | 'client';\n\n// ─── Tier 1: explicit markers (evaluation-time poison pills) ──────────────\n\nexport interface ExplicitMarker {\n /** The bare specifier user code imports (`server-only` / `client-only`). */\n readonly specifier: string;\n /** Virtual module ID the specifier resolves to in shims.ts. */\n readonly virtualId: string;\n /**\n * True when evaluating the marker in `env` is a violation (the virtual\n * module body must throw). `undefined` means \"no environment context\"\n * (e.g. a non-environment-aware build) and is treated as a server\n * environment — matching the historical shims.ts behavior.\n */\n readonly violatesIn: (env: EnvironmentName | string | undefined) => boolean;\n /** Exact runtime error message thrown in the wrong environment. */\n readonly errorMessage: string;\n readonly enforcement: 'poison-pill';\n}\n\nexport const EXPLICIT_MARKERS: readonly ExplicitMarker[] = [\n {\n specifier: 'server-only',\n virtualId: '\\0timber:server-only',\n violatesIn: (env) => env === 'client',\n errorMessage:\n 'This module cannot be imported from a Client Component module. ' +\n 'It should only be used from a Server Component.',\n enforcement: 'poison-pill',\n },\n {\n specifier: 'client-only',\n virtualId: '\\0timber:client-only',\n violatesIn: (env) => env !== 'client',\n errorMessage:\n 'This module cannot be imported from a Server Component module. ' +\n 'It should only be used from a Client Component.',\n enforcement: 'poison-pill',\n },\n];\n\n/**\n * Look up an explicit marker by its import specifier. Throws on an\n * unknown specifier — callers reference rules that must exist, and a\n * silent undefined would just defer the failure.\n */\nexport function markerFor(specifier: string): ExplicitMarker {\n const marker = EXPLICIT_MARKERS.find((m) => m.specifier === specifier);\n if (!marker) throw new Error(`[timber] unknown poison marker: ${specifier}`);\n return marker;\n}\n\n/**\n * Generate the virtual module body for an explicit marker in `env`:\n * a top-level throw in the wrong environment, a no-op otherwise.\n */\nexport function poisonPillSource(\n marker: ExplicitMarker,\n env: EnvironmentName | string | undefined\n): string {\n if (marker.violatesIn(env)) {\n return `throw new Error(${JSON.stringify(marker.errorMessage)});`;\n }\n return 'export {};';\n}\n\n// ─── Tier 2: inferred rules (report-only) ─────────────────────────────────\n\nexport interface InferredRule {\n readonly id: string;\n /** Which exclusivity the signal implies for the containing module. */\n readonly implies: 'server-only' | 'client-only';\n readonly enforcement: 'report-only';\n /** Human-readable description for reporter output. */\n readonly description: string;\n /** Import-specifier signal — matches static import sources. */\n readonly matchesImport?: (specifier: string) => boolean;\n /**\n * Identifier signal — global names whose use implies the exclusivity.\n * Consumers must apply shadow-safe matching (an allowlisted-position\n * AST check, not a text search).\n */\n readonly identifiers?: readonly string[];\n}\n\n/**\n * Timber modules that hold per-request AsyncLocalStorage state. Importing\n * one from client-reachable code is a strong server-only signal — cf. the\n * no-server-imports-in-isomorphic-define-modules rule.\n */\nconst ALS_MODULE_SPECIFIERS = new Set([\n '@timber-js/app/server',\n '@timber-js/app/server/internal',\n '#server-internal',\n]);\n\n/**\n * The ALS registry module itself, as it appears in import sources.\n * Framework code imports it ESM-style with a `.js` specifier — both\n * `../server/als-registry.js` and sibling `./als-registry.js` forms\n * exist throughout src/server — while resolved module ids carry `.ts`.\n * Matching any path ending in the basename is deliberate: the rule is\n * report-only, and a user file coincidentally named als-registry is a\n * far rarer event than a missed hint on the real one.\n */\nconst ALS_REGISTRY_SUFFIX = /(?:^|\\/)als-registry\\.(?:ts|js)$/;\n\nexport const INFERRED_RULES: readonly InferredRule[] = [\n {\n id: 'node-builtin-import',\n implies: 'server-only',\n enforcement: 'report-only',\n description: 'imports a node:* built-in module',\n // Deliberately node:-prefixed only, matching design/47 §3's scope.\n // Bare builtin names (`buffer`, `events`, `process`, `util`, …) are\n // also real npm packages that browser code legitimately imports (the\n // classic polyfill set) — matching them would report working client\n // code, so they are intentionally NOT a signal.\n matchesImport: (specifier) => specifier.startsWith('node:') && isBuiltin(specifier),\n },\n {\n id: 'timber-als-module',\n implies: 'server-only',\n enforcement: 'report-only',\n description: \"imports timber's per-request AsyncLocalStorage modules\",\n matchesImport: (specifier) =>\n ALS_MODULE_SPECIFIERS.has(specifier) || ALS_REGISTRY_SUFFIX.test(specifier),\n },\n {\n id: 'browser-global',\n implies: 'client-only',\n enforcement: 'report-only',\n description: 'references a browser-only global',\n identifiers: ['window', 'document', 'navigator', 'localStorage', 'sessionStorage'],\n },\n];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,IAAa,mBAA8C,CACzD;CACE,WAAW;CACX,WAAW;CACX,aAAa,QAAQ,QAAQ;CAC7B,cACE;CAEF,aAAa;AACf,GACA;CACE,WAAW;CACX,WAAW;CACX,aAAa,QAAQ,QAAQ;CAC7B,cACE;CAEF,aAAa;AACf,CACF;;;;;;AAOA,SAAgB,UAAU,WAAmC;CAC3D,MAAM,SAAS,iBAAiB,MAAM,MAAM,EAAE,cAAc,SAAS;CACrE,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,mCAAmC,WAAW;CAC3E,OAAO;AACT;;;;;AAMA,SAAgB,iBACd,QACA,KACQ;CACR,IAAI,OAAO,WAAW,GAAG,GACvB,OAAO,mBAAmB,KAAK,UAAU,OAAO,YAAY,EAAE;CAEhE,OAAO;AACT;;;;;;AA0BA,IAAM,wCAAwB,IAAI,IAAI;CACpC;CACA;CACA;AACF,CAAC;;;;;;;;;;AAWD,IAAM,sBAAsB;AAE5B,IAAa,iBAA0C;CACrD;EACE,IAAI;EACJ,SAAS;EACT,aAAa;EACb,aAAa;EAMb,gBAAgB,cAAc,UAAU,WAAW,OAAO,KAAK,UAAU,SAAS;CACpF;CACA;EACE,IAAI;EACJ,SAAS;EACT,aAAa;EACb,aAAa;EACb,gBAAgB,cACd,sBAAsB,IAAI,SAAS,KAAK,oBAAoB,KAAK,SAAS;CAC9E;CACA;EACE,IAAI;EACJ,SAAS;EACT,aAAa;EACb,aAAa;EACb,aAAa;GAAC;GAAU;GAAY;GAAa;GAAgB;EAAgB;CACnF;AACF"}
@@ -0,0 +1,101 @@
1
+ import { n as INFERRED_RULES, t as EXPLICIT_MARKERS } from "./poison-rules-DoEhbqaY.js";
2
+ import { o as langForFile } from "./chains-h7EO-u3n.js";
3
+ import { parseAst } from "vite";
4
+ //#region src/analyze/poison-scan.ts
5
+ /**
6
+ * poison-scan — report-only poisoning detection for `timber graph`.
7
+ *
8
+ * Matches a module's static import specifiers against the shared rule
9
+ * lists in poison-rules.ts (the single source of truth — design/47 §3)
10
+ * and reports a poisoning only when the implied exclusivity CONFLICTS
11
+ * with where the module actually runs: a server-only signal in a
12
+ * client-reachable module, or a client-only signal in a server-reachable
13
+ * one. A `node:fs` import in a file only the RSC environment loads is
14
+ * working code, not a finding.
15
+ *
16
+ * Scope: import-specifier signals only (explicit markers + the inferred
17
+ * rules' `matchesImport`). The inferred browser-global identifier rules
18
+ * need shadow-safe allowlisted-position AST matching and are a separate
19
+ * ticket — reporting them from a text scan would flag legitimate code.
20
+ *
21
+ * Design docs: 47-module-environment-tooling.md §3.
22
+ */
23
+ /** File extensions the specifier scan can parse. */
24
+ var PARSEABLE_EXTENSIONS = /\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts)$/;
25
+ /**
26
+ * A NON-EMPTY specifier list where every entry is type-only. Empty or
27
+ * absent lists return false — a bare `import 'pkg'` is a side-effect
28
+ * import and very much runs.
29
+ */
30
+ function isAllSpecifiersTypeOnly(specifiers) {
31
+ if (!specifiers || specifiers.length === 0) return false;
32
+ return specifiers.every((s) => s.importKind === "type" || s.exportKind === "type");
33
+ }
34
+ /**
35
+ * Collect every static import/export source and string-literal dynamic
36
+ * import from a module's original source. Sources that fail to parse
37
+ * (or are not JS/TS at all) return [] — no specifiers is a safe
38
+ * default for a report-only scan.
39
+ */
40
+ function collectImportSpecifiers(code, file) {
41
+ if (!PARSEABLE_EXTENSIONS.test(file)) return [];
42
+ let program;
43
+ try {
44
+ program = parseAst(code, { lang: langForFile(file) });
45
+ } catch {
46
+ return [];
47
+ }
48
+ const specifiers = [];
49
+ const visit = (node) => {
50
+ if (Array.isArray(node)) {
51
+ for (const child of node) visit(child);
52
+ return;
53
+ }
54
+ if (typeof node !== "object" || node === null) return;
55
+ const record = node;
56
+ if ((record.type === "ImportDeclaration" || record.type === "ExportNamedDeclaration" || record.type === "ExportAllDeclaration") && record.importKind !== "type" && record.exportKind !== "type" && !isAllSpecifiersTypeOnly(record.specifiers) && typeof record.source?.value === "string") specifiers.push(record.source.value);
57
+ else if (record.type === "ImportExpression" && record.source?.type === "Literal" && typeof record.source.value === "string") specifiers.push(record.source.value);
58
+ for (const key of Object.keys(record)) {
59
+ if (key === "type") continue;
60
+ visit(record[key]);
61
+ }
62
+ };
63
+ visit(program.body);
64
+ return specifiers;
65
+ }
66
+ /** Exclusivity signals a module's import specifiers carry. */
67
+ function importSignals(specifiers) {
68
+ const signals = [];
69
+ for (const specifier of specifiers) {
70
+ for (const marker of EXPLICIT_MARKERS) if (specifier === marker.specifier) signals.push({
71
+ rule: marker.specifier,
72
+ specifier,
73
+ implies: marker.specifier === "server-only" ? "server-only" : "client-only",
74
+ description: `imports the ${marker.specifier} poison-pill marker`
75
+ });
76
+ for (const rule of INFERRED_RULES) if (rule.matchesImport?.(specifier)) signals.push({
77
+ rule: rule.id,
78
+ specifier,
79
+ implies: rule.implies,
80
+ description: rule.description
81
+ });
82
+ }
83
+ return signals;
84
+ }
85
+ /**
86
+ * Filter a module's signals down to actual conflicts with its
87
+ * classification. Environment reach follows the taxonomy: boundary /
88
+ * client-internal / shared modules run client-side; server / shared /
89
+ * server-action modules run server-side. Pending (provisional) modules
90
+ * run nowhere confirmed, so nothing conflicts yet.
91
+ */
92
+ function poisoningsFor(kind, pending, signals) {
93
+ if (pending || signals.length === 0) return [];
94
+ const clientReachable = kind === "client-boundary" || kind === "client-internal" || kind === "shared";
95
+ const serverReachable = kind === "server" || kind === "shared" || kind === "server-action";
96
+ return signals.filter((signal) => signal.implies === "server-only" && clientReachable || signal.implies === "client-only" && serverReachable);
97
+ }
98
+ //#endregion
99
+ export { importSignals as n, poisoningsFor as r, collectImportSpecifiers as t };
100
+
101
+ //# sourceMappingURL=poison-scan-BAxfTT5L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poison-scan-BAxfTT5L.js","names":[],"sources":["../../src/analyze/poison-scan.ts"],"sourcesContent":["/**\n * poison-scan — report-only poisoning detection for `timber graph`.\n *\n * Matches a module's static import specifiers against the shared rule\n * lists in poison-rules.ts (the single source of truth — design/47 §3)\n * and reports a poisoning only when the implied exclusivity CONFLICTS\n * with where the module actually runs: a server-only signal in a\n * client-reachable module, or a client-only signal in a server-reachable\n * one. A `node:fs` import in a file only the RSC environment loads is\n * working code, not a finding.\n *\n * Scope: import-specifier signals only (explicit markers + the inferred\n * rules' `matchesImport`). The inferred browser-global identifier rules\n * need shadow-safe allowlisted-position AST matching and are a separate\n * ticket — reporting them from a text scan would flag legitimate code.\n *\n * Design docs: 47-module-environment-tooling.md §3.\n */\n\nimport { parseAst } from 'vite';\nimport { EXPLICIT_MARKERS, INFERRED_RULES } from './poison-rules.ts';\nimport { langForFile, type ModuleKind } from './classify.ts';\n\n/** One poisoning finding on a module, in the JSON-contract shape. */\nexport interface Poisoning {\n /** Rule id — an inferred rule's id, or the explicit marker specifier. */\n rule: string;\n /** The import specifier that matched. */\n specifier: string;\n /** Which exclusivity the signal implies for the containing module. */\n implies: 'server-only' | 'client-only';\n /** Human-readable description for reporter output. */\n description: string;\n}\n\n/** File extensions the specifier scan can parse. */\nconst PARSEABLE_EXTENSIONS = /\\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts)$/;\n\n/**\n * A NON-EMPTY specifier list where every entry is type-only. Empty or\n * absent lists return false — a bare `import 'pkg'` is a side-effect\n * import and very much runs.\n */\nfunction isAllSpecifiersTypeOnly(\n specifiers: Array<{ importKind?: string; exportKind?: string }> | undefined\n): boolean {\n if (!specifiers || specifiers.length === 0) return false;\n return specifiers.every((s) => s.importKind === 'type' || s.exportKind === 'type');\n}\n\n/**\n * Collect every static import/export source and string-literal dynamic\n * import from a module's original source. Sources that fail to parse\n * (or are not JS/TS at all) return [] — no specifiers is a safe\n * default for a report-only scan.\n */\nexport function collectImportSpecifiers(code: string, file: string): string[] {\n if (!PARSEABLE_EXTENSIONS.test(file)) return [];\n let program;\n try {\n // Language from the extension, never forced tsx — see langForFile.\n program = parseAst(code, { lang: langForFile(file) });\n } catch {\n return [];\n }\n const specifiers: string[] = [];\n const visit = (node: unknown): void => {\n if (Array.isArray(node)) {\n for (const child of node) visit(child);\n return;\n }\n if (typeof node !== 'object' || node === null) return;\n const record = node as Record<string, unknown> & {\n type?: string;\n importKind?: string;\n exportKind?: string;\n specifiers?: Array<{ importKind?: string; exportKind?: string }>;\n };\n if (\n (record.type === 'ImportDeclaration' ||\n record.type === 'ExportNamedDeclaration' ||\n record.type === 'ExportAllDeclaration') &&\n // Type-only imports/exports are erased at runtime — `import type\n // { Stats } from 'node:fs'` in client code is working code, and\n // flagging it would be a false positive in a report-only scan.\n // Covers both the declaration-level form (`import type {…}`,\n // importKind on the declaration) and the inline form\n // (`import { type Stats }`, where the declaration stays 'value'\n // and each SPECIFIER carries the kind) — a declaration whose\n // specifiers are all type-only is erased just the same.\n record.importKind !== 'type' &&\n record.exportKind !== 'type' &&\n !isAllSpecifiersTypeOnly(record.specifiers) &&\n typeof (record.source as { value?: unknown } | null)?.value === 'string'\n ) {\n specifiers.push((record.source as { value: string }).value);\n } else if (\n record.type === 'ImportExpression' &&\n (record.source as { type?: string; value?: unknown })?.type === 'Literal' &&\n typeof (record.source as { value?: unknown }).value === 'string'\n ) {\n specifiers.push((record.source as { value: string }).value);\n }\n for (const key of Object.keys(record)) {\n if (key === 'type') continue;\n visit(record[key]);\n }\n };\n visit(program.body);\n return specifiers;\n}\n\n/** Exclusivity signals a module's import specifiers carry. */\nexport function importSignals(specifiers: string[]): Poisoning[] {\n const signals: Poisoning[] = [];\n for (const specifier of specifiers) {\n for (const marker of EXPLICIT_MARKERS) {\n if (specifier === marker.specifier) {\n signals.push({\n rule: marker.specifier,\n specifier,\n implies: marker.specifier === 'server-only' ? 'server-only' : 'client-only',\n description: `imports the ${marker.specifier} poison-pill marker`,\n });\n }\n }\n for (const rule of INFERRED_RULES) {\n if (rule.matchesImport?.(specifier)) {\n signals.push({\n rule: rule.id,\n specifier,\n implies: rule.implies,\n description: rule.description,\n });\n }\n }\n }\n return signals;\n}\n\n/**\n * Filter a module's signals down to actual conflicts with its\n * classification. Environment reach follows the taxonomy: boundary /\n * client-internal / shared modules run client-side; server / shared /\n * server-action modules run server-side. Pending (provisional) modules\n * run nowhere confirmed, so nothing conflicts yet.\n */\nexport function poisoningsFor(\n kind: ModuleKind,\n pending: boolean,\n signals: Poisoning[]\n): Poisoning[] {\n if (pending || signals.length === 0) return [];\n const clientReachable =\n kind === 'client-boundary' || kind === 'client-internal' || kind === 'shared';\n const serverReachable = kind === 'server' || kind === 'shared' || kind === 'server-action';\n return signals.filter(\n (signal) =>\n (signal.implies === 'server-only' && clientReachable) ||\n (signal.implies === 'client-only' && serverReachable)\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoCA,IAAM,uBAAuB;;;;;;AAO7B,SAAS,wBACP,YACS;CACT,IAAI,CAAC,cAAc,WAAW,WAAW,GAAG,OAAO;CACnD,OAAO,WAAW,OAAO,MAAM,EAAE,eAAe,UAAU,EAAE,eAAe,MAAM;AACnF;;;;;;;AAQA,SAAgB,wBAAwB,MAAc,MAAwB;CAC5E,IAAI,CAAC,qBAAqB,KAAK,IAAI,GAAG,OAAO,CAAC;CAC9C,IAAI;CACJ,IAAI;EAEF,UAAU,SAAS,MAAM,EAAE,MAAM,YAAY,IAAI,EAAE,CAAC;CACtD,QAAQ;EACN,OAAO,CAAC;CACV;CACA,MAAM,aAAuB,CAAC;CAC9B,MAAM,SAAS,SAAwB;EACrC,IAAI,MAAM,QAAQ,IAAI,GAAG;GACvB,KAAK,MAAM,SAAS,MAAM,MAAM,KAAK;GACrC;EACF;EACA,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM;EAC/C,MAAM,SAAS;EAMf,KACG,OAAO,SAAS,uBACf,OAAO,SAAS,4BAChB,OAAO,SAAS,2BASlB,OAAO,eAAe,UACtB,OAAO,eAAe,UACtB,CAAC,wBAAwB,OAAO,UAAU,KAC1C,OAAQ,OAAO,QAAuC,UAAU,UAEhE,WAAW,KAAM,OAAO,OAA6B,KAAK;OACrD,IACL,OAAO,SAAS,sBACf,OAAO,QAA+C,SAAS,aAChE,OAAQ,OAAO,OAA+B,UAAU,UAExD,WAAW,KAAM,OAAO,OAA6B,KAAK;EAE5D,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG;GACrC,IAAI,QAAQ,QAAQ;GACpB,MAAM,OAAO,IAAI;EACnB;CACF;CACA,MAAM,QAAQ,IAAI;CAClB,OAAO;AACT;;AAGA,SAAgB,cAAc,YAAmC;CAC/D,MAAM,UAAuB,CAAC;CAC9B,KAAK,MAAM,aAAa,YAAY;EAClC,KAAK,MAAM,UAAU,kBACnB,IAAI,cAAc,OAAO,WACvB,QAAQ,KAAK;GACX,MAAM,OAAO;GACb;GACA,SAAS,OAAO,cAAc,gBAAgB,gBAAgB;GAC9D,aAAa,eAAe,OAAO,UAAU;EAC/C,CAAC;EAGL,KAAK,MAAM,QAAQ,gBACjB,IAAI,KAAK,gBAAgB,SAAS,GAChC,QAAQ,KAAK;GACX,MAAM,KAAK;GACX;GACA,SAAS,KAAK;GACd,aAAa,KAAK;EACpB,CAAC;CAGP;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,cACd,MACA,SACA,SACa;CACb,IAAI,WAAW,QAAQ,WAAW,GAAG,OAAO,CAAC;CAC7C,MAAM,kBACJ,SAAS,qBAAqB,SAAS,qBAAqB,SAAS;CACvE,MAAM,kBAAkB,SAAS,YAAY,SAAS,YAAY,SAAS;CAC3E,OAAO,QAAQ,QACZ,WACE,OAAO,YAAY,iBAAiB,mBACpC,OAAO,YAAY,iBAAiB,eACzC;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-schema-CBR6Lm4i.js","names":[],"sources":["../../src/params/resolve-schema.ts"],"sourcesContent":["/**\n * Schema resolution — resolves the global schema's segmentParams into\n * a runtime-ready codec map keyed by bracket name (e.g. '[id]').\n *\n * Bracket keys are preserved so that `[id]`, `[...id]`, and `[[...id]]`\n * remain distinct entries. The coercion layer reconstructs bracket keys\n * from matched segment metadata to look up the correct codec.\n *\n * Design doc: design/41-global-params.md §Pipeline Integration\n */\n\nimport type { Codec } from '../codec.js';\nimport { isCodec, resolveCodecOrSchema } from '../schema-bridge.js';\n\n/**\n * Reconstruct the bracket key for a segment from its type and param name.\n * Used by the coercion layer to look up codecs in the bracket-keyed map.\n *\n * 'dynamic' + 'id' → '[id]'\n * 'catch-all' + 'slug' → '[...slug]'\n * 'optional-catch-all' + 'slug' → '[[...slug]]'\n */\nexport function toBracketKey(segmentType: string, paramName: string): string {\n switch (segmentType) {\n case 'catch-all':\n return `[...${paramName}]`;\n case 'optional-catch-all':\n return `[[...${paramName}]]`;\n default:\n return `[${paramName}]`;\n }\n}\n\nconst CATCH_ALL_RE = /^\\[\\.\\.\\..+\\]$/;\nconst OPTIONAL_CATCH_ALL_RE = /^\\[\\[\\.\\.\\..+\\]\\]$/;\n\nfunction isCatchAllKey(key: string): boolean {\n return CATCH_ALL_RE.test(key) || OPTIONAL_CATCH_ALL_RE.test(key);\n}\n\nfunction isOptionalCatchAllKey(key: string): boolean {\n return OPTIONAL_CATCH_ALL_RE.test(key);\n}\n\n/**\n * Resolve the global schema's segmentParams into a map of bracket-keyed\n * param name → resolved Codec.\n *\n * Keys are preserved exactly as written in `app/schema.ts` so that\n * `[id]`, `[...id]`, and `[[...id]]` remain distinct entries.\n * The coercion layer in `param-coercion.ts` reconstructs bracket keys\n * from matched segment metadata to look up the correct codec.\n *\n * Input: { '[id]': z.coerce.number(), '[...slug]': codec.string }\n * Output: { '[id]': Codec<number>, '[...slug]': Codec<string> }\n */\nexport function resolveSchemaCodecs(\n segmentParams: Record<string, unknown>\n): Record<string, Codec<unknown>> {\n const resolved: Record<string, Codec<unknown>> = Object.create(null);\n\n for (const [bracketName, value] of Object.entries(segmentParams)) {\n if (isCatchAllKey(bracketName) && isCodec(value) && !('__catchAll' in value)) {\n throw new Error(\n `[timber] Schema error: '${bracketName}' is a catch-all segment and requires an array codec ` +\n `(e.g. codec.catchAll(codec.string)). Got a scalar codec.`\n );\n }\n if (\n isOptionalCatchAllKey(bracketName) &&\n isCodec(value) &&\n '__catchAll' in value &&\n !('__optional' in value)\n ) {\n throw new Error(\n `[timber] Schema error: '${bracketName}' is an optional catch-all segment and requires codec.optionalCatchAll() ` +\n `(e.g. codec.optionalCatchAll(codec.string)). Got a non-optional catch-all codec.`\n );\n }\n resolved[bracketName] = resolveCodecOrSchema(bracketName, value, 'param');\n }\n\n return resolved;\n}\n"],"mappings":";;;;;;;;;;AAsBA,SAAgB,aAAa,aAAqB,WAA2B;CAC3E,QAAQ,aAAR;EACE,KAAK,aACH,OAAO,OAAO,UAAU;EAC1B,KAAK,sBACH,OAAO,QAAQ,UAAU;EAC3B,SACE,OAAO,IAAI,UAAU;CACzB;AACF;AAEA,IAAM,eAAe;AACrB,IAAM,wBAAwB;AAE9B,SAAS,cAAc,KAAsB;CAC3C,OAAO,aAAa,KAAK,GAAG,KAAK,sBAAsB,KAAK,GAAG;AACjE;AAEA,SAAS,sBAAsB,KAAsB;CACnD,OAAO,sBAAsB,KAAK,GAAG;AACvC;;;;;;;;;;;;;AAcA,SAAgB,oBACd,eACgC;CAChC,MAAM,WAA2C,OAAO,OAAO,IAAI;CAEnE,KAAK,MAAM,CAAC,aAAa,UAAU,OAAO,QAAQ,aAAa,GAAG;EAChE,IAAI,cAAc,WAAW,KAAK,QAAQ,KAAK,KAAK,EAAE,gBAAgB,QACpE,MAAM,IAAI,MACR,2BAA2B,YAAY,8GAEzC;EAEF,IACE,sBAAsB,WAAW,KACjC,QAAQ,KAAK,KACb,gBAAgB,SAChB,EAAE,gBAAgB,QAElB,MAAM,IAAI,MACR,2BAA2B,YAAY,0JAEzC;EAEF,SAAS,eAAe,qBAAqB,aAAa,OAAO,OAAO;CAC1E;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"resolve-schema-CBR6Lm4i.js","names":[],"sources":["../../src/params/resolve-schema.ts"],"sourcesContent":["/**\n * Schema resolution — resolves the global schema's segmentParams into\n * a runtime-ready codec map keyed by bracket name (e.g. '[id]').\n *\n * Bracket keys are preserved so that `[id]`, `[...id]`, and `[[...id]]`\n * remain distinct entries. The coercion layer reconstructs bracket keys\n * from matched segment metadata to look up the correct codec.\n *\n * Design doc: design/41-global-params.md §Pipeline Integration\n */\n\nimport type { Codec } from '../codec.ts';\nimport { isCodec, resolveCodecOrSchema } from '../schema-bridge.ts';\n\n/**\n * Reconstruct the bracket key for a segment from its type and param name.\n * Used by the coercion layer to look up codecs in the bracket-keyed map.\n *\n * 'dynamic' + 'id' → '[id]'\n * 'catch-all' + 'slug' → '[...slug]'\n * 'optional-catch-all' + 'slug' → '[[...slug]]'\n */\nexport function toBracketKey(segmentType: string, paramName: string): string {\n switch (segmentType) {\n case 'catch-all':\n return `[...${paramName}]`;\n case 'optional-catch-all':\n return `[[...${paramName}]]`;\n default:\n return `[${paramName}]`;\n }\n}\n\nconst CATCH_ALL_RE = /^\\[\\.\\.\\..+\\]$/;\nconst OPTIONAL_CATCH_ALL_RE = /^\\[\\[\\.\\.\\..+\\]\\]$/;\n\nfunction isCatchAllKey(key: string): boolean {\n return CATCH_ALL_RE.test(key) || OPTIONAL_CATCH_ALL_RE.test(key);\n}\n\nfunction isOptionalCatchAllKey(key: string): boolean {\n return OPTIONAL_CATCH_ALL_RE.test(key);\n}\n\n/**\n * Resolve the global schema's segmentParams into a map of bracket-keyed\n * param name → resolved Codec.\n *\n * Keys are preserved exactly as written in `app/schema.ts` so that\n * `[id]`, `[...id]`, and `[[...id]]` remain distinct entries.\n * The coercion layer in `param-coercion.ts` reconstructs bracket keys\n * from matched segment metadata to look up the correct codec.\n *\n * Input: { '[id]': z.coerce.number(), '[...slug]': codec.string }\n * Output: { '[id]': Codec<number>, '[...slug]': Codec<string> }\n */\nexport function resolveSchemaCodecs(\n segmentParams: Record<string, unknown>\n): Record<string, Codec<unknown>> {\n const resolved: Record<string, Codec<unknown>> = Object.create(null);\n\n for (const [bracketName, value] of Object.entries(segmentParams)) {\n if (isCatchAllKey(bracketName) && isCodec(value) && !('__catchAll' in value)) {\n throw new Error(\n `[timber] Schema error: '${bracketName}' is a catch-all segment and requires an array codec ` +\n `(e.g. codec.catchAll(codec.string)). Got a scalar codec.`\n );\n }\n if (\n isOptionalCatchAllKey(bracketName) &&\n isCodec(value) &&\n '__catchAll' in value &&\n !('__optional' in value)\n ) {\n throw new Error(\n `[timber] Schema error: '${bracketName}' is an optional catch-all segment and requires codec.optionalCatchAll() ` +\n `(e.g. codec.optionalCatchAll(codec.string)). Got a non-optional catch-all codec.`\n );\n }\n resolved[bracketName] = resolveCodecOrSchema(bracketName, value, 'param');\n }\n\n return resolved;\n}\n"],"mappings":";;;;;;;;;;AAsBA,SAAgB,aAAa,aAAqB,WAA2B;CAC3E,QAAQ,aAAR;EACE,KAAK,aACH,OAAO,OAAO,UAAU;EAC1B,KAAK,sBACH,OAAO,QAAQ,UAAU;EAC3B,SACE,OAAO,IAAI,UAAU;CACzB;AACF;AAEA,IAAM,eAAe;AACrB,IAAM,wBAAwB;AAE9B,SAAS,cAAc,KAAsB;CAC3C,OAAO,aAAa,KAAK,GAAG,KAAK,sBAAsB,KAAK,GAAG;AACjE;AAEA,SAAS,sBAAsB,KAAsB;CACnD,OAAO,sBAAsB,KAAK,GAAG;AACvC;;;;;;;;;;;;;AAcA,SAAgB,oBACd,eACgC;CAChC,MAAM,WAA2C,OAAO,OAAO,IAAI;CAEnE,KAAK,MAAM,CAAC,aAAa,UAAU,OAAO,QAAQ,aAAa,GAAG;EAChE,IAAI,cAAc,WAAW,KAAK,QAAQ,KAAK,KAAK,EAAE,gBAAgB,QACpE,MAAM,IAAI,MACR,2BAA2B,YAAY,8GAEzC;EAEF,IACE,sBAAsB,WAAW,KACjC,QAAQ,KAAK,KACb,gBAAgB,SAChB,EAAE,gBAAgB,QAElB,MAAM,IAAI,MACR,2BAA2B,YAAY,0JAEzC;EAEF,SAAS,eAAe,qBAAqB,aAAa,OAAO,OAAO;CAC1E;CAEA,OAAO;AACT"}
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll as t };
@@ -1 +1 @@
1
- {"version":3,"file":"router-ref-DuYuV_0Q.js","names":[],"sources":["../../src/client/router-ref.ts"],"sourcesContent":["// Global router reference — shared between browser-entry and client hooks.\n//\n// Delegates to client/state.ts for the actual module-level variable.\n// This ensures singleton semantics regardless of import path — all\n// callers converge on the same state.ts instance via the barrel.\n//\n// See design/18-build-system.md §\"Module Singleton Strategy\"\n\nimport type { RouterInstance } from './router-types.js';\nimport { globalRouter, _setGlobalRouter } from './state.js';\n\n/**\n * Set the global router instance. Called once during bootstrap.\n */\nexport function setGlobalRouter(router: RouterInstance): void {\n _setGlobalRouter(router);\n}\n\n/**\n * Get the global router instance. Throws if called before bootstrap.\n * Used by client-side hooks (usePendingNavigation, etc.)\n */\nexport function getRouter(): RouterInstance {\n if (!globalRouter) {\n throw new Error('[timber] Router not initialized. getRouter() was called before bootstrap().');\n }\n return globalRouter;\n}\n\n/**\n * Get the global router instance or null if not yet initialized.\n * Used by useRouter() methods to avoid silent failures — callers\n * can log a meaningful warning instead of silently no-oping.\n */\nexport function getRouterOrNull(): RouterInstance | null {\n return globalRouter;\n}\n\n/**\n * Reset the global router to null. Used only in tests to isolate\n * module-level state between test cases.\n * @internal\n */\nexport function resetGlobalRouter(): void {\n _setGlobalRouter(null);\n}\n"],"mappings":";;;;;AAcA,SAAgB,gBAAgB,QAA8B;CAC5D,iBAAiB,MAAM;AACzB;;;;;AAMA,SAAgB,YAA4B;CAC1C,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,6EAA6E;CAE/F,OAAO;AACT;;;;;;AAOA,SAAgB,kBAAyC;CACvD,OAAO;AACT"}
1
+ {"version":3,"file":"router-ref-DuYuV_0Q.js","names":[],"sources":["../../src/client/router-ref.ts"],"sourcesContent":["// Global router reference — shared between browser-entry and client hooks.\n//\n// Delegates to client/state.ts for the actual module-level variable.\n// This ensures singleton semantics regardless of import path — all\n// callers converge on the same state.ts instance via the barrel.\n//\n// See design/18-build-system.md §\"Module Singleton Strategy\"\n\nimport type { RouterInstance } from './router-types.ts';\nimport { globalRouter, _setGlobalRouter } from './state.ts';\n\n/**\n * Set the global router instance. Called once during bootstrap.\n */\nexport function setGlobalRouter(router: RouterInstance): void {\n _setGlobalRouter(router);\n}\n\n/**\n * Get the global router instance. Throws if called before bootstrap.\n * Used by client-side hooks (usePendingNavigation, etc.)\n */\nexport function getRouter(): RouterInstance {\n if (!globalRouter) {\n throw new Error('[timber] Router not initialized. getRouter() was called before bootstrap().');\n }\n return globalRouter;\n}\n\n/**\n * Get the global router instance or null if not yet initialized.\n * Used by useRouter() methods to avoid silent failures — callers\n * can log a meaningful warning instead of silently no-oping.\n */\nexport function getRouterOrNull(): RouterInstance | null {\n return globalRouter;\n}\n\n/**\n * Reset the global router to null. Used only in tests to isolate\n * module-level state between test cases.\n * @internal\n */\nexport function resetGlobalRouter(): void {\n _setGlobalRouter(null);\n}\n"],"mappings":";;;;;AAcA,SAAgB,gBAAgB,QAA8B;CAC5D,iBAAiB,MAAM;AACzB;;;;;AAMA,SAAgB,YAA4B;CAC1C,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,6EAA6E;CAE/F,OAAO;AACT;;;;;;AAOA,SAAgB,kBAAyC;CACvD,OAAO;AACT"}
@@ -40,7 +40,22 @@ var RSC_CONTENT_TYPE = "text/x-component";
40
40
  function isRscRequest(req) {
41
41
  return (req.headers.get("Accept") ?? "").includes(RSC_CONTENT_TYPE);
42
42
  }
43
+ /**
44
+ * Does this Content-Type header value designate an RSC Flight payload?
45
+ *
46
+ * Case-insensitive exact media-type match per RFC 9110 §8.3.1 — media types
47
+ * are case-insensitive. Parameters (`;charset=utf-8`) are stripped before
48
+ * comparison.
49
+ *
50
+ * Contrast with `isRscRequest`, which uses substring containment because
51
+ * `Accept` is a list of types. A `Content-Type` header names exactly one
52
+ * type, so substring would over-match (e.g. `text/x-component-v2`).
53
+ */
54
+ function isRscContentType(contentType) {
55
+ if (!contentType) return false;
56
+ return contentType.split(";")[0].trim().toLowerCase() === RSC_CONTENT_TYPE;
57
+ }
43
58
  //#endregion
44
- export { isRscRequest as n, RSC_CONTENT_TYPE as t };
59
+ export { isRscContentType as n, isRscRequest as r, RSC_CONTENT_TYPE as t };
45
60
 
46
- //# sourceMappingURL=rsc-media-type-DRqE_lD_.js.map
61
+ //# sourceMappingURL=rsc-media-type-DDc7duTD.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rsc-media-type-DRqE_lD_.js","names":[],"sources":["../../src/shared/rsc-media-type.ts"],"sourcesContent":["/**\n * The RSC Flight media type, and the request predicate over it.\n *\n * One module owns the string because two independently-written spellings of\n * \"is this an RSC request?\" must agree, and the consequence of them\n * disagreeing is cache poisoning rather than a visible bug. The Cloudflare\n * adapter's `isRsc` decides what may enter the edge cache; the origin's\n * pipeline decides which headers may vary the response. TIM-1269 made the\n * adapter's `VARY_HONORED` allowlist exempt `Accept` *because* `isRsc`\n * excludes Flight responses from the cache, and exempt the `X-Timber-*`\n * headers *because* the origin reads them only behind its own RSC check. If\n * one predicate is ever tightened (a real media-type parse, a\n * parameter-aware match) and the other is not, the adapter can classify a\n * request as a document while the origin treats it as RSC, and store a\n * Flight payload under the document's key — the class\n * `design/48-payload-addressing.md` exists to prevent.\n *\n * `tests/rsc-media-type-single-source.test.ts` fails if the literal reappears\n * in executable source outside this file.\n *\n * Isomorphic: zero imports, so `adapters/cloudflare.ts` — which Node's native\n * ESM loader evaluates before Vite's resolver exists — can load it and\n * interpolate the value into the generated worker. Same precedent as\n * `shared/rsc-cache-key.ts`.\n *\n * See design/19-client-navigation.md, design/25-production-deployments.md\n * §\"`Vary` and the Workers Cache API\".\n */\n\n/** Media type of a React Flight payload. */\nexport const RSC_CONTENT_TYPE = 'text/x-component';\n\n/**\n * Is this request asking for an RSC payload rather than a full document?\n *\n * Substring containment, deliberately: `Accept` is a list, and a client may\n * send `text/x-component;charset=utf-8` or list it alongside other types.\n * Tightening this to a real media-type parse is a behaviour change that has\n * to move the adapter's generated `isRsc` in the same commit — see above.\n */\nexport function isRscRequest(req: Request): boolean {\n return (req.headers.get('Accept') ?? '').includes(RSC_CONTENT_TYPE);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,IAAa,mBAAmB;;;;;;;;;AAUhC,SAAgB,aAAa,KAAuB;CAClD,QAAQ,IAAI,QAAQ,IAAI,QAAQ,KAAK,GAAA,CAAI,SAAS,gBAAgB;AACpE"}
1
+ {"version":3,"file":"rsc-media-type-DDc7duTD.js","names":[],"sources":["../../src/shared/rsc-media-type.ts"],"sourcesContent":["/**\n * The RSC Flight media type, and the request predicate over it.\n *\n * One module owns the string because two independently-written spellings of\n * \"is this an RSC request?\" must agree, and the consequence of them\n * disagreeing is cache poisoning rather than a visible bug. The Cloudflare\n * adapter's `isRsc` decides what may enter the edge cache; the origin's\n * pipeline decides which headers may vary the response. TIM-1269 made the\n * adapter's `VARY_HONORED` allowlist exempt `Accept` *because* `isRsc`\n * excludes Flight responses from the cache, and exempt the `X-Timber-*`\n * headers *because* the origin reads them only behind its own RSC check. If\n * one predicate is ever tightened (a real media-type parse, a\n * parameter-aware match) and the other is not, the adapter can classify a\n * request as a document while the origin treats it as RSC, and store a\n * Flight payload under the document's key — the class\n * `design/48-payload-addressing.md` exists to prevent.\n *\n * `tests/rsc-media-type-single-source.test.ts` fails if the literal reappears\n * in executable source outside this file.\n *\n * Isomorphic: zero imports, so `adapters/cloudflare.ts` — which Node's native\n * ESM loader evaluates before Vite's resolver exists — can load it and\n * interpolate the value into the generated worker. Same precedent as\n * `shared/rsc-cache-key.ts`.\n *\n * See design/19-client-navigation.md, design/25-production-deployments.md\n * §\"`Vary` and the Workers Cache API\".\n */\n\n/** Media type of a React Flight payload. */\nexport const RSC_CONTENT_TYPE = 'text/x-component';\n\n/**\n * Is this request asking for an RSC payload rather than a full document?\n *\n * Substring containment, deliberately: `Accept` is a list, and a client may\n * send `text/x-component;charset=utf-8` or list it alongside other types.\n * Tightening this to a real media-type parse is a behaviour change that has\n * to move the adapter's generated `isRsc` in the same commit — see above.\n */\nexport function isRscRequest(req: Request): boolean {\n return (req.headers.get('Accept') ?? '').includes(RSC_CONTENT_TYPE);\n}\n\n/**\n * Does this Content-Type header value designate an RSC Flight payload?\n *\n * Case-insensitive exact media-type match per RFC 9110 §8.3.1 — media types\n * are case-insensitive. Parameters (`;charset=utf-8`) are stripped before\n * comparison.\n *\n * Contrast with `isRscRequest`, which uses substring containment because\n * `Accept` is a list of types. A `Content-Type` header names exactly one\n * type, so substring would over-match (e.g. `text/x-component-v2`).\n */\nexport function isRscContentType(contentType: string | null): boolean {\n if (!contentType) return false;\n return contentType.split(';')[0].trim().toLowerCase() === RSC_CONTENT_TYPE;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,IAAa,mBAAmB;;;;;;;;;AAUhC,SAAgB,aAAa,KAAuB;CAClD,QAAQ,IAAI,QAAQ,IAAI,QAAQ,KAAK,GAAA,CAAI,SAAS,gBAAgB;AACpE;;;;;;;;;;;;AAaA,SAAgB,iBAAiB,aAAqC;CACpE,IAAI,CAAC,aAAa,OAAO;CACzB,OAAO,YAAY,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,YAAY,MAAM;AAC5D"}
@@ -0,0 +1,140 @@
1
+ import { join } from "node:path";
2
+ import { readdir } from "node:fs/promises";
3
+ //#region src/analyze/scan.ts
4
+ /**
5
+ * scan — project source-file disk scan shared by the crawl and the
6
+ * graph cache.
7
+ *
8
+ * One walker, one rule set: the crawl uses it to find files no graph
9
+ * reached (the provisional/pending set) and to bound graph membership,
10
+ * and the mtime-keyed graph cache fingerprints exactly the same file
11
+ * set — the three can never disagree about what "the project" is (a
12
+ * file the crawl classifies but the fingerprint ignores would make the
13
+ * cache silently stale).
14
+ *
15
+ * Skip rules are deliberately shallow: timber's router excludes only
16
+ * `_`-prefixed directories, so `app/.well-known/page.tsx` and
17
+ * `app/dist/page.tsx` are REAL routes — a rule that skipped `dist` or
18
+ * dot-directories at any depth would hide legitimate route files from
19
+ * the scan while the module graph still reached them (codex review,
20
+ * PR #1056). Therefore:
21
+ *
22
+ * - `node_modules` is skipped at ANY depth (never project source, and
23
+ * graph membership excludes it identically)
24
+ * - dot-prefixed and build-output directories (`dist`, `coverage`, …)
25
+ * are skipped only as the FIRST path segment under the root — that
26
+ * is where `.git`, `.timber`, `.wrangler`, and real build outputs
27
+ * live; deeper occurrences are walked
28
+ *
29
+ * Deliberately vite-free: the cache-hit path of `timber graph` reads
30
+ * this module without booting (or even importing) Vite.
31
+ *
32
+ * Design docs: 47-module-environment-tooling.md §2, §Cold-path policy.
33
+ */
34
+ /**
35
+ * Slash-normalize a Windows path — Vite's `normalizePath` for the
36
+ * vite-free callers (the graph cache-hit path must not import Vite).
37
+ * Same platform guard as Vite's: posix paths pass through untouched,
38
+ * so a filename containing a literal backslash is never corrupted.
39
+ */
40
+ var normalizeSlashes = process.platform === "win32" ? (path) => path.replace(/\\/g, "/") : (path) => path;
41
+ /**
42
+ * Directories never scanned when they are the first path segment under
43
+ * the root. `node_modules` is additionally skipped at any depth.
44
+ */
45
+ var SCAN_IGNORED_DIRS = /* @__PURE__ */ new Set([
46
+ "node_modules",
47
+ "dist",
48
+ "test-results",
49
+ "coverage"
50
+ ]);
51
+ /**
52
+ * Single source of truth for builtin source extensions. Includes mdx —
53
+ * timber supports page.mdx via pageExtensions, so an unreferenced MDX
54
+ * page must not vanish from --all output.
55
+ */
56
+ var BUILTIN_EXTENSIONS = [
57
+ "ts",
58
+ "tsx",
59
+ "js",
60
+ "jsx",
61
+ "mjs",
62
+ "cjs",
63
+ "mts",
64
+ "cts",
65
+ "mdx"
66
+ ];
67
+ /** Regex form of BUILTIN_EXTENSIONS for file-basename matching. */
68
+ var SOURCE_EXTENSIONS = new RegExp(`\\.(?:${BUILTIN_EXTENSIONS.join("|")})$`);
69
+ /** Set form for O(1) membership checks. */
70
+ var BUILTIN_EXTENSION_SET = new Set(BUILTIN_EXTENSIONS);
71
+ /**
72
+ * Build a regex that matches SOURCE_EXTENSIONS plus any extra
73
+ * extensions from the user's pageExtensions config. Returns the
74
+ * builtin regex unchanged when nothing new is added.
75
+ */
76
+ function buildSourceExtensions(pageExtensions) {
77
+ if (!pageExtensions) return SOURCE_EXTENSIONS;
78
+ const extras = pageExtensions.filter((ext) => !BUILTIN_EXTENSION_SET.has(ext));
79
+ if (extras.length === 0) return SOURCE_EXTENSIONS;
80
+ const escaped = extras.map((ext) => ext.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
81
+ return new RegExp(`\\.(?:${BUILTIN_EXTENSIONS.join("|")}|${escaped.join("|")})$`);
82
+ }
83
+ /** Whether a directory SEGMENT is skipped at the given depth (0 = root child). */
84
+ function isSkippedDirSegment(segment, depth) {
85
+ if (segment === "node_modules") return true;
86
+ if (depth === 0 && (segment.startsWith(".") || SCAN_IGNORED_DIRS.has(segment))) return true;
87
+ return false;
88
+ }
89
+ /** Whether a file basename is admitted as project source. */
90
+ function isSourceBasename(base, depth, extensions) {
91
+ if (depth === 0 && base.startsWith(".")) return false;
92
+ if (!(extensions ?? SOURCE_EXTENSIONS).test(base)) return false;
93
+ if (/\.d\.[mc]?ts$/.test(base)) return false;
94
+ return true;
95
+ }
96
+ /**
97
+ * Whether an absolute, slash-normalized path is one the scanner WOULD
98
+ * admit — the same segment rules the walker applies, so a
99
+ * directly-addressed path (`package.json`, `<root>/dist/generated.js`,
100
+ * `types.d.ts`, a nested node_modules file) is answered exactly the
101
+ * way the scan-based sweep would answer it: by exclusion. Existence
102
+ * and is-a-file checks remain the caller's (this is pure path logic).
103
+ */
104
+ function isScannableSourceFile(file, root, extensions) {
105
+ if (!file.startsWith(root + "/")) return false;
106
+ const segments = file.slice(root.length + 1).split("/");
107
+ const base = segments[segments.length - 1];
108
+ for (let depth = 0; depth < segments.length - 1; depth++) if (isSkippedDirSegment(segments[depth], depth)) return false;
109
+ return isSourceBasename(base, segments.length - 1, extensions);
110
+ }
111
+ /**
112
+ * Recursively list project source files on disk.
113
+ *
114
+ * Unreadable directories are reported through `onFailure`, not thrown
115
+ * and not swallowed — this walker exists to keep files from silently
116
+ * vanishing, so a directory it cannot see must be visible too.
117
+ */
118
+ async function scanProjectSourceFiles(dir, out, onFailure, depth = 0, extensions) {
119
+ let entries;
120
+ try {
121
+ entries = await readdir(dir, { withFileTypes: true });
122
+ } catch (error) {
123
+ onFailure({
124
+ dir,
125
+ message: `directory scan failed: ${error instanceof Error ? error.message : String(error)}`
126
+ });
127
+ return;
128
+ }
129
+ for (const entry of entries) {
130
+ const full = join(dir, entry.name);
131
+ if (entry.isDirectory()) {
132
+ if (isSkippedDirSegment(entry.name, depth)) continue;
133
+ await scanProjectSourceFiles(full, out, onFailure, depth + 1, extensions);
134
+ } else if (entry.isFile() && isSourceBasename(entry.name, depth, extensions)) out.push(full);
135
+ }
136
+ }
137
+ //#endregion
138
+ export { scanProjectSourceFiles as i, isScannableSourceFile as n, normalizeSlashes as r, buildSourceExtensions as t };
139
+
140
+ //# sourceMappingURL=scan-BoP17W3w.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-BoP17W3w.js","names":[],"sources":["../../src/analyze/scan.ts"],"sourcesContent":["/**\n * scan — project source-file disk scan shared by the crawl and the\n * graph cache.\n *\n * One walker, one rule set: the crawl uses it to find files no graph\n * reached (the provisional/pending set) and to bound graph membership,\n * and the mtime-keyed graph cache fingerprints exactly the same file\n * set — the three can never disagree about what \"the project\" is (a\n * file the crawl classifies but the fingerprint ignores would make the\n * cache silently stale).\n *\n * Skip rules are deliberately shallow: timber's router excludes only\n * `_`-prefixed directories, so `app/.well-known/page.tsx` and\n * `app/dist/page.tsx` are REAL routes — a rule that skipped `dist` or\n * dot-directories at any depth would hide legitimate route files from\n * the scan while the module graph still reached them (codex review,\n * PR #1056). Therefore:\n *\n * - `node_modules` is skipped at ANY depth (never project source, and\n * graph membership excludes it identically)\n * - dot-prefixed and build-output directories (`dist`, `coverage`, …)\n * are skipped only as the FIRST path segment under the root — that\n * is where `.git`, `.timber`, `.wrangler`, and real build outputs\n * live; deeper occurrences are walked\n *\n * Deliberately vite-free: the cache-hit path of `timber graph` reads\n * this module without booting (or even importing) Vite.\n *\n * Design docs: 47-module-environment-tooling.md §2, §Cold-path policy.\n */\n\nimport { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n/**\n * Slash-normalize a Windows path — Vite's `normalizePath` for the\n * vite-free callers (the graph cache-hit path must not import Vite).\n * Same platform guard as Vite's: posix paths pass through untouched,\n * so a filename containing a literal backslash is never corrupted.\n */\nexport const normalizeSlashes: (path: string) => string =\n process.platform === 'win32' ? (path) => path.replace(/\\\\/g, '/') : (path) => path;\n\n/** A scan failure the caller records instead of swallowing. */\nexport interface ScanFailure {\n dir: string;\n message: string;\n}\n\n/**\n * Directories never scanned when they are the first path segment under\n * the root. `node_modules` is additionally skipped at any depth.\n */\nexport const SCAN_IGNORED_DIRS = new Set(['node_modules', 'dist', 'test-results', 'coverage']);\n\n/**\n * Single source of truth for builtin source extensions. Includes mdx —\n * timber supports page.mdx via pageExtensions, so an unreferenced MDX\n * page must not vanish from --all output.\n */\nconst BUILTIN_EXTENSIONS = ['ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'mts', 'cts', 'mdx'] as const;\n\n/** Regex form of BUILTIN_EXTENSIONS for file-basename matching. */\nexport const SOURCE_EXTENSIONS = new RegExp(`\\\\.(?:${BUILTIN_EXTENSIONS.join('|')})$`);\n\n/** Set form for O(1) membership checks. */\nconst BUILTIN_EXTENSION_SET = new Set<string>(BUILTIN_EXTENSIONS);\n\n/**\n * Build a regex that matches SOURCE_EXTENSIONS plus any extra\n * extensions from the user's pageExtensions config. Returns the\n * builtin regex unchanged when nothing new is added.\n */\nexport function buildSourceExtensions(pageExtensions?: readonly string[]): RegExp {\n if (!pageExtensions) return SOURCE_EXTENSIONS;\n const extras = pageExtensions.filter((ext) => !BUILTIN_EXTENSION_SET.has(ext));\n if (extras.length === 0) return SOURCE_EXTENSIONS;\n const escaped = extras.map((ext) => ext.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'));\n return new RegExp(`\\\\.(?:${BUILTIN_EXTENSIONS.join('|')}|${escaped.join('|')})$`);\n}\n\n/** Whether a directory SEGMENT is skipped at the given depth (0 = root child). */\nfunction isSkippedDirSegment(segment: string, depth: number): boolean {\n if (segment === 'node_modules') return true;\n if (depth === 0 && (segment.startsWith('.') || SCAN_IGNORED_DIRS.has(segment))) return true;\n return false;\n}\n\n/** Whether a file basename is admitted as project source. */\nfunction isSourceBasename(base: string, depth: number, extensions?: RegExp): boolean {\n if (depth === 0 && base.startsWith('.')) return false;\n if (!(extensions ?? SOURCE_EXTENSIONS).test(base)) return false;\n // Declaration files are types-only — they never run in any environment.\n if (/\\.d\\.[mc]?ts$/.test(base)) return false;\n return true;\n}\n\n/**\n * Whether an absolute, slash-normalized path is one the scanner WOULD\n * admit — the same segment rules the walker applies, so a\n * directly-addressed path (`package.json`, `<root>/dist/generated.js`,\n * `types.d.ts`, a nested node_modules file) is answered exactly the\n * way the scan-based sweep would answer it: by exclusion. Existence\n * and is-a-file checks remain the caller's (this is pure path logic).\n */\nexport function isScannableSourceFile(file: string, root: string, extensions?: RegExp): boolean {\n if (!file.startsWith(root + '/')) return false;\n const segments = file.slice(root.length + 1).split('/');\n const base = segments[segments.length - 1];\n for (let depth = 0; depth < segments.length - 1; depth++) {\n if (isSkippedDirSegment(segments[depth], depth)) return false;\n }\n return isSourceBasename(base, segments.length - 1, extensions);\n}\n\n/**\n * Recursively list project source files on disk.\n *\n * Unreadable directories are reported through `onFailure`, not thrown\n * and not swallowed — this walker exists to keep files from silently\n * vanishing, so a directory it cannot see must be visible too.\n */\nexport async function scanProjectSourceFiles(\n dir: string,\n out: string[],\n onFailure: (failure: ScanFailure) => void,\n depth = 0,\n extensions?: RegExp\n): Promise<void> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (error) {\n onFailure({\n dir,\n message: `directory scan failed: ${error instanceof Error ? error.message : String(error)}`,\n });\n return;\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n if (isSkippedDirSegment(entry.name, depth)) continue;\n await scanProjectSourceFiles(full, out, onFailure, depth + 1, extensions);\n } else if (entry.isFile() && isSourceBasename(entry.name, depth, extensions)) {\n out.push(full);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,IAAa,mBACX,QAAQ,aAAa,WAAW,SAAS,KAAK,QAAQ,OAAO,GAAG,KAAK,SAAS;;;;;AAYhF,IAAa,oCAAoB,IAAI,IAAI;CAAC;CAAgB;CAAQ;CAAgB;AAAU,CAAC;;;;;;AAO7F,IAAM,qBAAqB;CAAC;CAAM;CAAO;CAAM;CAAO;CAAO;CAAO;CAAO;CAAO;AAAK;;AAGvF,IAAa,oBAAoB,IAAI,OAAO,SAAS,mBAAmB,KAAK,GAAG,EAAE,GAAG;;AAGrF,IAAM,wBAAwB,IAAI,IAAY,kBAAkB;;;;;;AAOhE,SAAgB,sBAAsB,gBAA4C;CAChF,IAAI,CAAC,gBAAgB,OAAO;CAC5B,MAAM,SAAS,eAAe,QAAQ,QAAQ,CAAC,sBAAsB,IAAI,GAAG,CAAC;CAC7E,IAAI,OAAO,WAAW,GAAG,OAAO;CAChC,MAAM,UAAU,OAAO,KAAK,QAAQ,IAAI,QAAQ,uBAAuB,MAAM,CAAC;CAC9E,OAAO,IAAI,OAAO,SAAS,mBAAmB,KAAK,GAAG,EAAE,GAAG,QAAQ,KAAK,GAAG,EAAE,GAAG;AAClF;;AAGA,SAAS,oBAAoB,SAAiB,OAAwB;CACpE,IAAI,YAAY,gBAAgB,OAAO;CACvC,IAAI,UAAU,MAAM,QAAQ,WAAW,GAAG,KAAK,kBAAkB,IAAI,OAAO,IAAI,OAAO;CACvF,OAAO;AACT;;AAGA,SAAS,iBAAiB,MAAc,OAAe,YAA8B;CACnF,IAAI,UAAU,KAAK,KAAK,WAAW,GAAG,GAAG,OAAO;CAChD,IAAI,EAAE,cAAc,kBAAA,CAAmB,KAAK,IAAI,GAAG,OAAO;CAE1D,IAAI,gBAAgB,KAAK,IAAI,GAAG,OAAO;CACvC,OAAO;AACT;;;;;;;;;AAUA,SAAgB,sBAAsB,MAAc,MAAc,YAA8B;CAC9F,IAAI,CAAC,KAAK,WAAW,OAAO,GAAG,GAAG,OAAO;CACzC,MAAM,WAAW,KAAK,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG;CACtD,MAAM,OAAO,SAAS,SAAS,SAAS;CACxC,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,SAAS,GAAG,SAC/C,IAAI,oBAAoB,SAAS,QAAQ,KAAK,GAAG,OAAO;CAE1D,OAAO,iBAAiB,MAAM,SAAS,SAAS,GAAG,UAAU;AAC/D;;;;;;;;AASA,eAAsB,uBACpB,KACA,KACA,WACA,QAAQ,GACR,YACe;CACf,IAAI;CACJ,IAAI;EACF,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;CACtD,SAAS,OAAO;EACd,UAAU;GACR;GACA,SAAS,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAC1F,CAAC;EACD;CACF;CACA,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,OAAO,KAAK,KAAK,MAAM,IAAI;EACjC,IAAI,MAAM,YAAY,GAAG;GACvB,IAAI,oBAAoB,MAAM,MAAM,KAAK,GAAG;GAC5C,MAAM,uBAAuB,MAAM,KAAK,WAAW,QAAQ,GAAG,UAAU;EAC1E,OAAO,IAAI,MAAM,OAAO,KAAK,iBAAiB,MAAM,MAAM,OAAO,UAAU,GACzE,IAAI,KAAK,IAAI;CAEjB;AACF"}