blume 2.1.3 → 2.2.1

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 (397) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +134 -0
  3. package/README.md +4 -4
  4. package/dist/cli/{chunk-y4msrwm9.js → chunk-080mfch6.js} +15 -15
  5. package/dist/cli/{chunk-gfc5fqvf.js → chunk-1ch3ct3r.js} +18 -18
  6. package/dist/cli/{chunk-gfc5fqvf.js.map → chunk-1ch3ct3r.js.map} +1 -1
  7. package/dist/cli/{chunk-32khwcb6.js → chunk-2ssh60qh.js} +42 -69
  8. package/dist/cli/{chunk-32khwcb6.js.map → chunk-2ssh60qh.js.map} +9 -10
  9. package/dist/cli/{chunk-9qzgg6mj.js → chunk-34wap3ed.js} +3 -3
  10. package/dist/cli/{chunk-k3gr1nm9.js → chunk-40vk8kgf.js} +13 -16
  11. package/dist/cli/{chunk-k3gr1nm9.js.map → chunk-40vk8kgf.js.map} +3 -3
  12. package/dist/cli/chunk-487b95qy.js +329 -0
  13. package/dist/cli/chunk-487b95qy.js.map +13 -0
  14. package/dist/cli/chunk-4zxh25hc.js +157 -0
  15. package/dist/cli/chunk-4zxh25hc.js.map +10 -0
  16. package/dist/cli/chunk-69rjf786.js +146 -0
  17. package/dist/cli/chunk-69rjf786.js.map +11 -0
  18. package/dist/cli/{chunk-dqhg54mr.js → chunk-9h8mh2tk.js} +3 -3
  19. package/dist/cli/{chunk-dqhg54mr.js.map → chunk-9h8mh2tk.js.map} +2 -2
  20. package/dist/cli/{chunk-bqxaqn5p.js → chunk-9jqmq5hv.js} +8 -8
  21. package/dist/cli/{chunk-bqxaqn5p.js.map → chunk-9jqmq5hv.js.map} +1 -1
  22. package/dist/cli/{chunk-dv2z0rzf.js → chunk-aafhwx74.js} +38 -13
  23. package/dist/cli/{chunk-dv2z0rzf.js.map → chunk-aafhwx74.js.map} +5 -4
  24. package/dist/cli/{chunk-desvm72z.js → chunk-b680sv30.js} +22 -26
  25. package/dist/cli/chunk-b680sv30.js.map +13 -0
  26. package/dist/cli/{chunk-0w6hs479.js → chunk-beb0z983.js} +30 -18
  27. package/dist/cli/chunk-beb0z983.js.map +10 -0
  28. package/dist/cli/{chunk-1f882900.js → chunk-c5bjxq8v.js} +2 -2
  29. package/dist/cli/chunk-e1n41w9m.js +155 -0
  30. package/dist/cli/chunk-e1n41w9m.js.map +11 -0
  31. package/dist/cli/{chunk-sc93apfs.js → chunk-etckvbrh.js} +17 -17
  32. package/dist/cli/{chunk-sc93apfs.js.map → chunk-etckvbrh.js.map} +2 -2
  33. package/dist/cli/{chunk-bxwhtvw8.js → chunk-f260jdrn.js} +5 -5
  34. package/dist/cli/{chunk-74wfhv79.js → chunk-fnxgtjeq.js} +1 -1
  35. package/dist/cli/{chunk-ms9z66nz.js → chunk-gwy55cx3.js} +2 -2
  36. package/dist/cli/{chunk-ms9z66nz.js.map → chunk-gwy55cx3.js.map} +2 -2
  37. package/dist/cli/{chunk-dhwtqnnd.js → chunk-gxhcf2hs.js} +2 -2
  38. package/dist/cli/{chunk-tfycddbt.js → chunk-h0qwdbem.js} +2 -2
  39. package/dist/cli/{chunk-nbyvgnnm.js → chunk-hktq4j5r.js} +109 -49
  40. package/dist/cli/chunk-hktq4j5r.js.map +36 -0
  41. package/dist/cli/{chunk-twy7psdz.js → chunk-hn3g2b89.js} +14 -10
  42. package/dist/cli/chunk-hn3g2b89.js.map +10 -0
  43. package/dist/cli/{chunk-j1x92mx9.js → chunk-j4nfgn2j.js} +1 -1
  44. package/dist/cli/{chunk-dpy8qdjf.js → chunk-k45sq16q.js} +74 -183
  45. package/dist/cli/chunk-k45sq16q.js.map +18 -0
  46. package/dist/cli/{chunk-5cmts6dv.js → chunk-kmswjxj9.js} +7 -7
  47. package/dist/cli/{chunk-5cmts6dv.js.map → chunk-kmswjxj9.js.map} +1 -1
  48. package/dist/cli/{chunk-36bxs9c7.js → chunk-nqna8dzp.js} +27 -23
  49. package/dist/cli/chunk-nqna8dzp.js.map +10 -0
  50. package/dist/cli/{chunk-a57yh0h9.js → chunk-p834rkcn.js} +7 -7
  51. package/dist/cli/{chunk-a57yh0h9.js.map → chunk-p834rkcn.js.map} +1 -1
  52. package/dist/cli/{chunk-60hz265r.js → chunk-ppa6mg4d.js} +24 -11
  53. package/dist/cli/chunk-ppa6mg4d.js.map +10 -0
  54. package/dist/cli/{chunk-s0bdnc7v.js → chunk-q1wwrxzw.js} +5 -4
  55. package/dist/cli/chunk-q1wwrxzw.js.map +10 -0
  56. package/dist/cli/{chunk-ave1wcbr.js → chunk-qcyxkj44.js} +1 -1
  57. package/dist/cli/{chunk-124fvmzq.js → chunk-r5nm9w0c.js} +11183 -8806
  58. package/dist/cli/{chunk-124fvmzq.js.map → chunk-r5nm9w0c.js.map} +82 -66
  59. package/dist/cli/{chunk-ckrcm08h.js → chunk-rtvgmg2j.js} +48 -62
  60. package/dist/cli/{chunk-ckrcm08h.js.map → chunk-rtvgmg2j.js.map} +4 -5
  61. package/dist/cli/{chunk-297ajdcv.js → chunk-t2h8pwy1.js} +6 -6
  62. package/dist/cli/{chunk-297ajdcv.js.map → chunk-t2h8pwy1.js.map} +3 -3
  63. package/dist/cli/{chunk-gxtg6ed2.js → chunk-x60e15st.js} +21 -21
  64. package/dist/cli/{chunk-gxtg6ed2.js.map → chunk-x60e15st.js.map} +3 -3
  65. package/dist/cli/{chunk-58bt3hag.js → chunk-x7bh6d9j.js} +4 -4
  66. package/dist/cli/{chunk-hvcxng5f.js → chunk-ydqzkhjn.js} +6 -6
  67. package/dist/cli/{chunk-kdpzw38a.js → chunk-yg8ckc3g.js} +95 -7
  68. package/dist/cli/chunk-yg8ckc3g.js.map +11 -0
  69. package/dist/cli/{chunk-0pmb4tr4.js → chunk-zxd5jrgx.js} +1205 -222
  70. package/dist/cli/chunk-zxd5jrgx.js.map +44 -0
  71. package/dist/cli/index.js +78 -42
  72. package/dist/cli/index.js.map +7 -6
  73. package/dist/types/ai/changelog-components.d.ts +18 -0
  74. package/dist/types/ai/changelog-markdown.d.ts +12 -0
  75. package/dist/types/ai/openapi-components.d.ts +7 -7
  76. package/dist/types/ai/operation-details.d.ts +39 -0
  77. package/dist/types/ai/relative-links.d.ts +3 -1
  78. package/dist/types/ai/serializers.d.ts +6 -4
  79. package/dist/types/analytics/head.d.ts +4 -2
  80. package/dist/types/analytics/script.d.ts +8 -2
  81. package/dist/types/components/content/youtube.d.ts +20 -0
  82. package/dist/types/components/layout/nav-utils.d.ts +8 -0
  83. package/dist/types/components/openapi/example-panels.d.ts +33 -0
  84. package/dist/types/components/openapi/helpers.d.ts +53 -11
  85. package/dist/types/components/openapi/snippets.d.ts +7 -1
  86. package/dist/types/core/alert-diagnostics.d.ts +10 -0
  87. package/dist/types/core/builtin-tags.d.ts +16 -0
  88. package/dist/types/core/changelog-list.d.ts +48 -0
  89. package/dist/types/core/closest-match.d.ts +6 -0
  90. package/dist/types/core/code-fence-diagnostics.d.ts +18 -0
  91. package/dist/types/core/code-fences.d.ts +8 -1
  92. package/dist/types/core/config-input.d.ts +38 -6
  93. package/dist/types/core/content-assets.d.ts +16 -18
  94. package/dist/types/core/data.d.ts +6 -2
  95. package/dist/types/core/diagnostics.d.ts +14 -0
  96. package/dist/types/core/directive-diagnostics.d.ts +22 -8
  97. package/dist/types/core/former-routes.d.ts +14 -0
  98. package/dist/types/core/github.d.ts +5 -4
  99. package/dist/types/core/heading-markers.d.ts +65 -2
  100. package/dist/types/core/hidden-pages.d.ts +3 -0
  101. package/dist/types/core/includes.d.ts +23 -0
  102. package/dist/types/core/last-modified.d.ts +18 -6
  103. package/dist/types/core/links.d.ts +42 -2
  104. package/dist/types/core/load-module.d.ts +19 -4
  105. package/dist/types/core/manifest.d.ts +14 -1
  106. package/dist/types/core/markdown-mirrors.d.ts +22 -0
  107. package/dist/types/core/mcp-clients.d.ts +47 -0
  108. package/dist/types/core/mdx-elements.d.ts +32 -0
  109. package/dist/types/core/mdx-syntax.d.ts +100 -0
  110. package/dist/types/core/meta-diagnostics.d.ts +7 -0
  111. package/dist/types/core/meta.d.ts +32 -5
  112. package/dist/types/core/nav-diagnostics.d.ts +16 -2
  113. package/dist/types/core/navigation.d.ts +13 -0
  114. package/dist/types/core/ordering-prefix.d.ts +6 -0
  115. package/dist/types/core/pinned-ids.d.ts +23 -0
  116. package/dist/types/core/project-graph.d.ts +9 -1
  117. package/dist/types/core/redirect-patterns.d.ts +18 -0
  118. package/dist/types/core/relative-files.d.ts +31 -0
  119. package/dist/types/core/schema.d.ts +322 -11
  120. package/dist/types/core/sources/normalize.d.ts +101 -9
  121. package/dist/types/core/sources/types.d.ts +16 -0
  122. package/dist/types/core/static-files.d.ts +10 -0
  123. package/dist/types/core/static-host.d.ts +42 -0
  124. package/dist/types/core/svg-images.d.ts +26 -0
  125. package/dist/types/core/syntax-diagnostics.d.ts +14 -0
  126. package/dist/types/core/types.d.ts +42 -1
  127. package/dist/types/deploy/generated-files.d.ts +41 -0
  128. package/dist/types/deploy/redirects.d.ts +21 -7
  129. package/dist/types/markdown/code-title.d.ts +9 -5
  130. package/dist/types/markdown/directives.d.ts +8 -0
  131. package/dist/types/markdown/fence-language.d.ts +51 -0
  132. package/dist/types/markdown/fence-meta.d.ts +5 -0
  133. package/dist/types/markdown/github-alerts.d.ts +35 -0
  134. package/dist/types/openapi/asyncapi.d.ts +6 -5
  135. package/dist/types/openapi/checks.d.ts +10 -5
  136. package/dist/types/openapi/model.d.ts +55 -8
  137. package/dist/types/openapi/parse.d.ts +4 -1
  138. package/dist/types/ratelimit/index.d.ts +2 -0
  139. package/dist/types/ratelimit/memory.d.ts +1 -1
  140. package/dist/types/ratelimit/schema.d.ts +40 -0
  141. package/dist/types/ratelimit/unkey.d.ts +48 -0
  142. package/dist/types/sources/filesystem.d.ts +14 -4
  143. package/dist/types/sources/mdx-remote.d.ts +6 -3
  144. package/dist/types/sources/registry.d.ts +3 -3
  145. package/dist/types/theme/color.d.ts +33 -0
  146. package/dist/types/theme/palette.d.ts +122 -0
  147. package/docs/01-quickstart.mdx +1 -1
  148. package/docs/02-deployment.mdx +24 -8
  149. package/docs/04-migrating.mdx +16 -4
  150. package/docs/advanced/changelog.mdx +27 -1
  151. package/docs/advanced/skills.mdx +1 -1
  152. package/docs/cli/audit.mdx +1 -1
  153. package/docs/cli/doctor.mdx +2 -2
  154. package/docs/cli/evals.mdx +1 -1
  155. package/docs/cli/index.mdx +4 -2
  156. package/docs/cli/validate.mdx +10 -7
  157. package/docs/configuration/analytics.mdx +2 -0
  158. package/docs/configuration/customization.mdx +3 -1
  159. package/docs/configuration/index.mdx +7 -6
  160. package/docs/configuration/rate-limiting.mdx +20 -1
  161. package/docs/configuration/theming.mdx +5 -1
  162. package/docs/content/components.mdx +26 -6
  163. package/docs/content/frontmatter.mdx +1 -1
  164. package/docs/content/i18n.mdx +1 -1
  165. package/docs/content/includes.mdx +6 -2
  166. package/docs/content/index.mdx +11 -1
  167. package/docs/content/islands.mdx +2 -0
  168. package/docs/content/meta.mdx +9 -3
  169. package/docs/content/navigation.mdx +14 -6
  170. package/docs/content/sources/obsidian.mdx +1 -1
  171. package/docs/content/sources/remote-mdx.mdx +3 -1
  172. package/docs/content/syntax.mdx +76 -8
  173. package/docs/content/variables.mdx +3 -1
  174. package/docs/discoverability/agent-discovery.mdx +1 -1
  175. package/docs/discoverability/json-api.mdx +1 -1
  176. package/docs/discoverability/llms-txt.mdx +1 -1
  177. package/docs/discoverability/markdown.mdx +2 -2
  178. package/docs/discoverability/mcp.mdx +40 -8
  179. package/docs/discoverability/open-graph.mdx +1 -1
  180. package/docs/discoverability/sitemap-and-robots.mdx +1 -1
  181. package/docs/references/graphql.mdx +2 -0
  182. package/docs/references/openapi.mdx +45 -7
  183. package/package.json +4 -4
  184. package/skills/blume/SKILL.md +2 -2
  185. package/skills/blume-migrate/SKILL.md +51 -29
  186. package/skills/blume-migrate/references/docsify.md +262 -0
  187. package/skills/blume-migrate/references/docus.md +298 -0
  188. package/skills/blume-migrate/references/docusaurus.md +5 -5
  189. package/skills/blume-migrate/references/fern.md +327 -0
  190. package/skills/blume-migrate/references/fumadocs.md +1 -1
  191. package/skills/blume-migrate/references/gitbook.md +267 -0
  192. package/skills/blume-migrate/references/github-wiki.md +259 -0
  193. package/skills/blume-migrate/references/jekyll.md +253 -0
  194. package/skills/blume-migrate/references/mdbook.md +256 -0
  195. package/skills/blume-migrate/references/mintlify.md +5 -5
  196. package/skills/blume-migrate/references/mkdocs.md +236 -0
  197. package/skills/blume-migrate/references/monorepo.md +20 -8
  198. package/skills/blume-migrate/references/nextra.md +5 -5
  199. package/skills/blume-migrate/references/readme.md +257 -0
  200. package/skills/blume-migrate/references/redocly.md +198 -0
  201. package/skills/blume-migrate/references/starlight.md +3 -3
  202. package/skills/blume-migrate/references/vitepress.md +204 -0
  203. package/skills/blume-migrate/references/vuepress.md +271 -0
  204. package/skills/blume-migrate/scripts/docsify-codemod.mjs +2387 -0
  205. package/skills/blume-migrate/scripts/docus-codemod.mjs +2542 -0
  206. package/skills/blume-migrate/scripts/fern-codemod.mjs +2633 -0
  207. package/skills/blume-migrate/scripts/github-wiki-codemod.mjs +2808 -0
  208. package/skills/blume-migrate/scripts/include-excerpts.mjs +649 -0
  209. package/skills/blume-migrate/scripts/jekyll-codemod.mjs +3649 -0
  210. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +17 -13
  211. package/skills/blume-migrate/scripts/mkdocs-codemod.mjs +2526 -0
  212. package/skills/blume-migrate/scripts/operation-routes.mjs +508 -0
  213. package/skills/blume-migrate/scripts/pin-heading-ids.mjs +1049 -0
  214. package/skills/blume-migrate/scripts/readme-codemod.mjs +4139 -0
  215. package/skills/blume-migrate/scripts/vitepress-codemod.mjs +1511 -0
  216. package/src/ai/changelog-components.ts +24 -0
  217. package/src/ai/changelog-markdown.ts +45 -41
  218. package/src/ai/component-markdown.ts +22 -9
  219. package/src/ai/llms.ts +36 -5
  220. package/src/ai/markdown.ts +2 -2
  221. package/src/ai/openapi-components.ts +25 -9
  222. package/src/ai/operation-details.ts +208 -0
  223. package/src/ai/relative-links.ts +48 -8
  224. package/src/ai/serializers.ts +7 -6
  225. package/src/ai/site-skill.ts +6 -2
  226. package/src/analytics/head.ts +11 -5
  227. package/src/analytics/script.ts +13 -3
  228. package/src/astro/generate.ts +47 -11
  229. package/src/astro/index.ts +1 -0
  230. package/src/astro/integration.ts +27 -1
  231. package/src/astro/mdx-source-errors.ts +46 -0
  232. package/src/astro/templates.ts +93 -189
  233. package/src/audit/checks/redirects.ts +5 -1
  234. package/src/audit/redirects.ts +36 -19
  235. package/src/audit/report.ts +22 -9
  236. package/src/audit/run.ts +12 -28
  237. package/src/audit/terms.ts +23 -0
  238. package/src/audit/url.ts +2 -2
  239. package/src/cli/build-failure.ts +256 -7
  240. package/src/cli/command-meta.ts +1 -1
  241. package/src/cli/commands/audit.ts +1 -1
  242. package/src/cli/commands/build.ts +12 -3
  243. package/src/cli/commands/check.ts +13 -2
  244. package/src/cli/commands/dev.ts +1 -1
  245. package/src/cli/commands/doctor.ts +4 -2
  246. package/src/cli/commands/init.ts +3 -3
  247. package/src/cli/commands/preview.ts +17 -1
  248. package/src/cli/commands/validate.ts +22 -10
  249. package/src/cli/prepare.ts +1 -1
  250. package/src/cli/preview-pages.ts +161 -0
  251. package/src/cli/required-secrets.ts +0 -1
  252. package/src/cli/unknown-flags.ts +1 -42
  253. package/src/components/code-copy.ts +51 -0
  254. package/src/components/code-language.ts +75 -0
  255. package/src/components/content/AccordionItem.astro +16 -1
  256. package/src/components/content/Callout.astro +11 -1
  257. package/src/components/content/Changelog.astro +189 -0
  258. package/src/components/content/CodeBlock.astro +8 -11
  259. package/src/components/content/Tabs.astro +16 -2
  260. package/src/components/content/YouTube.astro +6 -4
  261. package/src/components/content/code-block.ts +33 -0
  262. package/src/components/content/content-strings.ts +5 -1
  263. package/src/components/content/inline-markdown.ts +35 -8
  264. package/src/components/content/youtube.ts +49 -7
  265. package/src/components/layout/Analytics.astro +5 -1
  266. package/src/components/layout/NavTree.astro +8 -3
  267. package/src/components/layout/PageActions.astro +81 -23
  268. package/src/components/layout/RootLayout.astro +35 -32
  269. package/src/components/layout/SiteFooter.astro +31 -8
  270. package/src/components/layout/nav-utils.ts +14 -0
  271. package/src/components/layout/search/pagefind.ts +2 -1
  272. package/src/components/openapi/Operation.astro +4 -0
  273. package/src/components/openapi/PanelTabs.astro +9 -3
  274. package/src/components/openapi/RequestBody.astro +42 -8
  275. package/src/components/openapi/RequestPanel.astro +34 -53
  276. package/src/components/openapi/example-panels.ts +110 -0
  277. package/src/components/openapi/helpers.ts +195 -20
  278. package/src/components/openapi/operation-model.ts +63 -26
  279. package/src/components/openapi/request.ts +13 -0
  280. package/src/components/openapi/snippets.ts +14 -2
  281. package/src/core/alert-diagnostics.ts +89 -0
  282. package/src/core/builtin-tags.ts +76 -0
  283. package/src/core/changelog-list.ts +87 -0
  284. package/src/core/closest-match.ts +41 -0
  285. package/src/core/code-fence-diagnostics.ts +267 -0
  286. package/src/core/code-fences.ts +43 -7
  287. package/src/core/component-diagnostics.ts +65 -12
  288. package/src/core/config-input.ts +39 -5
  289. package/src/core/config.ts +46 -1
  290. package/src/core/content-assets.ts +64 -144
  291. package/src/core/data.ts +10 -3
  292. package/src/core/diagnostics.ts +36 -3
  293. package/src/core/directive-diagnostics.ts +265 -47
  294. package/src/core/former-routes.ts +46 -0
  295. package/src/core/git-ignored.ts +53 -0
  296. package/src/core/github.ts +5 -4
  297. package/src/core/heading-markers.ts +156 -2
  298. package/src/core/hidden-pages.ts +64 -0
  299. package/src/core/includes.ts +181 -41
  300. package/src/core/last-modified.ts +47 -10
  301. package/src/core/links.ts +438 -83
  302. package/src/core/load-module.ts +98 -9
  303. package/src/core/manifest.ts +12 -9
  304. package/src/core/markdown-mirrors.ts +52 -0
  305. package/src/core/mcp-clients.ts +87 -0
  306. package/src/core/mdx-elements.ts +153 -0
  307. package/src/core/mdx-syntax.ts +377 -0
  308. package/src/core/meta-diagnostics.ts +134 -0
  309. package/src/core/meta.ts +154 -55
  310. package/src/core/nav-diagnostics.ts +41 -4
  311. package/src/core/navigation.ts +70 -10
  312. package/src/core/ordering-prefix.ts +22 -2
  313. package/src/core/pinned-ids.ts +141 -0
  314. package/src/core/project-graph.ts +221 -29
  315. package/src/core/redirect-patterns.ts +41 -0
  316. package/src/core/relative-files.ts +145 -0
  317. package/src/core/schema.ts +110 -6
  318. package/src/core/sources/mdx-remote.ts +75 -14
  319. package/src/core/sources/normalize.ts +885 -179
  320. package/src/core/sources/notion.ts +5 -4
  321. package/src/core/sources/obsidian.ts +2 -5
  322. package/src/core/sources/types.ts +17 -0
  323. package/src/core/static-files.ts +40 -0
  324. package/src/core/static-host.ts +125 -0
  325. package/src/core/svg-images.ts +98 -0
  326. package/src/core/syntax-diagnostics.ts +491 -0
  327. package/src/core/types.ts +43 -1
  328. package/src/deploy/artifacts.ts +2 -28
  329. package/src/deploy/generated-files.ts +128 -0
  330. package/src/deploy/platforms/vercel.ts +25 -1
  331. package/src/deploy/redirects.ts +43 -16
  332. package/src/deploy/sitemap.ts +2 -1
  333. package/src/markdown/base-links.ts +87 -6
  334. package/src/markdown/code-title.ts +29 -13
  335. package/src/markdown/content-assets.ts +210 -0
  336. package/src/markdown/directives.ts +69 -5
  337. package/src/markdown/fence-language.ts +106 -0
  338. package/src/markdown/fence-meta.ts +42 -0
  339. package/src/markdown/github-alerts.ts +172 -0
  340. package/src/markdown/heading-anchors.ts +265 -56
  341. package/src/markdown/include.ts +30 -3
  342. package/src/markdown/index.ts +145 -40
  343. package/src/markdown/prompt-text.ts +95 -0
  344. package/src/markdown/relative-links.ts +37 -2
  345. package/src/markdown/route-snapshot.ts +22 -12
  346. package/src/markdown/svg-fallback.ts +51 -0
  347. package/src/markdown/title-heading.ts +134 -0
  348. package/src/migrate/migrate.ts +127 -2
  349. package/src/og/card.ts +14 -4
  350. package/src/openapi/asyncapi.ts +14 -6
  351. package/src/openapi/checks.ts +160 -15
  352. package/src/openapi/model.ts +172 -33
  353. package/src/openapi/parse.ts +13 -4
  354. package/src/openapi/render-mdx.ts +55 -9
  355. package/src/openapi/source.ts +87 -6
  356. package/src/ratelimit/index.ts +2 -0
  357. package/src/ratelimit/memory.ts +1 -1
  358. package/src/ratelimit/runtime.ts +81 -0
  359. package/src/ratelimit/schema.ts +2 -0
  360. package/src/ratelimit/unkey.ts +61 -0
  361. package/src/registry/eject.ts +0 -1
  362. package/src/registry/registry.ts +1 -1
  363. package/src/search/documents.ts +10 -2
  364. package/src/sources/filesystem.ts +28 -3
  365. package/src/sources/mdx-remote.ts +7 -15
  366. package/src/theme/color.ts +14 -0
  367. package/src/theme/entry.ts +22 -1
  368. package/src/theme/palette.ts +74 -1
  369. package/dist/cli/chunk-0pmb4tr4.js.map +0 -35
  370. package/dist/cli/chunk-0w6hs479.js.map +0 -10
  371. package/dist/cli/chunk-150jk7km.js +0 -52
  372. package/dist/cli/chunk-150jk7km.js.map +0 -10
  373. package/dist/cli/chunk-36bxs9c7.js.map +0 -10
  374. package/dist/cli/chunk-53jqw8z0.js +0 -89
  375. package/dist/cli/chunk-53jqw8z0.js.map +0 -10
  376. package/dist/cli/chunk-60hz265r.js.map +0 -10
  377. package/dist/cli/chunk-desvm72z.js.map +0 -14
  378. package/dist/cli/chunk-dpy8qdjf.js.map +0 -17
  379. package/dist/cli/chunk-es8h0v3j.js +0 -441
  380. package/dist/cli/chunk-es8h0v3j.js.map +0 -11
  381. package/dist/cli/chunk-kdpzw38a.js.map +0 -11
  382. package/dist/cli/chunk-nbyvgnnm.js.map +0 -36
  383. package/dist/cli/chunk-s0bdnc7v.js.map +0 -10
  384. package/dist/cli/chunk-twy7psdz.js.map +0 -10
  385. package/dist/cli/chunk-ydp3065p.js +0 -64
  386. package/dist/cli/chunk-ydp3065p.js.map +0 -10
  387. /package/dist/cli/{chunk-y4msrwm9.js.map → chunk-080mfch6.js.map} +0 -0
  388. /package/dist/cli/{chunk-9qzgg6mj.js.map → chunk-34wap3ed.js.map} +0 -0
  389. /package/dist/cli/{chunk-1f882900.js.map → chunk-c5bjxq8v.js.map} +0 -0
  390. /package/dist/cli/{chunk-bxwhtvw8.js.map → chunk-f260jdrn.js.map} +0 -0
  391. /package/dist/cli/{chunk-74wfhv79.js.map → chunk-fnxgtjeq.js.map} +0 -0
  392. /package/dist/cli/{chunk-dhwtqnnd.js.map → chunk-gxhcf2hs.js.map} +0 -0
  393. /package/dist/cli/{chunk-tfycddbt.js.map → chunk-h0qwdbem.js.map} +0 -0
  394. /package/dist/cli/{chunk-j1x92mx9.js.map → chunk-j4nfgn2j.js.map} +0 -0
  395. /package/dist/cli/{chunk-ave1wcbr.js.map → chunk-qcyxkj44.js.map} +0 -0
  396. /package/dist/cli/{chunk-58bt3hag.js.map → chunk-x7bh6d9j.js.map} +0 -0
  397. /package/dist/cli/{chunk-hvcxng5f.js.map → chunk-ydqzkhjn.js.map} +0 -0
@@ -0,0 +1,329 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ normalizeBasePath,
4
+ normalizePath,
5
+ mountBasePath,
6
+ siteRoot,
7
+ absoluteUrl2
8
+ } from "./chunk-zccbjcj0.js";
9
+ import {
10
+ OPENAPI_PATH,
11
+ API_PAGES_PATH,
12
+ API_NAVIGATION_PATH,
13
+ API_SEARCH_PATH,
14
+ API_CATALOG_PATH,
15
+ hasApiCatalog,
16
+ buildApiCatalog,
17
+ AGENT_SKILLS_INDEX_PATH,
18
+ servesSkillsIndex,
19
+ AI_CATALOG_PATH,
20
+ ARD_MANIFEST_PATH,
21
+ hasAiCatalog,
22
+ buildAiCatalog,
23
+ discoverPagesSync,
24
+ customStaticRoutes,
25
+ hasGeneratedChangelog,
26
+ repoUrl,
27
+ isHiddenPage,
28
+ buildRssFeeds,
29
+ staticFileResolver,
30
+ SIGNATURES_DIRECTORY_PATH,
31
+ buildSignaturesDirectory,
32
+ deployPlatform
33
+ } from "./chunk-r5nm9w0c.js";
34
+ import {
35
+ SKILL_MD_PATH
36
+ } from "./chunk-q1wwrxzw.js";
37
+
38
+ // src/deploy/generated-files.ts
39
+ import { join } from "pathe";
40
+
41
+ // src/ai/agent-readability.ts
42
+ var USAGE_TOKENS = [
43
+ ["search", "search"],
44
+ ["aiInput", "ai-input"],
45
+ ["aiTrain", "ai-train"]
46
+ ];
47
+ var usagePolicy = (signals) => {
48
+ if (!signals) {
49
+ return null;
50
+ }
51
+ return Object.fromEntries(USAGE_TOKENS.map(([key, token]) => [token, signals[key]]));
52
+ };
53
+ var askApiUrl = (endpoint, site, abs) => {
54
+ if (!endpoint) {
55
+ return abs("/api/ask");
56
+ }
57
+ return site && endpoint.startsWith("/") ? absoluteUrl2(site, endpoint) : endpoint;
58
+ };
59
+ var markdownArtifact = (config, abs) => {
60
+ const negotiates = config.deployment.options.output === "server" && deployPlatform(config.deployment).negotiatesMarkdown;
61
+ return negotiates ? { contentNegotiation: "text/markdown", pattern: abs("/{route}.md") } : { pattern: abs("/{route}.md") };
62
+ };
63
+ var apiArtifact = (config, abs) => {
64
+ if (!config.agents.api) {
65
+ return null;
66
+ }
67
+ const api = {
68
+ openapi: abs(OPENAPI_PATH),
69
+ pages: abs(API_PAGES_PATH)
70
+ };
71
+ if (config.deployment.options.output === "server") {
72
+ api.search = abs(API_SEARCH_PATH);
73
+ }
74
+ return api;
75
+ };
76
+ var wellKnownArtifacts = (config, abs) => {
77
+ const artifacts = {};
78
+ if (config.agents.webBotAuth.keys.length > 0) {
79
+ artifacts.httpMessageSignaturesDirectory = abs("/.well-known/http-message-signatures-directory");
80
+ }
81
+ if (hasAiCatalog(config)) {
82
+ artifacts.aiCatalog = abs(AI_CATALOG_PATH);
83
+ }
84
+ if (hasApiCatalog(config)) {
85
+ artifacts.apiCatalog = abs("/.well-known/api-catalog");
86
+ }
87
+ if (servesSkillsIndex(config)) {
88
+ artifacts.agentSkills = abs("/.well-known/agent-skills/index.json");
89
+ }
90
+ return artifacts;
91
+ };
92
+ var buildAgentReadability = (project) => {
93
+ const { config } = project;
94
+ if (!config.agents.agentReadability) {
95
+ return null;
96
+ }
97
+ const site = config.deployment.options.site ?? null;
98
+ const deployBase = normalizeBasePath(config.deployment.options.base);
99
+ const abs = (path) => {
100
+ const based = mountBasePath(deployBase, path);
101
+ return site ? absoluteUrl2(site, based) : based;
102
+ };
103
+ const artifacts = {
104
+ markdown: markdownArtifact(config, abs)
105
+ };
106
+ const api = apiArtifact(config, abs);
107
+ if (api) {
108
+ artifacts.api = api;
109
+ }
110
+ if (config.agents.llmsTxt.enabled) {
111
+ artifacts.llmsFullTxt = abs("/llms-full.txt");
112
+ artifacts.llmsTxt = abs("/llms.txt");
113
+ }
114
+ if (config.agents.mcp.enabled) {
115
+ artifacts.mcp = {
116
+ discovery: abs("/.well-known/mcp.json"),
117
+ url: abs(config.agents.mcp.route)
118
+ };
119
+ }
120
+ if (config.ai.assistant?.enabled) {
121
+ artifacts.askApi = askApiUrl(config.ai.assistant.endpoint, site, abs);
122
+ }
123
+ Object.assign(artifacts, wellKnownArtifacts(config, abs));
124
+ if (site && config.seo.sitemap) {
125
+ artifacts.sitemap = abs("/sitemap.xml");
126
+ }
127
+ const feeds = site && config.seo.rss.enabled ? buildRssFeeds(project).map((feed) => abs(feed.path)) : [];
128
+ if (feeds.length > 0) {
129
+ artifacts.feeds = feeds;
130
+ }
131
+ const version = project.manifest?.blumeVersion;
132
+ const manifest = {
133
+ artifacts,
134
+ description: config.description,
135
+ generator: version ? `blume@${version}` : undefined,
136
+ name: config.agents.mcp.name ?? config.title,
137
+ site
138
+ };
139
+ const usage = usagePolicy(config.agents.contentSignals);
140
+ if (usage) {
141
+ manifest.contentUsage = usage;
142
+ }
143
+ if (config.github) {
144
+ manifest.repository = repoUrl(config.github);
145
+ }
146
+ return manifest;
147
+ };
148
+
149
+ // src/deploy/robots.ts
150
+ var SIGNAL_TOKENS = [
151
+ ["search", "search"],
152
+ ["aiInput", "ai-input"],
153
+ ["aiTrain", "ai-train"]
154
+ ];
155
+ var contentSignalLine = (signals) => {
156
+ if (!signals) {
157
+ return null;
158
+ }
159
+ const tokens = SIGNAL_TOKENS.map(([key, token]) => `${token}=${signals[key] ? "yes" : "no"}`);
160
+ return `Content-Signal: ${tokens.join(", ")}`;
161
+ };
162
+ var buildRobots = (project) => {
163
+ const { config } = project;
164
+ if (!config.seo.robots) {
165
+ return null;
166
+ }
167
+ const lines = ["User-agent: *"];
168
+ const signal = contentSignalLine(config.agents.contentSignals);
169
+ if (signal) {
170
+ lines.push(signal);
171
+ }
172
+ lines.push("Allow: /");
173
+ const { site } = config.deployment.options;
174
+ if (site && config.seo.sitemap) {
175
+ const sitemapPath = mountBasePath(normalizeBasePath(config.deployment.options.base), "/sitemap.xml");
176
+ lines.push("", `Sitemap: ${absoluteUrl2(site, sitemapPath)}`);
177
+ }
178
+ return `${lines.join(`
179
+ `)}
180
+ `;
181
+ };
182
+
183
+ // src/deploy/sitemap.ts
184
+ import { escape as escapeXml } from "html-escaper";
185
+ var ERROR_ROUTES = new Set(["/404", "/500"]);
186
+ var lastmodTag = (value) => {
187
+ if (!value) {
188
+ return "";
189
+ }
190
+ const date = new Date(value);
191
+ return Number.isNaN(date.getTime()) ? "" : `<lastmod>${date.toISOString().slice(0, 10)}</lastmod>`;
192
+ };
193
+ var canonicalElsewhere = (canonical, served) => {
194
+ if (!canonical) {
195
+ return false;
196
+ }
197
+ const { pathname } = new URL(canonical);
198
+ let path = pathname;
199
+ try {
200
+ path = decodeURI(pathname);
201
+ } catch {}
202
+ return normalizePath(path) !== normalizePath(served);
203
+ };
204
+ var URLS_PER_FILE = 50000;
205
+ var renderUrlset = (urls) => `<?xml version="1.0" encoding="UTF-8"?>
206
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
207
+ ${urls.join(`
208
+ `)}
209
+ </urlset>
210
+ `;
211
+ var buildSitemapFiles = (project) => {
212
+ const { site } = project.config.deployment.options;
213
+ if (!(site && project.config.seo.sitemap)) {
214
+ return null;
215
+ }
216
+ const base = siteRoot(site);
217
+ const deployBase = normalizeBasePath(project.config.deployment.options.base);
218
+ const { versions } = project.config;
219
+ const archivedById = new Map((versions?.archived ?? []).map((version) => [version.id, version]));
220
+ const currentKeys = versions ? new Set(project.graph.pages.flatMap((page) => page.version === "" ? [`${page.versionKey}\x00${page.locale}`] : [])) : null;
221
+ const archivedExcluded = (page) => {
222
+ if (!page.version) {
223
+ return false;
224
+ }
225
+ const archived = archivedById.get(page.version);
226
+ return Boolean(archived?.noindex || archived?.canonical === "latest" && !page.meta.seo.canonical && currentKeys?.has(`${page.versionKey}\x00${page.locale}`));
227
+ };
228
+ const seen = new Set;
229
+ const urls = [];
230
+ const pushUrl = (route, lastModified) => {
231
+ const loc = escapeXml(encodeURI(`${base}${route}`));
232
+ if (seen.has(loc)) {
233
+ return;
234
+ }
235
+ seen.add(loc);
236
+ urls.push(` <url><loc>${loc}</loc>${lastmodTag(lastModified)}</url>`);
237
+ };
238
+ for (const page of project.graph.pages) {
239
+ const served = mountBasePath(deployBase, page.route);
240
+ if (page.meta.draft || isHiddenPage(page, project.graph) || page.meta.seo.noindex || ERROR_ROUTES.has(page.route) || archivedExcluded(page) || canonicalElsewhere(page.meta.seo.canonical, served)) {
241
+ continue;
242
+ }
243
+ pushUrl(served, page.lastModified);
244
+ }
245
+ const userPages = project.context.pagesRoot ? discoverPagesSync(project.context.pagesRoot) : [];
246
+ const extraRoutes = customStaticRoutes(userPages).filter((route) => !ERROR_ROUTES.has(route));
247
+ if (hasGeneratedChangelog(project, userPages)) {
248
+ extraRoutes.push("/changelog");
249
+ }
250
+ for (const route of extraRoutes) {
251
+ pushUrl(mountBasePath(deployBase, route));
252
+ }
253
+ urls.sort();
254
+ if (urls.length <= URLS_PER_FILE) {
255
+ return [{ name: "sitemap.xml", xml: renderUrlset(urls) }];
256
+ }
257
+ const chunks = [];
258
+ const references = [];
259
+ for (let start = 0;start < urls.length; start += URLS_PER_FILE) {
260
+ const name = `sitemap-${chunks.length + 1}.xml`;
261
+ chunks.push({
262
+ name,
263
+ xml: renderUrlset(urls.slice(start, start + URLS_PER_FILE))
264
+ });
265
+ const loc = escapeXml(encodeURI(`${base}${mountBasePath(deployBase, `/${name}`)}`));
266
+ references.push(` <sitemap><loc>${loc}</loc></sitemap>`);
267
+ }
268
+ const index = `<?xml version="1.0" encoding="UTF-8"?>
269
+ <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
270
+ ${references.join(`
271
+ `)}
272
+ </sitemapindex>
273
+ `;
274
+ return [{ name: "sitemap.xml", xml: index }, ...chunks];
275
+ };
276
+
277
+ // src/deploy/generated-files.ts
278
+ var wellKnownFiles = (config, skills) => {
279
+ const aiCatalog = buildAiCatalog(config, skills);
280
+ return [
281
+ {
282
+ content: buildSignaturesDirectory(config),
283
+ label: "Web Bot Auth",
284
+ path: SIGNATURES_DIRECTORY_PATH
285
+ },
286
+ {
287
+ content: buildApiCatalog(config),
288
+ label: "RFC 9727",
289
+ path: API_CATALOG_PATH
290
+ },
291
+ { content: aiCatalog, label: "AI Catalog", path: AI_CATALOG_PATH },
292
+ { content: aiCatalog, label: "ARD manifest", path: ARD_MANIFEST_PATH }
293
+ ];
294
+ };
295
+ var generatedFilePaths = (project) => {
296
+ const { config } = project;
297
+ const paths = [];
298
+ if (config.agents.llmsTxt.enabled) {
299
+ paths.push("/llms.txt", "/llms-full.txt");
300
+ }
301
+ paths.push(...(buildSitemapFiles(project) ?? []).map((file) => `/${file.name}`));
302
+ if (buildRobots(project)) {
303
+ paths.push("/robots.txt");
304
+ }
305
+ if (buildAgentReadability(project)) {
306
+ paths.push("/agent-readability.json");
307
+ }
308
+ paths.push(...wellKnownFiles(config, []).flatMap((file) => file.content ? [file.path] : []));
309
+ if (servesSkillsIndex(config)) {
310
+ paths.push(AGENT_SKILLS_INDEX_PATH);
311
+ if (config.agents.skillMd) {
312
+ paths.push(SKILL_MD_PATH);
313
+ }
314
+ }
315
+ paths.push(...buildRssFeeds(project).map((feed) => feed.path));
316
+ if (config.agents.api) {
317
+ paths.push(OPENAPI_PATH, API_PAGES_PATH, API_NAVIGATION_PATH);
318
+ }
319
+ if (config.agents.mcp.enabled) {
320
+ paths.push("/.well-known/mcp.json", "/.well-known/mcp/server-card.json");
321
+ }
322
+ return paths;
323
+ };
324
+ var servedFiles = (project) => staticFileResolver(join(project.context.root, "public"), generatedFilePaths(project));
325
+
326
+ export { generatedFilePaths, servedFiles };
327
+
328
+ //# debugId=AFE0F5252B96AD6064756E2164756E21
329
+ //# sourceMappingURL=chunk-487b95qy.js.map
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/deploy/generated-files.ts", "../src/ai/agent-readability.ts", "../src/deploy/robots.ts", "../src/deploy/sitemap.ts"],
4
+ "sourcesContent": [
5
+ "import { join } from \"pathe\";\n\nimport { buildAgentReadability } from \"../ai/agent-readability.ts\";\nimport {\n AI_CATALOG_PATH,\n ARD_MANIFEST_PATH,\n buildAiCatalog,\n} from \"../ai/ai-catalog.ts\";\nimport { API_CATALOG_PATH, buildApiCatalog } from \"../ai/api-catalog.ts\";\nimport {\n API_NAVIGATION_PATH,\n API_PAGES_PATH,\n OPENAPI_PATH,\n} from \"../ai/api/paths.ts\";\nimport { SKILL_MD_PATH } from \"../ai/site-skill.ts\";\nimport { AGENT_SKILLS_INDEX_PATH, servesSkillsIndex } from \"../ai/skills.ts\";\nimport type { SkillArtifact } from \"../ai/skills.ts\";\nimport {\n buildSignaturesDirectory,\n SIGNATURES_DIRECTORY_PATH,\n} from \"../ai/web-bot-auth.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\nimport { staticFileResolver } from \"../core/static-files.ts\";\nimport { buildRobots } from \"./robots.ts\";\nimport { buildRssFeeds } from \"./rss.ts\";\nimport { buildSitemapFiles } from \"./sitemap.ts\";\n\n/** A generated `.well-known` discovery document: `null` content when it's off. */\nexport interface WellKnownFile {\n content: string | null;\n label: string;\n path: string;\n}\n\n/**\n * The generated `.well-known` discovery documents — the Web Bot Auth signature\n * directory, the RFC 9727 API catalog, and the AI catalog under both the\n * ai-catalog spec's well-known URI and the ARD v0.91 one (see\n * `ai/ai-catalog.ts`) — each with `null` content when its feature is off.\n */\nexport const wellKnownFiles = (\n config: ResolvedConfig,\n skills: readonly SkillArtifact[]\n): WellKnownFile[] => {\n const aiCatalog = buildAiCatalog(config, skills);\n return [\n {\n content: buildSignaturesDirectory(config),\n label: \"Web Bot Auth\",\n path: SIGNATURES_DIRECTORY_PATH,\n },\n {\n content: buildApiCatalog(config),\n label: \"RFC 9727\",\n path: API_CATALOG_PATH,\n },\n { content: aiCatalog, label: \"AI Catalog\", path: AI_CATALOG_PATH },\n { content: aiCatalog, label: \"ARD manifest\", path: ARD_MANIFEST_PATH },\n ];\n};\n\n/**\n * The files a build serves beside its pages that don't come from `public/`,\n * as base-less root-relative paths: what `publishBuildArtifacts` writes once\n * Astro is done (llms.txt, the sitemap, robots.txt, `agent-readability.json`,\n * the `.well-known` discovery documents, the Agent Skills index, `skill.md`)\n * and the generated endpoints at fixed paths (the RSS feeds, the JSON docs\n * API and its OpenAPI description, the MCP discovery documents). Each is\n * listed under the gate its writer reads, so a feature the config switches\n * off drops its file here too: `blume validate` accepts a link to\n * `/llms.txt` exactly when the build writes one.\n *\n * Read from the config alone, before a build: the skill archives a build\n * publishes beside the index, and the platform files (`_redirects`,\n * `_headers`, `vercel.json`), aren't listed. A page's Markdown copy\n * (`/guide.md`) is its route's, and resolves through the page.\n */\nexport const generatedFilePaths = (project: BlumeProject): string[] => {\n const { config } = project;\n const paths: string[] = [];\n if (config.agents.llmsTxt.enabled) {\n paths.push(\"/llms.txt\", \"/llms-full.txt\");\n }\n paths.push(\n ...(buildSitemapFiles(project) ?? []).map((file) => `/${file.name}`)\n );\n if (buildRobots(project)) {\n paths.push(\"/robots.txt\");\n }\n if (buildAgentReadability(project)) {\n paths.push(\"/agent-readability.json\");\n }\n paths.push(\n ...wellKnownFiles(config, []).flatMap((file) =>\n file.content ? [file.path] : []\n )\n );\n if (servesSkillsIndex(config)) {\n paths.push(AGENT_SKILLS_INDEX_PATH);\n if (config.agents.skillMd) {\n paths.push(SKILL_MD_PATH);\n }\n }\n paths.push(...buildRssFeeds(project).map((feed) => feed.path));\n if (config.agents.api) {\n paths.push(OPENAPI_PATH, API_PAGES_PATH, API_NAVIGATION_PATH);\n }\n if (config.agents.mcp.enabled) {\n paths.push(\"/.well-known/mcp.json\", \"/.well-known/mcp/server-card.json\");\n }\n return paths;\n};\n\n/**\n * Whether a base-less path is a file the project's site serves beside its\n * pages: one in `public/` (`/spec.pdf`, a folder's `index.html`) or one the\n * build generates (`/llms.txt`). What `generateRuntime` and `blume doctor`\n * check navigation entries against, beside the routes, as `blume validate`\n * checks links.\n */\nexport const servedFiles = (\n project: BlumeProject\n): ((path: string) => boolean) =>\n staticFileResolver(\n join(project.context.root, \"public\"),\n generatedFilePaths(project)\n );\n",
6
+ "import { mountBasePath, normalizeBasePath } from \"../core/base-path.ts\";\nimport { repoUrl } from \"../core/github.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport type { ContentSignalPolicy, ContentSignals } from \"../core/schema.ts\";\nimport { absoluteUrl } from \"../core/site-url.ts\";\nimport { deployPlatform } from \"../deploy/platforms/index.ts\";\nimport { buildRssFeeds } from \"../deploy/rss.ts\";\nimport { AI_CATALOG_PATH, hasAiCatalog } from \"./ai-catalog.ts\";\nimport { hasApiCatalog } from \"./api-catalog.ts\";\nimport { API_PAGES_PATH, API_SEARCH_PATH, OPENAPI_PATH } from \"./api/paths.ts\";\nimport { servesSkillsIndex } from \"./skills.ts\";\n\n/** Token map for the machine-readable content-usage echo. */\nconst USAGE_TOKENS: [keyof ContentSignalPolicy, string][] = [\n [\"search\", \"search\"],\n [\"aiInput\", \"ai-input\"],\n [\"aiTrain\", \"ai-train\"],\n];\n\n/**\n * The configured usage preferences as a `{ token: allowed }` object, or null\n * when the declaration is disabled (`contentSignals: false`). Mirrors the\n * robots.txt `Content-Signal` line so an agent that reads the manifest instead\n * of robots.txt sees the same policy.\n */\nconst usagePolicy = (\n signals: ContentSignals\n): Record<string, boolean> | null => {\n if (!signals) {\n return null;\n }\n return Object.fromEntries(\n USAGE_TOKENS.map(([key, token]) => [token, signals[key]] as const)\n );\n};\n\n/**\n * The advertised assistant URL. An external endpoint is not served under\n * `deployment.base`, so a root-relative one absolutizes against the site\n * origin alone; the built-in route gets site and base via `abs`.\n */\nconst askApiUrl = (\n endpoint: string | undefined,\n site: string | null,\n abs: (path: string) => string\n): string => {\n if (!endpoint) {\n return abs(\"/api/ask\");\n }\n return site && endpoint.startsWith(\"/\")\n ? absoluteUrl(site, endpoint)\n : endpoint;\n};\n\n/** The `.well-known` discovery URLs a site can publish. */\ninterface WellKnownArtifacts {\n httpMessageSignaturesDirectory?: string;\n aiCatalog?: string;\n apiCatalog?: string;\n agentSkills?: string;\n}\n\n/** The JSON docs API's entry points; `search` exists on server output only. */\ninterface ApiArtifact {\n openapi: string;\n pages: string;\n search?: string;\n}\n\n/** The agent-facing artifact index the manifest publishes. */\ninterface AgentArtifacts extends WellKnownArtifacts {\n markdown: { contentNegotiation?: string; pattern: string };\n api?: ApiArtifact;\n llmsFullTxt?: string;\n llmsTxt?: string;\n mcp?: { discovery: string; url: string };\n askApi?: string;\n sitemap?: string;\n feeds?: string[];\n}\n\n/** The published `agent-readability.json` document. */\nexport interface AgentReadabilityManifest {\n artifacts: AgentArtifacts;\n description?: string;\n generator?: string;\n name: string;\n site: string | null;\n contentUsage?: Record<string, boolean>;\n repository?: string;\n}\n\n/**\n * The raw-Markdown mirror pattern. `Accept: text/markdown` negotiation is\n * advertised only where the deployed site actually honors it — a server build\n * on a platform that declares `negotiatesMarkdown` (Vercel, whose routing\n * config gets the rewrite rules; Cloudflare, whose deploy bundle gets a\n * wrapper Worker — see `deploy/platforms/*`). Static builds and other\n * adapters serve prerendered pages from a static layer with no request-time\n * hook, so agents there should fetch the `.md` pattern directly.\n */\nconst markdownArtifact = (\n config: BlumeProject[\"config\"],\n abs: (path: string) => string\n): AgentArtifacts[\"markdown\"] => {\n const negotiates =\n config.deployment.options.output === \"server\" &&\n deployPlatform(config.deployment).negotiatesMarkdown;\n return negotiates\n ? { contentNegotiation: \"text/markdown\", pattern: abs(\"/{route}.md\") }\n : { pattern: abs(\"/{route}.md\") };\n};\n\n/** The JSON docs API's entry points, or null when the API is off. */\nconst apiArtifact = (\n config: BlumeProject[\"config\"],\n abs: (path: string) => string\n): ApiArtifact | null => {\n if (!config.agents.api) {\n return null;\n }\n const api: ApiArtifact = {\n openapi: abs(OPENAPI_PATH),\n pages: abs(API_PAGES_PATH),\n };\n if (config.deployment.options.output === \"server\") {\n api.search = abs(API_SEARCH_PATH);\n }\n return api;\n};\n\n/** The `.well-known` discovery artifacts the site publishes, if any. */\nconst wellKnownArtifacts = (\n config: BlumeProject[\"config\"],\n abs: (path: string) => string\n): WellKnownArtifacts => {\n const artifacts: WellKnownArtifacts = {};\n if (config.agents.webBotAuth.keys.length > 0) {\n artifacts.httpMessageSignaturesDirectory = abs(\n \"/.well-known/http-message-signatures-directory\"\n );\n }\n if (hasAiCatalog(config)) {\n artifacts.aiCatalog = abs(AI_CATALOG_PATH);\n }\n if (hasApiCatalog(config)) {\n artifacts.apiCatalog = abs(\"/.well-known/api-catalog\");\n }\n if (servesSkillsIndex(config)) {\n artifacts.agentSkills = abs(\"/.well-known/agent-skills/index.json\");\n }\n return artifacts;\n};\n\n/**\n * Build `agent-readability.json`: a root manifest that indexes the project's\n * agent-facing surface — llms.txt, the raw-Markdown mirrors, the JSON docs\n * API and its OpenAPI description, the MCP server, the assistant, sitemap, and feeds\n * — so agents can discover and cite the docs without\n * scraping HTML. URLs are absolute when a `site` is configured and root-relative\n * (still under `deployment.base`) otherwise. Returns null when the manifest is\n * disabled.\n */\nexport const buildAgentReadability = (\n project: BlumeProject\n): AgentReadabilityManifest | null => {\n const { config } = project;\n if (!config.agents.agentReadability) {\n return null;\n }\n\n const site = config.deployment.options.site ?? null;\n // Every artifact is served under `deployment.base` — with or without a\n // `site`; concatenate rather than `new URL()` so the subpath is preserved.\n const deployBase = normalizeBasePath(config.deployment.options.base);\n const abs = (path: string): string => {\n const based = mountBasePath(deployBase, path);\n return site ? absoluteUrl(site, based) : based;\n };\n\n const artifacts: AgentArtifacts = {\n markdown: markdownArtifact(config, abs),\n };\n const api = apiArtifact(config, abs);\n if (api) {\n artifacts.api = api;\n }\n if (config.agents.llmsTxt.enabled) {\n artifacts.llmsFullTxt = abs(\"/llms-full.txt\");\n artifacts.llmsTxt = abs(\"/llms.txt\");\n }\n if (config.agents.mcp.enabled) {\n artifacts.mcp = {\n discovery: abs(\"/.well-known/mcp.json\"),\n url: abs(config.agents.mcp.route),\n };\n }\n if (config.ai.assistant?.enabled) {\n artifacts.askApi = askApiUrl(config.ai.assistant.endpoint, site, abs);\n }\n Object.assign(artifacts, wellKnownArtifacts(config, abs));\n if (site && config.seo.sitemap) {\n artifacts.sitemap = abs(\"/sitemap.xml\");\n }\n const feeds =\n site && config.seo.rss.enabled\n ? buildRssFeeds(project).map((feed) => abs(feed.path))\n : [];\n if (feeds.length > 0) {\n artifacts.feeds = feeds;\n }\n\n const version = project.manifest?.blumeVersion;\n const manifest: AgentReadabilityManifest = {\n artifacts,\n description: config.description,\n generator: version ? `blume@${version}` : undefined,\n name: config.agents.mcp.name ?? config.title,\n site,\n };\n\n const usage = usagePolicy(config.agents.contentSignals);\n if (usage) {\n manifest.contentUsage = usage;\n }\n if (config.github) {\n manifest.repository = repoUrl(config.github);\n }\n\n return manifest;\n};\n",
7
+ "import { mountBasePath, normalizeBasePath } from \"../core/base-path.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport type { ContentSignalPolicy, ContentSignals } from \"../core/schema.ts\";\nimport { absoluteUrl } from \"../core/site-url.ts\";\n\n/**\n * Ordered mapping from config field to its `Content-Signal` token. The order\n * fixes the emitted sequence (`search`, then `ai-input`, then `ai-train`).\n */\nconst SIGNAL_TOKENS: [keyof ContentSignalPolicy, string][] = [\n [\"search\", \"search\"],\n [\"aiInput\", \"ai-input\"],\n [\"aiTrain\", \"ai-train\"],\n];\n\n/**\n * The `Content-Signal:` line declaring how crawlers may reuse the site, or null\n * when the declaration is disabled (`contentSignals: false`). Otherwise every\n * signal is emitted with its resolved yes/no value.\n */\nconst contentSignalLine = (signals: ContentSignals): string | null => {\n if (!signals) {\n return null;\n }\n const tokens = SIGNAL_TOKENS.map(\n ([key, token]) => `${token}=${signals[key] ? \"yes\" : \"no\"}`\n );\n return `Content-Signal: ${tokens.join(\", \")}`;\n};\n\n/**\n * Build a robots.txt that allows all crawlers, declares any configured\n * `Content-Signal` usage preferences, and points to the sitemap when one is\n * available (a `site` is set and the sitemap is enabled). Returns null when\n * robots generation is disabled.\n */\nexport const buildRobots = (project: BlumeProject): string | null => {\n const { config } = project;\n if (!config.seo.robots) {\n return null;\n }\n\n const lines = [\"User-agent: *\"];\n const signal = contentSignalLine(config.agents.contentSignals);\n if (signal) {\n lines.push(signal);\n }\n lines.push(\"Allow: /\");\n\n const { site } = config.deployment.options;\n if (site && config.seo.sitemap) {\n const sitemapPath = mountBasePath(\n normalizeBasePath(config.deployment.options.base),\n \"/sitemap.xml\"\n );\n lines.push(\"\", `Sitemap: ${absoluteUrl(site, sitemapPath)}`);\n }\n return `${lines.join(\"\\n\")}\\n`;\n};\n",
8
+ "// html-escaper's five-entity table is XML-safe (`'` → the numeric `&#39;`).\nimport { escape as escapeXml } from \"html-escaper\";\n\nimport {\n customStaticRoutes,\n discoverPagesSync,\n hasGeneratedChangelog,\n} from \"../astro/pages.ts\";\nimport {\n mountBasePath,\n normalizeBasePath,\n normalizePath,\n} from \"../core/base-path.ts\";\nimport { isHiddenPage } from \"../core/hidden-pages.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport { siteRoot } from \"../core/site-url.ts\";\n\n/**\n * Astro's reserved error routes. A user-authored override (`pages/404.astro`,\n * `pages/500.astro`, or a `404.md` content page — see `writeNotFoundPage` in\n * `astro/generate.ts`) is neither dynamic nor private, so it would otherwise\n * be emitted — but error pages aren't crawlable destinations and must stay out\n * of the sitemap.\n */\nconst ERROR_ROUTES = new Set([\"/404\", \"/500\"]);\n\n/** A `<lastmod>` element (W3C date) when the page has a valid modified date. */\nconst lastmodTag = (value: string | undefined): string => {\n if (!value) {\n return \"\";\n }\n const date = new Date(value);\n return Number.isNaN(date.getTime())\n ? \"\"\n : `<lastmod>${date.toISOString().slice(0, 10)}</lastmod>`;\n};\n\n/**\n * Whether a page's own `seo.canonical` names another URL. The sitemap lists\n * canonical URLs only, so such a page stays out — `blume audit` reports a\n * listed one as NON_CANONICAL_IN_SITEMAP and expects it unlisted. Compared by\n * decoded path, as the audit does: `served` is the page's path with the\n * deployment base mounted, which the canonical carries too.\n */\nconst canonicalElsewhere = (\n canonical: string | undefined,\n served: string\n): boolean => {\n if (!canonical) {\n return false;\n }\n const { pathname } = new URL(canonical);\n let path = pathname;\n try {\n path = decodeURI(pathname);\n } catch {\n // A malformed escape stays as written; it can't match the served path.\n }\n return normalizePath(path) !== normalizePath(served);\n};\n\n/** One emitted sitemap artifact: its dist-root filename and XML body. */\nexport interface SitemapFile {\n name: string;\n xml: string;\n}\n\n/** The build log line for an emitted sitemap set: one file, or an index. */\nexport const describeSitemapFiles = (files: readonly SitemapFile[]): string =>\n files.length === 1\n ? \"Generated sitemap.xml\"\n : `Generated sitemap.xml (index of ${files.length - 1} sitemap files)`;\n\n/**\n * The sitemaps.org cap on `<url>` entries in a single file. Beyond it,\n * `sitemap.xml` becomes a sitemap index pointing at numbered chunk files —\n * search engines reject an oversized urlset outright.\n */\nconst URLS_PER_FILE = 50_000;\n\nconst renderUrlset = (\n urls: string[]\n): string => `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n${urls.join(\"\\n\")}\n</urlset>\n`;\n\n/**\n * Build the sitemap files from the route manifest plus the routes the manifest\n * can't see: custom `.astro` pages (most importantly a custom landing `/`) and\n * the generated `/changelog` index. Returns null when the sitemap is disabled\n * or no `site` is configured (absolute URLs are required for a valid sitemap).\n * Drafts, hidden, and `noindex` pages are excluded, and so is a page whose\n * `seo.canonical` points elsewhere.\n *\n * Sites within the per-file URL cap get the single classic `sitemap.xml`;\n * larger sites get `sitemap.xml` as a sitemap index over numbered\n * `sitemap-N.xml` chunks, all served from the same directory robots.txt\n * already points at.\n */\nexport const buildSitemapFiles = (\n project: BlumeProject\n): SitemapFile[] | null => {\n const { site } = project.config.deployment.options;\n if (!(site && project.config.seo.sitemap)) {\n return null;\n }\n\n const base = siteRoot(site);\n // Routes carry `basePath`; a `deployment.base` subdirectory is mounted on\n // top of every one, even a route whose first segment matches it: under base\n // `/guides`, `guides/setup.md` is served at `/guides/guides/setup`.\n const deployBase = normalizeBasePath(project.config.deployment.options.base);\n\n // Archived-version pages leave the sitemap when the version is noindexed,\n // or when their canonical points at a still-existing latest equivalent —\n // listing a URL whose canonical says \"index the other page\" invites the\n // noindexed-page-in-sitemap incoherence Docusaurus is known for. A page\n // that exists only in an archived version stays listed (self-canonical),\n // and a page's own `seo.canonical` wins over the version's default, as it\n // does in the page head (see `canonicalElsewhere`).\n const { versions } = project.config;\n const archivedById = new Map(\n (versions?.archived ?? []).map((version) => [version.id, version])\n );\n const currentKeys = versions\n ? new Set(\n project.graph.pages.flatMap((page) =>\n page.version === \"\" ? [`${page.versionKey}\\u0000${page.locale}`] : []\n )\n )\n : null;\n const archivedExcluded = (page: (typeof project.graph.pages)[number]) => {\n if (!page.version) {\n return false;\n }\n // A non-empty version always names a configured archived entry — that is\n // the only way detection assigns one.\n const archived = archivedById.get(page.version);\n return Boolean(\n archived?.noindex ||\n (archived?.canonical === \"latest\" &&\n !page.meta.seo.canonical &&\n currentKeys?.has(`${page.versionKey}\\u0000${page.locale}`))\n );\n };\n\n const seen = new Set<string>();\n const urls: string[] = [];\n const pushUrl = (route: string, lastModified?: string): void => {\n // `<loc>` must be a well-formed, XML-escaped URL: percent-encode the path,\n // then escape XML metacharacters (notably `&`) so a route like\n // `/Tips & Tricks` doesn't produce invalid XML that gets the whole sitemap\n // rejected.\n const loc = escapeXml(encodeURI(`${base}${route}`));\n if (seen.has(loc)) {\n return;\n }\n seen.add(loc);\n urls.push(` <url><loc>${loc}</loc>${lastmodTag(lastModified)}</url>`);\n };\n for (const page of project.graph.pages) {\n const served = mountBasePath(deployBase, page.route);\n if (\n page.meta.draft ||\n isHiddenPage(page, project.graph) ||\n page.meta.seo.noindex ||\n ERROR_ROUTES.has(page.route) ||\n archivedExcluded(page) ||\n canonicalElsewhere(page.meta.seo.canonical, served)\n ) {\n continue;\n }\n pushUrl(served, page.lastModified);\n }\n // Custom `.astro` pages and the generated changelog index mount outside\n // `basePath` (they're injected at their pattern — see `blumeIntegration`), so\n // only the deployment base layers onto their URLs.\n const userPages = project.context.pagesRoot\n ? discoverPagesSync(project.context.pagesRoot)\n : [];\n const extraRoutes = customStaticRoutes(userPages).filter(\n (route) => !ERROR_ROUTES.has(route)\n );\n if (hasGeneratedChangelog(project, userPages)) {\n extraRoutes.push(\"/changelog\");\n }\n for (const route of extraRoutes) {\n pushUrl(mountBasePath(deployBase, route));\n }\n urls.sort();\n\n if (urls.length <= URLS_PER_FILE) {\n return [{ name: \"sitemap.xml\", xml: renderUrlset(urls) }];\n }\n\n const chunks: SitemapFile[] = [];\n const references: string[] = [];\n for (let start = 0; start < urls.length; start += URLS_PER_FILE) {\n const name = `sitemap-${chunks.length + 1}.xml`;\n chunks.push({\n name,\n xml: renderUrlset(urls.slice(start, start + URLS_PER_FILE)),\n });\n // Chunks sit next to sitemap.xml, so their URLs layer the same deployment\n // base robots.txt uses for the index.\n const loc = escapeXml(\n encodeURI(`${base}${mountBasePath(deployBase, `/${name}`)}`)\n );\n references.push(` <sitemap><loc>${loc}</loc></sitemap>`);\n }\n const index = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n${references.join(\"\\n\")}\n</sitemapindex>\n`;\n return [{ name: \"sitemap.xml\", xml: index }, ...chunks];\n};\n"
9
+ ],
10
+ "mappings": "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",
11
+ "debugId": "AFE0F5252B96AD6064756E2164756E21",
12
+ "names": []
13
+ }
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ locateMdxFailure
4
+ } from "./chunk-zxd5jrgx.js";
5
+
6
+ // src/cli/build-failure.ts
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "pathe";
9
+ import ts from "typescript";
10
+ import { z } from "zod";
11
+ var buildErrorSchema = z.looseObject({
12
+ errors: z.array(z.instanceof(Error)).optional(),
13
+ id: z.string().optional(),
14
+ loc: z.looseObject({
15
+ column: z.number().optional(),
16
+ file: z.string().optional(),
17
+ line: z.number().optional()
18
+ }).optional()
19
+ });
20
+ var blumeErrorSchema = z.looseObject({
21
+ diagnostic: z.object({
22
+ code: z.string(),
23
+ column: z.number().optional(),
24
+ docsUrl: z.string().optional(),
25
+ file: z.string().optional(),
26
+ line: z.number().optional(),
27
+ message: z.string(),
28
+ severity: z.enum(["error", "info", "warning"]),
29
+ suggestion: z.string().optional()
30
+ })
31
+ });
32
+ var UNDEFINED_NAME = [
33
+ /^(?<name>[\w$]+) is not defined$/u,
34
+ /^Can't find variable: (?<name>[\w$]+)$/u
35
+ ];
36
+ var POSITIONED = /^\d+:\d+: /u;
37
+ var undefinedNameDiagnostic = (name, file, site) => {
38
+ const escape = "show the braces as text: escape each opening brace (`\\{`) or put it in inline code";
39
+ const variable = site?.expression === `{{${name}}}`;
40
+ return {
41
+ code: "BLUME_MDX_UNDEFINED_NAME",
42
+ column: site?.column,
43
+ file: site?.file ?? file,
44
+ line: site?.line,
45
+ message: site?.expression ? `\`${site.expression}\` reads \`${name}\`, which isn't defined, so the page fails to render. In .mdx, \`{…}\` is a JavaScript expression.` : `\`${name}\` isn't defined, so the page fails to render. In .mdx, \`{…}\` is a JavaScript expression, and one reads it.`,
46
+ severity: "error",
47
+ suggestion: variable ? `Define \`${name}\` under \`variables\` in blume.config.ts, or ${escape}.` : `To ${escape}. For a value every page shares, define a variable in blume.config.ts and write \`{{name}}\`.`
48
+ };
49
+ };
50
+ var TSCONFIG_NOT_FOUND = /Tsconfig not found (?<target>\S+?)\.?$/mu;
51
+ var tsconfigLinksSchema = z.object({
52
+ extends: z.union([z.string(), z.array(z.string())]).optional(),
53
+ references: z.array(z.object({ path: z.string() })).optional()
54
+ });
55
+ var linkTo = (path, target) => {
56
+ const parsed = tsconfigLinksSchema.safeParse(ts.readConfigFile(path, ts.sys.readFile).config);
57
+ if (!parsed.success) {
58
+ return;
59
+ }
60
+ const names = (written) => {
61
+ const resolved = resolve(dirname(path), written);
62
+ return written === target || resolved === target || join(resolved, "tsconfig.json") === target;
63
+ };
64
+ const extended = [parsed.data.extends ?? []].flat().find(names);
65
+ if (extended !== undefined) {
66
+ return { key: "extends", written: extended };
67
+ }
68
+ const referenced = (parsed.data.references ?? []).map((reference) => reference.path).find(names);
69
+ return referenced === undefined ? undefined : { key: "references", written: referenced };
70
+ };
71
+ var tsconfigFix = ({ key, written }, name) => {
72
+ if (key === "references") {
73
+ return `Create \`${written}\` (a framework's generated tsconfig appears once its prepare or build step runs), or remove it from \`references\` in ${name}.`;
74
+ }
75
+ if (written.startsWith(".") || isAbsolute(written)) {
76
+ return `Restore \`${written}\`, or remove it from \`extends\` in ${name}.`;
77
+ }
78
+ const packageName = written.split("/").slice(0, written.startsWith("@") ? 2 : 1).join("/");
79
+ return `Install the package that provides it (\`${packageName}\`), or remove it from \`extends\` in ${name}.`;
80
+ };
81
+ var tsconfigExtendsDiagnostic = (target, root) => {
82
+ const found = root ? ["tsconfig.json", "jsconfig.json"].map((name) => join(root, name)).filter((path) => existsSync(path)).map((path) => ({ link: linkTo(path, target), path })).find(({ link }) => link !== undefined) : undefined;
83
+ const file = found?.path;
84
+ const { key, written } = found?.link ?? { key: "extends", written: target };
85
+ const line = file ? readFileSync(file, "utf-8").split(`
86
+ `).findIndex((text) => text.includes(JSON.stringify(written))) + 1 : 0;
87
+ const name = file ? basename(file) : "tsconfig.json";
88
+ return {
89
+ code: "BLUME_TSCONFIG_EXTENDS",
90
+ file,
91
+ line: line > 0 ? line : undefined,
92
+ message: `${file ? name : "A tsconfig.json in the project"} ${key} \`${written}\`, which can't be found. The build reads the project's ${name} to resolve imports, so it stops here.`,
93
+ severity: "error",
94
+ suggestion: tsconfigFix({ key, written }, name)
95
+ };
96
+ };
97
+ var missingTsconfig = (error) => (TSCONFIG_NOT_FOUND.exec(error.message) ?? (error.cause instanceof Error ? TSCONFIG_NOT_FOUND.exec(error.cause.message) : null))?.groups?.target;
98
+ var undefinedName = (error) => error.name === "ReferenceError" ? UNDEFINED_NAME.map((pattern) => pattern.exec(error.message)).find(Boolean)?.groups?.name : undefined;
99
+ var locateFailure = async (error, page, name, locate) => {
100
+ if (!locate) {
101
+ return null;
102
+ }
103
+ if (name) {
104
+ return await locate(page, { kind: "undefined-name", name });
105
+ }
106
+ return error.name === "MDXError" && !POSITIONED.test(error.message) ? await locate(page, { kind: "syntax" }) : null;
107
+ };
108
+ var failureDiagnostic = async (error, context) => {
109
+ const raised = blumeErrorSchema.safeParse(error);
110
+ if (raised.success) {
111
+ return raised.data.diagnostic;
112
+ }
113
+ const tsconfig = missingTsconfig(error);
114
+ if (tsconfig) {
115
+ return tsconfigExtendsDiagnostic(tsconfig, context.root);
116
+ }
117
+ const parsed = buildErrorSchema.safeParse(error);
118
+ const { id, loc } = parsed.success ? parsed.data : {};
119
+ const file = loc?.file ?? id;
120
+ const name = undefinedName(error);
121
+ const site = file?.endsWith(".mdx") ? await locateFailure(error, file, name, context.locate) : null;
122
+ if (file?.endsWith(".mdx") && name) {
123
+ return undefinedNameDiagnostic(name, file, site);
124
+ }
125
+ if (site?.diagnostic) {
126
+ return site.diagnostic;
127
+ }
128
+ const label = error.name === "Error" ? "" : `${error.name}: `;
129
+ return {
130
+ code: "BLUME_BUILD_FAILED",
131
+ column: loc?.column,
132
+ file,
133
+ line: loc?.line,
134
+ message: `${label}${error.message}`,
135
+ severity: "error"
136
+ };
137
+ };
138
+ var astroBuildDiagnostics = async (rejection, context = {}) => {
139
+ const parsed = buildErrorSchema.safeParse(rejection);
140
+ const failures = parsed.success ? parsed.data.errors ?? [] : [];
141
+ return await Promise.all((failures.length > 0 ? failures : [rejection]).map(async (failure) => await failureDiagnostic(failure, context)));
142
+ };
143
+ var buildFailureLocator = (project) => (file, failure) => {
144
+ const page = project.graph.pages.find((candidate) => candidate.sourcePath === file);
145
+ const source = project.sources.find((candidate) => candidate.name === page?.source.name);
146
+ return locateMdxFailure({
147
+ contentRoot: source?.staged ? undefined : source?.contentRoot,
148
+ name: relative(project.context.root, file),
149
+ sourcePath: file,
150
+ variables: project.config.variables
151
+ }, failure);
152
+ };
153
+
154
+ export { astroBuildDiagnostics, buildFailureLocator };
155
+
156
+ //# debugId=A5E390AFCF69E70164756E2164756E21
157
+ //# sourceMappingURL=chunk-4zxh25hc.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/cli/build-failure.ts"],
4
+ "sourcesContent": [
5
+ "import { existsSync, readFileSync } from \"node:fs\";\n\nimport { basename, dirname, isAbsolute, join, relative, resolve } from \"pathe\";\nimport ts from \"typescript\";\nimport { z } from \"zod\";\n\nimport { locateMdxFailure } from \"../core/mdx-syntax.ts\";\nimport type { MdxFailure, MdxFailureSite } from \"../core/mdx-syntax.ts\";\nimport type { BlumeProject } from \"../core/project-graph.ts\";\nimport type { Diagnostic } from \"../core/types.ts\";\n\n/**\n * The fields of an `astro build` rejection the report reads. Rolldown bundles\n * every plugin failure (an MDX compile error, say) into one error whose\n * `errors` holds each; a failure carries `loc` where the compiler pinned it,\n * or only `id`, the module that failed.\n */\nconst buildErrorSchema = z.looseObject({\n errors: z.array(z.instanceof(Error)).optional(),\n id: z.string().optional(),\n loc: z\n .looseObject({\n column: z.number().optional(),\n file: z.string().optional(),\n line: z.number().optional(),\n })\n .optional(),\n});\n\n/**\n * The diagnostic a `BlumeError` thrown inside the build carries, such as a\n * failed hosted search sync in `astro:build:done`. The hook runs Blume's\n * source rather than the CLI bundle, so its error is another copy of the class\n * that the command's `instanceof BlumeError` doesn't recognize.\n */\nconst blumeErrorSchema = z.looseObject({\n diagnostic: z.object({\n code: z.string(),\n column: z.number().optional(),\n docsUrl: z.string().optional(),\n file: z.string().optional(),\n line: z.number().optional(),\n message: z.string(),\n severity: z.enum([\"error\", \"info\", \"warning\"]),\n suggestion: z.string().optional(),\n }),\n});\n\n/**\n * Finds where in an `.mdx` page's files a failure Astro reported with no line\n * happened (see `locateMdxFailure`).\n */\nexport type MdxFailureLocator = (\n file: string,\n failure: MdxFailure\n) => Promise<MdxFailureSite | null>;\n\n/** What the report reads besides the error. */\nexport interface BuildFailureContext {\n locate?: MdxFailureLocator;\n /** The project root, where the build reads `tsconfig.json`. */\n root?: string;\n}\n\n// The message for a name nothing defines, in V8 (Node) and JavaScriptCore (Bun).\nconst UNDEFINED_NAME = [\n /^(?<name>[\\w$]+) is not defined$/u,\n /^Can't find variable: (?<name>[\\w$]+)$/u,\n];\n// A compiler message that opens with where it failed.\nconst POSITIONED = /^\\d+:\\d+: /u;\n\n/**\n * A `{…}` expression in an `.mdx` page that reads a name nothing defines: the\n * page compiles, then throws while it renders. Placed at the expression when\n * the page (or a partial it includes) shows where.\n */\nconst undefinedNameDiagnostic = (\n name: string,\n file: string,\n site: MdxFailureSite | null\n): Diagnostic => {\n const escape =\n \"show the braces as text: escape each opening brace (`\\\\{`) or put it in inline code\";\n // `{{name}}` is a Blume variable the site doesn't define.\n const variable = site?.expression === `{{${name}}}`;\n return {\n code: \"BLUME_MDX_UNDEFINED_NAME\",\n column: site?.column,\n file: site?.file ?? file,\n line: site?.line,\n message: site?.expression\n ? `\\`${site.expression}\\` reads \\`${name}\\`, which isn't defined, so the page fails to render. In .mdx, \\`{…}\\` is a JavaScript expression.`\n : `\\`${name}\\` isn't defined, so the page fails to render. In .mdx, \\`{…}\\` is a JavaScript expression, and one reads it.`,\n severity: \"error\",\n suggestion: variable\n ? `Define \\`${name}\\` under \\`variables\\` in blume.config.ts, or ${escape}.`\n : `To ${escape}. For a value every page shares, define a variable in blume.config.ts and write \\`{{name}}\\`.`,\n };\n};\n\n// Vite's message for an `extends` or `references` entry it can't resolve. It\n// names an `extends` package as written, and a path resolved.\nconst TSCONFIG_NOT_FOUND = /Tsconfig not found (?<target>\\S+?)\\.?$/mu;\n\nconst tsconfigLinksSchema = z.object({\n extends: z.union([z.string(), z.array(z.string())]).optional(),\n references: z.array(z.object({ path: z.string() })).optional(),\n});\n\n/** An entry in a tsconfig's `extends` or `references`, as written. */\ninterface TsconfigLink {\n key: \"extends\" | \"references\";\n written: string;\n}\n\n/**\n * The `extends` or `references` entry in the tsconfig at `path` that names\n * `target`: written as is, or resolved from the tsconfig's folder (a\n * reference can name a folder, which means its `tsconfig.json`).\n */\nconst linkTo = (path: string, target: string): TsconfigLink | undefined => {\n const parsed = tsconfigLinksSchema.safeParse(\n ts.readConfigFile(path, ts.sys.readFile).config\n );\n if (!parsed.success) {\n return undefined;\n }\n const names = (written: string): boolean => {\n const resolved = resolve(dirname(path), written);\n return (\n written === target ||\n resolved === target ||\n join(resolved, \"tsconfig.json\") === target\n );\n };\n const extended = [parsed.data.extends ?? []].flat().find(names);\n if (extended !== undefined) {\n return { key: \"extends\", written: extended };\n }\n const referenced = (parsed.data.references ?? [])\n .map((reference) => reference.path)\n .find(names);\n return referenced === undefined\n ? undefined\n : { key: \"references\", written: referenced };\n};\n\n/** How to fix a tsconfig entry that doesn't resolve. */\nconst tsconfigFix = ({ key, written }: TsconfigLink, name: string): string => {\n if (key === \"references\") {\n return `Create \\`${written}\\` (a framework's generated tsconfig appears once its prepare or build step runs), or remove it from \\`references\\` in ${name}.`;\n }\n if (written.startsWith(\".\") || isAbsolute(written)) {\n return `Restore \\`${written}\\`, or remove it from \\`extends\\` in ${name}.`;\n }\n const packageName = written\n .split(\"/\")\n .slice(0, written.startsWith(\"@\") ? 2 : 1)\n .join(\"/\");\n return `Install the package that provides it (\\`${packageName}\\`), or remove it from \\`extends\\` in ${name}.`;\n};\n\n/**\n * An `extends` or `references` entry in the project's `tsconfig.json` that\n * doesn't resolve: Vite reads that file while it builds the site, so the\n * build fails in `astro sync` before any page compiles. Placed at the entry's\n * line when the project's own tsconfig names the target.\n */\nconst tsconfigExtendsDiagnostic = (\n target: string,\n root: string | undefined\n): Diagnostic => {\n const found = root\n ? [\"tsconfig.json\", \"jsconfig.json\"]\n .map((name) => join(root, name))\n .filter((path) => existsSync(path))\n .map((path) => ({ link: linkTo(path, target), path }))\n .find(({ link }) => link !== undefined)\n : undefined;\n const file = found?.path;\n const { key, written } = found?.link ?? { key: \"extends\", written: target };\n const line = file\n ? readFileSync(file, \"utf-8\")\n .split(\"\\n\")\n .findIndex((text) => text.includes(JSON.stringify(written))) + 1\n : 0;\n const name = file ? basename(file) : \"tsconfig.json\";\n return {\n code: \"BLUME_TSCONFIG_EXTENDS\",\n file,\n line: line > 0 ? line : undefined,\n message: `${file ? name : \"A tsconfig.json in the project\"} ${key} \\`${written}\\`, which can't be found. The build reads the project's ${name} to resolve imports, so it stops here.`,\n severity: \"error\",\n suggestion: tsconfigFix({ key, written }, name),\n };\n};\n\n/** The `extends` target an unresolvable tsconfig names, if `error` is that. */\nconst missingTsconfig = (error: Error): string | undefined =>\n (\n TSCONFIG_NOT_FOUND.exec(error.message) ??\n // `astro sync` wraps the resolver's error in its own.\n (error.cause instanceof Error\n ? TSCONFIG_NOT_FOUND.exec(error.cause.message)\n : null)\n )?.groups?.target;\n\n/** The name a render error says nothing defines, if it says that. */\nconst undefinedName = (error: Error): string | undefined =>\n error.name === \"ReferenceError\"\n ? UNDEFINED_NAME.map((pattern) => pattern.exec(error.message)).find(Boolean)\n ?.groups?.name\n : undefined;\n\n/**\n * Where in an `.mdx` page's files a failure the compiler didn't place\n * happened: a render error the page threw, or a compile error in a partial it\n * includes, which the compiler pins on the page with no `line:column:` in its\n * message. (Bun stamps a `line` of its own on every error, so `loc` can't\n * tell.)\n */\nconst locateFailure = async (\n error: Error,\n page: string,\n name: string | undefined,\n locate: MdxFailureLocator | undefined\n): Promise<MdxFailureSite | null> => {\n if (!locate) {\n return null;\n }\n if (name) {\n return await locate(page, { kind: \"undefined-name\", name });\n }\n return error.name === \"MDXError\" && !POSITIONED.test(error.message)\n ? await locate(page, { kind: \"syntax\" })\n : null;\n};\n\n/** One failure as a diagnostic at the file (and position) it names. */\nconst failureDiagnostic = async (\n error: Error,\n context: BuildFailureContext\n): Promise<Diagnostic> => {\n const raised = blumeErrorSchema.safeParse(error);\n if (raised.success) {\n return raised.data.diagnostic;\n }\n const tsconfig = missingTsconfig(error);\n if (tsconfig) {\n return tsconfigExtendsDiagnostic(tsconfig, context.root);\n }\n const parsed = buildErrorSchema.safeParse(error);\n const { id, loc } = parsed.success ? parsed.data : {};\n const file = loc?.file ?? id;\n const name = undefinedName(error);\n const site = file?.endsWith(\".mdx\")\n ? await locateFailure(error, file, name, context.locate)\n : null;\n if (file?.endsWith(\".mdx\") && name) {\n return undefinedNameDiagnostic(name, file, site);\n }\n if (site?.diagnostic) {\n return site.diagnostic;\n }\n // A named error (`MDXError`, `CompilerError`) says which step failed.\n const label = error.name === \"Error\" ? \"\" : `${error.name}: `;\n return {\n code: \"BLUME_BUILD_FAILED\",\n column: loc?.column,\n file,\n line: loc?.line,\n message: `${label}${error.message}`,\n severity: \"error\",\n };\n};\n\n/**\n * What `astro build` rejected with, as build diagnostics: one per failure\n * Rolldown collected, else the error itself. A page Blume's own checks pass\n * can still fail Astro's compile (MDX that doesn't parse) or render, and that\n * is a problem in the site, reported at its file, rather than an internal\n * error blaming Blume.\n */\nexport const astroBuildDiagnostics = async (\n rejection: Error,\n context: BuildFailureContext = {}\n): Promise<Diagnostic[]> => {\n const parsed = buildErrorSchema.safeParse(rejection);\n const failures = parsed.success ? (parsed.data.errors ?? []) : [];\n return await Promise.all(\n (failures.length > 0 ? failures : [rejection]).map(\n async (failure) => await failureDiagnostic(failure, context)\n )\n );\n};\n\n/**\n * The locator a build uses: the failing page's source, read with the includes\n * and variables the scan resolved for it.\n */\nexport const buildFailureLocator =\n (\n project: Pick<BlumeProject, \"config\" | \"context\" | \"graph\" | \"sources\">\n ): MdxFailureLocator =>\n (file, failure) => {\n const page = project.graph.pages.find(\n (candidate) => candidate.sourcePath === file\n );\n const source = project.sources.find(\n (candidate) => candidate.name === page?.source.name\n );\n return locateMdxFailure(\n {\n contentRoot: source?.staged ? undefined : source?.contentRoot,\n name: relative(project.context.root, file),\n sourcePath: file,\n variables: project.config.variables,\n },\n failure\n );\n };\n"
6
+ ],
7
+ "mappings": ";;;;;;AAAA;AAEA;AACA;AACA;AAaA,IAAM,mBAAmB,EAAE,YAAY;AAAA,EACrC,QAAQ,EAAE,MAAM,EAAE,WAAW,KAAK,CAAC,EAAE,SAAS;AAAA,EAC9C,IAAI,EAAE,OAAO,EAAE,SAAS;AAAA,EACxB,KAAK,EACF,YAAY;AAAA,IACX,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,IAC5B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,CAAC,EACA,SAAS;AACd,CAAC;AAQD,IAAM,mBAAmB,EAAE,YAAY;AAAA,EACrC,YAAY,EAAE,OAAO;AAAA,IACnB,MAAM,EAAE,OAAO;AAAA,IACf,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,IAC5B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,SAAS,EAAE,OAAO;AAAA,IAClB,UAAU,EAAE,KAAK,CAAC,SAAS,QAAQ,SAAS,CAAC;AAAA,IAC7C,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,CAAC;AACH,CAAC;AAmBD,IAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AACF;AAEA,IAAM,aAAa;AAOnB,IAAM,0BAA0B,CAC9B,MACA,MACA,SACe;AAAA,EACf,MAAM,SACJ;AAAA,EAEF,MAAM,WAAW,MAAM,eAAe,KAAK;AAAA,EAC3C,OAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,MAAM;AAAA,IACd,MAAM,MAAM,QAAQ;AAAA,IACpB,MAAM,MAAM;AAAA,IACZ,SAAS,MAAM,aACX,KAAK,KAAK,wBAAwB,2GAClC,KAAK;AAAA,IACT,UAAU;AAAA,IACV,YAAY,WACR,YAAY,qDAAqD,YACjE,MAAM;AAAA,EACZ;AAAA;AAKF,IAAM,qBAAqB;AAE3B,IAAM,sBAAsB,EAAE,OAAO;AAAA,EACnC,SAAS,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS;AAAA,EAC7D,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS;AAC/D,CAAC;AAaD,IAAM,SAAS,CAAC,MAAc,WAA6C;AAAA,EACzE,MAAM,SAAS,oBAAoB,UACjC,GAAG,eAAe,MAAM,GAAG,IAAI,QAAQ,EAAE,MAC3C;AAAA,EACA,IAAI,CAAC,OAAO,SAAS;AAAA,IACnB;AAAA,EACF;AAAA,EACA,MAAM,QAAQ,CAAC,YAA6B;AAAA,IAC1C,MAAM,WAAW,QAAQ,QAAQ,IAAI,GAAG,OAAO;AAAA,IAC/C,OACE,YAAY,UACZ,aAAa,UACb,KAAK,UAAU,eAAe,MAAM;AAAA;AAAA,EAGxC,MAAM,WAAW,CAAC,OAAO,KAAK,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK;AAAA,EAC9D,IAAI,aAAa,WAAW;AAAA,IAC1B,OAAO,EAAE,KAAK,WAAW,SAAS,SAAS;AAAA,EAC7C;AAAA,EACA,MAAM,cAAc,OAAO,KAAK,cAAc,CAAC,GAC5C,IAAI,CAAC,cAAc,UAAU,IAAI,EACjC,KAAK,KAAK;AAAA,EACb,OAAO,eAAe,YAClB,YACA,EAAE,KAAK,cAAc,SAAS,WAAW;AAAA;AAI/C,IAAM,cAAc,GAAG,KAAK,WAAyB,SAAyB;AAAA,EAC5E,IAAI,QAAQ,cAAc;AAAA,IACxB,OAAO,YAAY,iIAAiI;AAAA,EACtJ;AAAA,EACA,IAAI,QAAQ,WAAW,GAAG,KAAK,WAAW,OAAO,GAAG;AAAA,IAClD,OAAO,aAAa,+CAA+C;AAAA,EACrE;AAAA,EACA,MAAM,cAAc,QACjB,MAAM,GAAG,EACT,MAAM,GAAG,QAAQ,WAAW,GAAG,IAAI,IAAI,CAAC,EACxC,KAAK,GAAG;AAAA,EACX,OAAO,2CAA2C,oDAAoD;AAAA;AASxG,IAAM,4BAA4B,CAChC,QACA,SACe;AAAA,EACf,MAAM,QAAQ,OACV,CAAC,iBAAiB,eAAe,EAC9B,IAAI,CAAC,SAAS,KAAK,MAAM,IAAI,CAAC,EAC9B,OAAO,CAAC,SAAS,WAAW,IAAI,CAAC,EACjC,IAAI,CAAC,UAAU,EAAE,MAAM,OAAO,MAAM,MAAM,GAAG,KAAK,EAAE,EACpD,KAAK,GAAG,WAAW,SAAS,SAAS,IACxC;AAAA,EACJ,MAAM,OAAO,OAAO;AAAA,EACpB,QAAQ,KAAK,YAAY,OAAO,QAAQ,EAAE,KAAK,WAAW,SAAS,OAAO;AAAA,EAC1E,MAAM,OAAO,OACT,aAAa,MAAM,OAAO,EACvB,MAAM;AAAA,CAAI,EACV,UAAU,CAAC,SAAS,KAAK,SAAS,KAAK,UAAU,OAAO,CAAC,CAAC,IAAI,IACjE;AAAA,EACJ,MAAM,OAAO,OAAO,SAAS,IAAI,IAAI;AAAA,EACrC,OAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,MAAM,OAAO,IAAI,OAAO;AAAA,IACxB,SAAS,GAAG,OAAO,OAAO,oCAAoC,SAAS,kEAAkE;AAAA,IACzI,UAAU;AAAA,IACV,YAAY,YAAY,EAAE,KAAK,QAAQ,GAAG,IAAI;AAAA,EAChD;AAAA;AAIF,IAAM,kBAAkB,CAAC,WAErB,mBAAmB,KAAK,MAAM,OAAO,MAEpC,MAAM,iBAAiB,QACpB,mBAAmB,KAAK,MAAM,MAAM,OAAO,IAC3C,QACH,QAAQ;AAGb,IAAM,gBAAgB,CAAC,UACrB,MAAM,SAAS,mBACX,eAAe,IAAI,CAAC,YAAY,QAAQ,KAAK,MAAM,OAAO,CAAC,EAAE,KAAK,OAAO,GACrE,QAAQ,OACZ;AASN,IAAM,gBAAgB,OACpB,OACA,MACA,MACA,WACmC;AAAA,EACnC,IAAI,CAAC,QAAQ;AAAA,IACX,OAAO;AAAA,EACT;AAAA,EACA,IAAI,MAAM;AAAA,IACR,OAAO,MAAM,OAAO,MAAM,EAAE,MAAM,kBAAkB,KAAK,CAAC;AAAA,EAC5D;AAAA,EACA,OAAO,MAAM,SAAS,cAAc,CAAC,WAAW,KAAK,MAAM,OAAO,IAC9D,MAAM,OAAO,MAAM,EAAE,MAAM,SAAS,CAAC,IACrC;AAAA;AAIN,IAAM,oBAAoB,OACxB,OACA,YACwB;AAAA,EACxB,MAAM,SAAS,iBAAiB,UAAU,KAAK;AAAA,EAC/C,IAAI,OAAO,SAAS;AAAA,IAClB,OAAO,OAAO,KAAK;AAAA,EACrB;AAAA,EACA,MAAM,WAAW,gBAAgB,KAAK;AAAA,EACtC,IAAI,UAAU;AAAA,IACZ,OAAO,0BAA0B,UAAU,QAAQ,IAAI;AAAA,EACzD;AAAA,EACA,MAAM,SAAS,iBAAiB,UAAU,KAAK;AAAA,EAC/C,QAAQ,IAAI,QAAQ,OAAO,UAAU,OAAO,OAAO,CAAC;AAAA,EACpD,MAAM,OAAO,KAAK,QAAQ;AAAA,EAC1B,MAAM,OAAO,cAAc,KAAK;AAAA,EAChC,MAAM,OAAO,MAAM,SAAS,MAAM,IAC9B,MAAM,cAAc,OAAO,MAAM,MAAM,QAAQ,MAAM,IACrD;AAAA,EACJ,IAAI,MAAM,SAAS,MAAM,KAAK,MAAM;AAAA,IAClC,OAAO,wBAAwB,MAAM,MAAM,IAAI;AAAA,EACjD;AAAA,EACA,IAAI,MAAM,YAAY;AAAA,IACpB,OAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAQ,MAAM,SAAS,UAAU,KAAK,GAAG,MAAM;AAAA,EACrD,OAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,KAAK;AAAA,IACb;AAAA,IACA,MAAM,KAAK;AAAA,IACX,SAAS,GAAG,QAAQ,MAAM;AAAA,IAC1B,UAAU;AAAA,EACZ;AAAA;AAUK,IAAM,wBAAwB,OACnC,WACA,UAA+B,CAAC,MACN;AAAA,EAC1B,MAAM,SAAS,iBAAiB,UAAU,SAAS;AAAA,EACnD,MAAM,WAAW,OAAO,UAAW,OAAO,KAAK,UAAU,CAAC,IAAK,CAAC;AAAA,EAChE,OAAO,MAAM,QAAQ,KAClB,SAAS,SAAS,IAAI,WAAW,CAAC,SAAS,GAAG,IAC7C,OAAO,YAAY,MAAM,kBAAkB,SAAS,OAAO,CAC7D,CACF;AAAA;AAOK,IAAM,sBACX,CACE,YAEF,CAAC,MAAM,YAAY;AAAA,EACjB,MAAM,OAAO,QAAQ,MAAM,MAAM,KAC/B,CAAC,cAAc,UAAU,eAAe,IAC1C;AAAA,EACA,MAAM,SAAS,QAAQ,QAAQ,KAC7B,CAAC,cAAc,UAAU,SAAS,MAAM,OAAO,IACjD;AAAA,EACA,OAAO,iBACL;AAAA,IACE,aAAa,QAAQ,SAAS,YAAY,QAAQ;AAAA,IAClD,MAAM,SAAS,QAAQ,QAAQ,MAAM,IAAI;AAAA,IACzC,YAAY;AAAA,IACZ,WAAW,QAAQ,OAAO;AAAA,EAC5B,GACA,OACF;AAAA;",
8
+ "debugId": "A5E390AFCF69E70164756E2164756E21",
9
+ "names": []
10
+ }