blume 2.0.3 → 2.1.0

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 (455) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +48 -0
  3. package/README.md +1 -1
  4. package/dist/cli/{chunk-1d7ve1dm.js → chunk-0gz36akr.js} +18 -2
  5. package/dist/cli/{chunk-1d7ve1dm.js.map → chunk-0gz36akr.js.map} +3 -3
  6. package/dist/cli/{chunk-2eytanqx.js → chunk-1n228xqb.js} +2 -2
  7. package/dist/cli/{chunk-yfyb25rh.js → chunk-2f3ndkpw.js} +24 -8
  8. package/dist/cli/chunk-2f3ndkpw.js.map +14 -0
  9. package/dist/cli/{chunk-r20tn01b.js → chunk-2f7n4qzt.js} +8 -2
  10. package/dist/cli/{chunk-r20tn01b.js.map → chunk-2f7n4qzt.js.map} +3 -3
  11. package/dist/cli/{chunk-35d4wj9f.js → chunk-2n4ps1b3.js} +7 -7
  12. package/dist/cli/{chunk-j85vccga.js → chunk-43zcf4gz.js} +97 -57
  13. package/dist/cli/{chunk-j85vccga.js.map → chunk-43zcf4gz.js.map} +6 -6
  14. package/dist/cli/{chunk-e04dxsz1.js → chunk-4ejxbzee.js} +1 -1
  15. package/dist/cli/{chunk-5m5nmvyq.js → chunk-4h8z9vv5.js} +233 -39
  16. package/dist/cli/chunk-4h8z9vv5.js.map +16 -0
  17. package/dist/cli/{chunk-5f86nr5m.js → chunk-5cg2rzgf.js} +18 -16
  18. package/dist/cli/{chunk-5f86nr5m.js.map → chunk-5cg2rzgf.js.map} +2 -2
  19. package/dist/cli/{chunk-tzmab476.js → chunk-5ffywsmb.js} +4 -4
  20. package/dist/cli/{chunk-2z928egk.js → chunk-5wj2qwn2.js} +5 -5
  21. package/dist/cli/chunk-6bm0xpgd.js +18 -0
  22. package/dist/cli/chunk-6bm0xpgd.js.map +10 -0
  23. package/dist/cli/{chunk-vg9r4eb9.js → chunk-713mngdq.js} +12 -5
  24. package/dist/cli/{chunk-vg9r4eb9.js.map → chunk-713mngdq.js.map} +3 -3
  25. package/dist/cli/{chunk-5xvm6tfj.js → chunk-9geymqns.js} +17 -15
  26. package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-9geymqns.js.map} +2 -2
  27. package/dist/cli/{chunk-q58y5e6a.js → chunk-9xr4dgee.js} +26 -17
  28. package/dist/cli/chunk-9xr4dgee.js.map +10 -0
  29. package/dist/cli/{chunk-b07cmahc.js → chunk-amrb6hgh.js} +2 -2
  30. package/dist/cli/chunk-cm89scdv.js +443 -0
  31. package/dist/cli/chunk-cm89scdv.js.map +11 -0
  32. package/dist/cli/{chunk-akbpwfxc.js → chunk-cmtcnh9f.js} +2 -2
  33. package/dist/cli/chunk-cy5bm0j0.js +104 -0
  34. package/dist/cli/chunk-cy5bm0j0.js.map +11 -0
  35. package/dist/cli/{chunk-crgn1q09.js → chunk-e7vvk5ya.js} +4 -4
  36. package/dist/cli/{chunk-pehfxfta.js → chunk-g2z9x01v.js} +6 -98
  37. package/dist/cli/chunk-g2z9x01v.js.map +10 -0
  38. package/dist/cli/{chunk-tkacnehg.js → chunk-gp84za0h.js} +2 -2
  39. package/dist/cli/{chunk-wrr3j9w9.js → chunk-h2a48yhd.js} +186 -63
  40. package/dist/cli/chunk-h2a48yhd.js.map +36 -0
  41. package/dist/cli/{chunk-hm3vjy5s.js → chunk-jnwj5kjj.js} +14 -9
  42. package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-jnwj5kjj.js.map} +4 -4
  43. package/dist/cli/chunk-kwrg63tm.js +31 -0
  44. package/dist/cli/chunk-kwrg63tm.js.map +10 -0
  45. package/dist/cli/{chunk-2hsdwb9n.js → chunk-nd1821sk.js} +18 -16
  46. package/dist/cli/{chunk-2hsdwb9n.js.map → chunk-nd1821sk.js.map} +2 -2
  47. package/dist/cli/{chunk-6dsbexzp.js → chunk-ntv4qrt7.js} +17 -15
  48. package/dist/cli/{chunk-6dsbexzp.js.map → chunk-ntv4qrt7.js.map} +2 -2
  49. package/dist/cli/{chunk-r9rcc4w7.js → chunk-p804f3pe.js} +7 -7
  50. package/dist/cli/{chunk-ey84smr6.js → chunk-py62fewh.js} +6 -6
  51. package/dist/cli/{chunk-ey84smr6.js.map → chunk-py62fewh.js.map} +1 -1
  52. package/dist/cli/chunk-q3wxxq39.js +126 -0
  53. package/dist/cli/chunk-q3wxxq39.js.map +11 -0
  54. package/dist/cli/{chunk-9t7a85s3.js → chunk-rekqz4qg.js} +23 -13
  55. package/dist/cli/chunk-rekqz4qg.js.map +10 -0
  56. package/dist/cli/{chunk-8ktnccpt.js → chunk-ta27feev.js} +1 -1
  57. package/dist/cli/{chunk-pv29h0wf.js → chunk-xkz5xbtv.js} +3476 -822
  58. package/dist/cli/chunk-xkz5xbtv.js.map +213 -0
  59. package/dist/cli/{chunk-a58773jm.js → chunk-y4ykbark.js} +2 -2
  60. package/dist/cli/{chunk-p3v96n38.js → chunk-y5h4r2y0.js} +4 -4
  61. package/dist/cli/{chunk-acanzt5p.js → chunk-yj17vs39.js} +6 -6
  62. package/dist/cli/{chunk-p73c0m7w.js → chunk-yxmk4pec.js} +16 -14
  63. package/dist/cli/{chunk-p73c0m7w.js.map → chunk-yxmk4pec.js.map} +2 -2
  64. package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
  65. package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
  66. package/dist/cli/{chunk-c8chx29p.js → chunk-zf748avv.js} +384 -207
  67. package/dist/cli/chunk-zf748avv.js.map +37 -0
  68. package/dist/cli/{chunk-g4hq16wv.js → chunk-zhvd6adm.js} +16 -14
  69. package/dist/cli/{chunk-g4hq16wv.js.map → chunk-zhvd6adm.js.map} +2 -2
  70. package/dist/cli/index.js +26 -20
  71. package/dist/cli/index.js.map +5 -5
  72. package/dist/types/ai/agent-surface.d.ts +8 -7
  73. package/dist/types/ai/ai-catalog.d.ts +7 -0
  74. package/dist/types/ai/ask-context.d.ts +22 -0
  75. package/dist/types/ai/ask.d.ts +271 -58
  76. package/dist/types/ai/index.d.ts +2 -2
  77. package/dist/types/ai/site-skill.d.ts +26 -0
  78. package/dist/types/ai/skills.d.ts +16 -0
  79. package/dist/types/astro/integration.d.ts +8 -0
  80. package/dist/types/captcha/hcaptcha.d.ts +27 -0
  81. package/dist/types/captcha/index.d.ts +28 -0
  82. package/dist/types/captcha/schema.d.ts +29 -0
  83. package/dist/types/captcha/turnstile.d.ts +28 -0
  84. package/dist/types/components/content/api-field.d.ts +59 -0
  85. package/dist/types/components/content/api-page.d.ts +95 -0
  86. package/dist/types/components/layout/nav-utils.d.ts +26 -0
  87. package/dist/types/components/openapi/helpers.d.ts +137 -0
  88. package/dist/types/components/openapi/security.d.ts +85 -0
  89. package/dist/types/consent/ethyca.d.ts +48 -0
  90. package/dist/types/consent/index.d.ts +37 -0
  91. package/dist/types/consent/native.d.ts +28 -0
  92. package/dist/types/consent/osano.d.ts +42 -0
  93. package/dist/types/consent/schema.d.ts +110 -0
  94. package/dist/types/core/config-input.d.ts +187 -20
  95. package/dist/types/core/data.d.ts +49 -4
  96. package/dist/types/core/footer.d.ts +8 -0
  97. package/dist/types/core/i18n-ui.d.ts +86 -0
  98. package/dist/types/core/includes.d.ts +8 -2
  99. package/dist/types/core/localizable.d.ts +7 -0
  100. package/dist/types/core/page-modes.d.ts +29 -0
  101. package/dist/types/core/redirect-patterns.d.ts +144 -0
  102. package/dist/types/core/related.d.ts +40 -0
  103. package/dist/types/core/schema.d.ts +551 -56
  104. package/dist/types/core/sources/read.d.ts +5 -0
  105. package/dist/types/core/types.d.ts +1 -1
  106. package/dist/types/core/variables.d.ts +42 -0
  107. package/dist/types/deploy/node-headers.d.ts +13 -2
  108. package/dist/types/deploy/platforms/cloudflare.d.ts +5 -0
  109. package/dist/types/deploy/platforms/netlify.d.ts +7 -0
  110. package/dist/types/deploy/platforms/vercel.d.ts +6 -0
  111. package/dist/types/deploy/redirects.d.ts +39 -11
  112. package/dist/types/deploy/vercel-negotiation.d.ts +9 -0
  113. package/dist/types/markdown/code-title.d.ts +17 -0
  114. package/dist/types/markdown/features.d.ts +3 -2
  115. package/dist/types/narration/build.d.ts +70 -0
  116. package/dist/types/narration/provider.d.ts +26 -0
  117. package/dist/types/narration/script.d.ts +154 -0
  118. package/dist/types/openapi/model.d.ts +12 -6
  119. package/dist/types/openapi/overlay.d.ts +54 -0
  120. package/dist/types/openapi/parse.d.ts +13 -0
  121. package/dist/types/openapi/references.d.ts +14 -4
  122. package/dist/types/ratelimit/cloudflare.d.ts +39 -0
  123. package/dist/types/ratelimit/index.d.ts +27 -0
  124. package/dist/types/ratelimit/memory.d.ts +36 -0
  125. package/dist/types/ratelimit/schema.d.ts +111 -0
  126. package/dist/types/ratelimit/upstash.d.ts +21 -0
  127. package/dist/types/ratelimit/wrangler.d.ts +23 -0
  128. package/dist/types/reference/asyncapi.d.ts +10 -10
  129. package/dist/types/reference/graphql.d.ts +13 -10
  130. package/dist/types/reference/openapi.d.ts +33 -12
  131. package/dist/types/reference/options.d.ts +45 -5
  132. package/dist/types/reference/scalar.d.ts +13 -0
  133. package/dist/types/reference/schema.d.ts +60 -36
  134. package/dist/types/search/documents.d.ts +12 -1
  135. package/dist/types/search/orama-index.d.ts +4 -0
  136. package/dist/types/seo/metatags.d.ts +20 -0
  137. package/docs/02-deployment.mdx +41 -5
  138. package/docs/03-upgrading.mdx +4 -4
  139. package/docs/04-migrating.mdx +1 -1
  140. package/docs/advanced/changelog.mdx +2 -2
  141. package/docs/advanced/skills.mdx +14 -0
  142. package/docs/cli/audit.mdx +21 -1
  143. package/docs/cli/index.mdx +1 -0
  144. package/docs/configuration/analytics.mdx +3 -1
  145. package/docs/configuration/assistant.mdx +188 -36
  146. package/docs/configuration/consent.mdx +100 -0
  147. package/docs/configuration/customization.mdx +4 -4
  148. package/docs/configuration/index.mdx +63 -5
  149. package/docs/configuration/meta.ts +3 -0
  150. package/docs/configuration/narration.mdx +119 -0
  151. package/docs/configuration/rate-limiting.mdx +69 -0
  152. package/docs/configuration/search.mdx +29 -1
  153. package/docs/configuration/theming.mdx +3 -1
  154. package/docs/content/components.mdx +106 -0
  155. package/docs/content/frontmatter.mdx +76 -0
  156. package/docs/content/i18n.mdx +38 -3
  157. package/docs/content/includes.mdx +16 -0
  158. package/docs/content/meta.mdx +1 -0
  159. package/docs/content/meta.ts +1 -0
  160. package/docs/content/navigation.mdx +28 -6
  161. package/docs/content/sources/contentful.mdx +32 -0
  162. package/docs/content/sources/custom.mdx +39 -0
  163. package/docs/content/sources/github-releases.mdx +31 -0
  164. package/docs/content/sources/index.mdx +91 -0
  165. package/docs/content/sources/meta.ts +16 -0
  166. package/docs/content/sources/notion.mdx +32 -0
  167. package/docs/content/sources/obsidian.mdx +37 -0
  168. package/docs/content/sources/payload.mdx +30 -0
  169. package/docs/content/sources/remote-mdx.mdx +40 -0
  170. package/docs/content/sources/sanity.mdx +29 -0
  171. package/docs/content/sources/strapi.mdx +31 -0
  172. package/docs/content/syntax.mdx +67 -2
  173. package/docs/content/variables.mdx +41 -0
  174. package/docs/discoverability/agent-discovery.mdx +29 -2
  175. package/docs/discoverability/index.mdx +1 -1
  176. package/docs/discoverability/llms-txt.mdx +1 -1
  177. package/docs/discoverability/metadata.mdx +17 -0
  178. package/docs/references/api-pages.mdx +74 -0
  179. package/docs/references/asyncapi.mdx +1 -1
  180. package/docs/references/graphql.mdx +2 -2
  181. package/docs/references/meta.ts +1 -1
  182. package/docs/references/openapi.mdx +102 -3
  183. package/docs/references/scalar.mdx +3 -1
  184. package/package.json +36 -1
  185. package/skills/blume/SKILL.md +3 -0
  186. package/skills/blume-migrate/SKILL.md +5 -5
  187. package/skills/blume-migrate/references/docusaurus.md +3 -3
  188. package/skills/blume-migrate/references/mintlify.md +37 -19
  189. package/skills/blume-migrate/references/nextra.md +2 -2
  190. package/skills/blume-migrate/references/starlight.md +2 -1
  191. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
  192. package/skills/blume-write-skill/SKILL.md +82 -0
  193. package/src/ai/agent-readability.ts +2 -1
  194. package/src/ai/agent-surface.ts +9 -7
  195. package/src/ai/ai-catalog.ts +6 -3
  196. package/src/ai/ask-context.ts +73 -20
  197. package/src/ai/ask-data.ts +6 -0
  198. package/src/ai/ask-tools.ts +142 -0
  199. package/src/ai/ask.ts +354 -76
  200. package/src/ai/component-markdown.ts +75 -0
  201. package/src/ai/cors.ts +2 -0
  202. package/src/ai/index.ts +12 -0
  203. package/src/ai/llms.ts +6 -2
  204. package/src/ai/markdown.ts +2 -1
  205. package/src/ai/mcp/data.ts +6 -0
  206. package/src/ai/openapi-components.ts +9 -3
  207. package/src/ai/site-skill.ts +274 -0
  208. package/src/ai/skills.ts +35 -2
  209. package/src/ai/write-skill.ts +97 -0
  210. package/src/astro/generate.ts +132 -18
  211. package/src/astro/index.ts +1 -0
  212. package/src/astro/integration.ts +35 -0
  213. package/src/astro/module-types.ts +6 -0
  214. package/src/astro/templates.ts +283 -30
  215. package/src/astro/variables.ts +31 -0
  216. package/src/audit/catalog.ts +19 -0
  217. package/src/audit/checks/contrast.ts +183 -0
  218. package/src/audit/checks/i18n.ts +2 -3
  219. package/src/audit/checks/indexability.ts +2 -3
  220. package/src/audit/checks/links.ts +5 -12
  221. package/src/audit/checks/sitemap.ts +2 -3
  222. package/src/audit/redirects.ts +46 -15
  223. package/src/audit/run.ts +2 -0
  224. package/src/audit/types.ts +2 -1
  225. package/src/blume-modules.d.ts +7 -0
  226. package/src/captcha/client.ts +152 -0
  227. package/src/captcha/hcaptcha.ts +36 -0
  228. package/src/captcha/index.ts +28 -0
  229. package/src/captcha/schema.ts +32 -0
  230. package/src/captcha/turnstile.ts +38 -0
  231. package/src/captcha/verify.ts +71 -0
  232. package/src/cli/command-meta.ts +5 -0
  233. package/src/cli/commands/doctor.ts +22 -16
  234. package/src/cli/commands/skill.ts +96 -0
  235. package/src/cli/index.ts +5 -0
  236. package/src/cli/required-secrets.ts +71 -29
  237. package/src/components/BlumePage.astro +2 -0
  238. package/src/components/content/ApiEndpoint.astro +18 -0
  239. package/src/components/content/ApiField.astro +79 -0
  240. package/src/components/content/ApiPlayground.astro +62 -0
  241. package/src/components/content/ApiRail.astro +19 -0
  242. package/src/components/content/Color.astro +1 -0
  243. package/src/components/content/FileTree.astro +1 -0
  244. package/src/components/content/GithubInfo.astro +1 -0
  245. package/src/components/content/Panel.astro +1 -0
  246. package/src/components/content/ParamField.astro +25 -0
  247. package/src/components/content/RequestExample.astro +17 -0
  248. package/src/components/content/ResponseExample.astro +17 -0
  249. package/src/components/content/ResponseField.astro +32 -0
  250. package/src/components/content/Step.astro +1 -0
  251. package/src/components/content/Tile.astro +1 -0
  252. package/src/components/content/Tooltip.astro +1 -0
  253. package/src/components/content/Tree.astro +1 -0
  254. package/src/components/content/TypeTable.astro +4 -1
  255. package/src/components/content/View.astro +21 -0
  256. package/src/components/content/ViewSwitcher.astro +168 -0
  257. package/src/components/content/api-field.ts +100 -0
  258. package/src/components/content/api-page.ts +224 -0
  259. package/src/components/content/view-switcher.ts +71 -0
  260. package/src/components/index.ts +2 -0
  261. package/src/components/islands/Assistant.astro +10 -1
  262. package/src/components/islands/assistant.tsx +104 -14
  263. package/src/components/islands/code-question.ts +62 -0
  264. package/src/components/islands/hooks.ts +110 -21
  265. package/src/components/islands/support-link.ts +68 -0
  266. package/src/components/layout/Analytics.astro +11 -2
  267. package/src/components/layout/Banner.astro +14 -10
  268. package/src/components/layout/Breadcrumbs.astro +6 -2
  269. package/src/components/layout/ConsentBanner.astro +62 -0
  270. package/src/components/layout/ConsentHead.astro +38 -0
  271. package/src/components/layout/Directory.astro +94 -0
  272. package/src/components/layout/DrawerSwitchers.astro +51 -0
  273. package/src/components/layout/Empty.astro +2 -2
  274. package/src/components/layout/Header.astro +122 -80
  275. package/src/components/layout/LanguageSwitcher.astro +48 -15
  276. package/src/components/layout/NarrationPlayer.astro +1085 -0
  277. package/src/components/layout/NavSelector.astro +33 -7
  278. package/src/components/layout/PageFeedback.astro +54 -49
  279. package/src/components/layout/PageLayout.astro +71 -3
  280. package/src/components/layout/ReferenceLayout.astro +17 -6
  281. package/src/components/layout/RelatedPages.astro +42 -0
  282. package/src/components/layout/RootLayout.astro +308 -45
  283. package/src/components/layout/Search.astro +31 -17
  284. package/src/components/layout/SiteFooter.astro +124 -0
  285. package/src/components/layout/SiteMetatags.astro +16 -0
  286. package/src/components/layout/consent/native.ts +79 -0
  287. package/src/components/layout/consent/types.ts +37 -0
  288. package/src/components/layout/footer-links.ts +53 -0
  289. package/src/components/layout/footer-socials.ts +87 -0
  290. package/src/components/layout/locale-redirect.ts +107 -0
  291. package/src/components/layout/nav-utils.ts +83 -0
  292. package/src/components/layout/page-feedback.ts +96 -0
  293. package/src/components/layout/search/analytics.ts +98 -0
  294. package/src/components/layout/search/flexsearch.ts +17 -5
  295. package/src/components/layout/search/orama-cloud.ts +26 -14
  296. package/src/components/layout/search/types.ts +20 -0
  297. package/src/components/layout/search/typesense.ts +5 -1
  298. package/src/components/openapi/Operation.astro +161 -13
  299. package/src/components/openapi/RequestBody.astro +6 -4
  300. package/src/components/openapi/RequestPanel.astro +59 -7
  301. package/src/components/openapi/Responses.astro +6 -4
  302. package/src/components/openapi/async-snippets.ts +4 -4
  303. package/src/components/openapi/code-samples.ts +97 -0
  304. package/src/components/openapi/security.ts +6 -3
  305. package/src/components/openapi/snippets.ts +869 -8
  306. package/src/components/props.ts +6 -0
  307. package/src/consent/client.ts +95 -0
  308. package/src/consent/clients.ts +19 -0
  309. package/src/consent/ethyca.ts +71 -0
  310. package/src/consent/head.ts +24 -0
  311. package/src/consent/index.ts +37 -0
  312. package/src/consent/init.ts +29 -0
  313. package/src/consent/native.ts +36 -0
  314. package/src/consent/osano.ts +59 -0
  315. package/src/consent/schema.ts +30 -0
  316. package/src/core/builtin-tags.ts +5 -0
  317. package/src/core/client-address.ts +19 -0
  318. package/src/core/config-input.ts +194 -20
  319. package/src/core/data.ts +44 -4
  320. package/src/core/diagnostics.ts +3 -2
  321. package/src/core/footer.ts +26 -0
  322. package/src/core/graph.ts +39 -36
  323. package/src/core/i18n-ui.ts +82 -2
  324. package/src/core/includes.ts +20 -3
  325. package/src/core/links.ts +16 -2
  326. package/src/core/localizable.ts +26 -0
  327. package/src/core/navigation.ts +43 -12
  328. package/src/core/page-modes.ts +56 -0
  329. package/src/core/project-graph.ts +111 -5
  330. package/src/core/redirect-patterns.ts +491 -0
  331. package/src/core/related.ts +131 -0
  332. package/src/core/schema.ts +318 -64
  333. package/src/core/sources/normalize.ts +2 -1
  334. package/src/core/sources/read.ts +8 -3
  335. package/src/core/types.ts +1 -1
  336. package/src/core/ui-packs/ar.ts +43 -0
  337. package/src/core/ui-packs/bg.ts +45 -0
  338. package/src/core/ui-packs/bn.ts +43 -0
  339. package/src/core/ui-packs/ca.ts +46 -0
  340. package/src/core/ui-packs/cs.ts +44 -0
  341. package/src/core/ui-packs/da.ts +45 -0
  342. package/src/core/ui-packs/de.ts +46 -0
  343. package/src/core/ui-packs/el.ts +45 -0
  344. package/src/core/ui-packs/es.ts +46 -0
  345. package/src/core/ui-packs/fa.ts +45 -0
  346. package/src/core/ui-packs/fi.ts +45 -0
  347. package/src/core/ui-packs/fr.ts +46 -0
  348. package/src/core/ui-packs/he.ts +43 -0
  349. package/src/core/ui-packs/hi.ts +44 -0
  350. package/src/core/ui-packs/hr.ts +45 -0
  351. package/src/core/ui-packs/hu.ts +44 -0
  352. package/src/core/ui-packs/id.ts +45 -0
  353. package/src/core/ui-packs/it.ts +45 -0
  354. package/src/core/ui-packs/ja.ts +45 -0
  355. package/src/core/ui-packs/ko.ts +44 -0
  356. package/src/core/ui-packs/nl.ts +46 -0
  357. package/src/core/ui-packs/no.ts +44 -0
  358. package/src/core/ui-packs/pl.ts +45 -0
  359. package/src/core/ui-packs/pt-br.ts +46 -0
  360. package/src/core/ui-packs/pt.ts +45 -0
  361. package/src/core/ui-packs/ro.ts +45 -0
  362. package/src/core/ui-packs/ru.ts +45 -0
  363. package/src/core/ui-packs/sk.ts +44 -0
  364. package/src/core/ui-packs/sr.ts +45 -0
  365. package/src/core/ui-packs/sv.ts +44 -0
  366. package/src/core/ui-packs/th.ts +43 -0
  367. package/src/core/ui-packs/tr.ts +45 -0
  368. package/src/core/ui-packs/uk.ts +45 -0
  369. package/src/core/ui-packs/vi.ts +45 -0
  370. package/src/core/ui-packs/zh-tw.ts +43 -0
  371. package/src/core/ui-packs/zh.ts +43 -0
  372. package/src/core/variables.ts +103 -0
  373. package/src/deploy/artifacts.ts +77 -8
  374. package/src/deploy/cloudflare-negotiation.ts +35 -5
  375. package/src/deploy/headers.ts +2 -1
  376. package/src/deploy/node-headers.ts +63 -9
  377. package/src/deploy/platforms/cloudflare.ts +32 -0
  378. package/src/deploy/platforms/netlify.ts +33 -1
  379. package/src/deploy/platforms/vercel.ts +37 -2
  380. package/src/deploy/redirects.ts +91 -24
  381. package/src/deploy/vercel-negotiation.ts +36 -0
  382. package/src/markdown/api-rail.ts +259 -0
  383. package/src/markdown/code-title.ts +35 -9
  384. package/src/markdown/features.ts +3 -2
  385. package/src/markdown/fence-meta.ts +2 -0
  386. package/src/markdown/include.ts +11 -1
  387. package/src/markdown/index.ts +28 -5
  388. package/src/markdown/math.ts +4 -4
  389. package/src/markdown/variables.ts +56 -0
  390. package/src/markdown/views.ts +82 -0
  391. package/src/narration/build.ts +412 -0
  392. package/src/narration/player.ts +249 -0
  393. package/src/narration/provider.ts +29 -0
  394. package/src/narration/script.ts +592 -0
  395. package/src/og/card.ts +7 -6
  396. package/src/openapi/model.ts +57 -24
  397. package/src/openapi/overlay.ts +256 -0
  398. package/src/openapi/parse.ts +55 -2
  399. package/src/openapi/references.ts +21 -5
  400. package/src/openapi/render-mdx.ts +5 -1
  401. package/src/openapi/scalar.ts +40 -6
  402. package/src/openapi/source.ts +1 -1
  403. package/src/ratelimit/cloudflare.ts +54 -0
  404. package/src/ratelimit/index.ts +30 -0
  405. package/src/ratelimit/memory.ts +45 -0
  406. package/src/ratelimit/runtime.ts +229 -0
  407. package/src/ratelimit/schema.ts +28 -0
  408. package/src/ratelimit/upstash.ts +30 -0
  409. package/src/ratelimit/wrangler.ts +70 -0
  410. package/src/reference/asyncapi.ts +2 -2
  411. package/src/reference/graphql.ts +5 -2
  412. package/src/reference/openapi.ts +21 -7
  413. package/src/reference/options.ts +51 -7
  414. package/src/reference/scalar.ts +33 -8
  415. package/src/registry/eject.ts +20 -4
  416. package/src/registry/registry.ts +7 -0
  417. package/src/search/documents.ts +26 -2
  418. package/src/search/orama-index.ts +28 -3
  419. package/src/search/pagefind-ranking.ts +39 -0
  420. package/src/search/sync/algolia.ts +15 -4
  421. package/src/search/sync/orama-cloud.ts +3 -0
  422. package/src/search/sync/typesense.ts +5 -0
  423. package/src/seo/metatags.ts +67 -0
  424. package/src/theme/chrome-icons.ts +1 -0
  425. package/src/theme/color.ts +500 -0
  426. package/src/theme/entry.ts +56 -3
  427. package/src/theme/palette.ts +121 -45
  428. package/src/translate/prompts.ts +1 -0
  429. package/src/translate/validate.ts +8 -2
  430. package/src/upgrade/upgrade.ts +4 -171
  431. package/dist/cli/chunk-364znk6q.js +0 -75
  432. package/dist/cli/chunk-364znk6q.js.map +0 -11
  433. package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
  434. package/dist/cli/chunk-9t7a85s3.js.map +0 -10
  435. package/dist/cli/chunk-c8chx29p.js.map +0 -36
  436. package/dist/cli/chunk-pehfxfta.js.map +0 -10
  437. package/dist/cli/chunk-pv29h0wf.js.map +0 -190
  438. package/dist/cli/chunk-q58y5e6a.js.map +0 -10
  439. package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
  440. package/dist/cli/chunk-yfyb25rh.js.map +0 -14
  441. package/docs/content/sources.mdx +0 -334
  442. /package/dist/cli/{chunk-2eytanqx.js.map → chunk-1n228xqb.js.map} +0 -0
  443. /package/dist/cli/{chunk-35d4wj9f.js.map → chunk-2n4ps1b3.js.map} +0 -0
  444. /package/dist/cli/{chunk-e04dxsz1.js.map → chunk-4ejxbzee.js.map} +0 -0
  445. /package/dist/cli/{chunk-tzmab476.js.map → chunk-5ffywsmb.js.map} +0 -0
  446. /package/dist/cli/{chunk-2z928egk.js.map → chunk-5wj2qwn2.js.map} +0 -0
  447. /package/dist/cli/{chunk-b07cmahc.js.map → chunk-amrb6hgh.js.map} +0 -0
  448. /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-cmtcnh9f.js.map} +0 -0
  449. /package/dist/cli/{chunk-crgn1q09.js.map → chunk-e7vvk5ya.js.map} +0 -0
  450. /package/dist/cli/{chunk-tkacnehg.js.map → chunk-gp84za0h.js.map} +0 -0
  451. /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-p804f3pe.js.map} +0 -0
  452. /package/dist/cli/{chunk-8ktnccpt.js.map → chunk-ta27feev.js.map} +0 -0
  453. /package/dist/cli/{chunk-a58773jm.js.map → chunk-y4ykbark.js.map} +0 -0
  454. /package/dist/cli/{chunk-p3v96n38.js.map → chunk-y5h4r2y0.js.map} +0 -0
  455. /package/dist/cli/{chunk-acanzt5p.js.map → chunk-yj17vs39.js.map} +0 -0
@@ -1,21 +1,90 @@
1
1
  import type { ResolvedConfig } from "../core/schema.ts";
2
+ import { composite, contrastRatio, parseColor } from "./color.ts";
3
+ import type { Rgba } from "./color.ts";
2
4
 
3
- const FALLBACK_ACCENT = "oklch(0.62 0.16 250)";
5
+ /** Per-mode CSS colors. */
6
+ export interface AccentColors {
7
+ dark: string;
8
+ light: string;
9
+ }
10
+
11
+ /** A color mode. */
12
+ export type ColorMode = keyof AccentColors;
4
13
 
5
14
  /**
6
- * Named accent presets mapped to OKLCH values. The single source of truth for
7
- * preset colors: the theme CSS and the OG card (og/card.ts) both resolve from
8
- * this table, so a site and its social cards can't disagree about "blue".
15
+ * Named accent presets mapped to OKLCH values, per mode. The single source of
16
+ * truth for preset colors: the theme CSS and the OG card (og/card.ts) both
17
+ * resolve from this table, so a site and its social cards can't disagree
18
+ * about "blue". Each clears WCAG AA (4.5:1) as text on its mode's page and
19
+ * under its button label ({@link readableOn}), with room to spare on the
20
+ * tinted surfaces accent text also sits on: the light shades are dark enough
21
+ * for white labels, the dark shades light enough to read on the dark page.
9
22
  */
10
23
  export const ACCENTS = {
11
- blue: FALLBACK_ACCENT,
12
- green: "oklch(0.6 0.16 150)",
13
- orange: "oklch(0.68 0.17 50)",
14
- pink: "oklch(0.65 0.2 350)",
15
- purple: "oklch(0.58 0.2 290)",
16
- red: "oklch(0.58 0.22 25)",
17
- teal: "oklch(0.6 0.12 195)",
18
- } satisfies Record<string, string>;
24
+ blue: { dark: "oklch(0.62 0.16 250)", light: "oklch(0.55 0.16 250)" },
25
+ green: { dark: "oklch(0.6 0.16 150)", light: "oklch(0.53 0.16 150)" },
26
+ orange: { dark: "oklch(0.68 0.17 50)", light: "oklch(0.56 0.17 50)" },
27
+ pink: { dark: "oklch(0.65 0.2 350)", light: "oklch(0.58 0.2 350)" },
28
+ purple: { dark: "oklch(0.6 0.2 290)", light: "oklch(0.57 0.2 290)" },
29
+ red: { dark: "oklch(0.61 0.22 25)", light: "oklch(0.58 0.22 25)" },
30
+ teal: { dark: "oklch(0.6 0.12 195)", light: "oklch(0.53 0.12 195)" },
31
+ } satisfies Record<string, AccentColors>;
32
+
33
+ /** The contrast WCAG AA asks of body-size text. */
34
+ export const MIN_TEXT_CONTRAST = 4.5;
35
+
36
+ /**
37
+ * The theme's own colors a configured accent is drawn against: each mode's
38
+ * page background and text, and the dark ink a filled accent can carry.
39
+ * Mirrors the defaults in `entry.ts`.
40
+ */
41
+ export const THEME_INKS = {
42
+ dark: {
43
+ background: "oklch(0.085 0 0)",
44
+ foreground: "oklch(0.96 0 0)",
45
+ ink: "oklch(0.085 0 0)",
46
+ mutedForeground: "oklch(0.68 0 0)",
47
+ },
48
+ light: {
49
+ background: "oklch(1 0 0)",
50
+ foreground: "oklch(0.145 0 0)",
51
+ ink: "oklch(0.145 0 0)",
52
+ mutedForeground: "oklch(0.53 0 0)",
53
+ },
54
+ } satisfies Record<ColorMode, Record<string, string>>;
55
+
56
+ const WHITE = "oklch(1 0 0)";
57
+
58
+ /** A color this module writes itself, parsed (they all parse). */
59
+ const own = (value: string): Rgba =>
60
+ parseColor(value) ?? { alpha: 1, blue: 0, green: 0, red: 0 };
61
+
62
+ /** {@link THEME_INKS}, parsed, for contrast math. */
63
+ export const themeInk = (
64
+ mode: ColorMode,
65
+ name: keyof (typeof THEME_INKS)[ColorMode]
66
+ ): Rgba => own(THEME_INKS[mode][name]);
67
+
68
+ /**
69
+ * The label color for text on a filled `fill` (a button, a step number): white
70
+ * while it reaches AA, else the mode's dark ink when that reads better, so a
71
+ * light accent (every dark-mode preset) gets dark text instead of white text
72
+ * nobody can read.
73
+ */
74
+ export const labelOn = (fill: Rgba, mode: ColorMode): string => {
75
+ const opaque = composite(fill, themeInk(mode, "background"));
76
+ const onWhite = contrastRatio(own(WHITE), opaque);
77
+ return onWhite >= MIN_TEXT_CONTRAST ||
78
+ onWhite >= contrastRatio(themeInk(mode, "ink"), opaque)
79
+ ? WHITE
80
+ : THEME_INKS[mode].ink;
81
+ };
82
+
83
+ /** {@link labelOn} for a CSS color; one this module can't parse keeps white. */
84
+ export const readableOn = (fill: string, mode: ColorMode): string => {
85
+ const color = parseColor(fill);
86
+ return color ? labelOn(color, mode) : WHITE;
87
+ };
19
88
 
20
89
  /**
21
90
  * Whether a raw config value names an accent preset. `hasOwn` keeps a value
@@ -35,9 +104,11 @@ const CSS_COLOR = /^[\w\s#%.,()/+-]+$/u;
35
104
  const safeColor = (value: string, fallback: string): string =>
36
105
  CSS_COLOR.test(value.trim()) ? value.trim() : fallback;
37
106
 
38
- /** Resolve a named preset or fall back to {@link safeColor}. */
39
- const presetOrColor = (value: string): string =>
40
- isAccentPreset(value) ? ACCENTS[value] : safeColor(value, FALLBACK_ACCENT);
107
+ /** Resolve a named preset in `mode`, or fall back to {@link safeColor}. */
108
+ const presetOrColor = (value: string, mode: ColorMode): string =>
109
+ isAccentPreset(value)
110
+ ? ACCENTS[value][mode]
111
+ : safeColor(value, ACCENTS.blue[mode]);
41
112
 
42
113
  /** Like {@link safeColor} but drops an unsafe/absent value to `null`. */
43
114
  const safeColorOrNull = (value: string | undefined): string | null =>
@@ -58,20 +129,23 @@ const backgroundImageCss = (image: string): string =>
58
129
  const cssToken = (name: string, value?: string | null): string[] =>
59
130
  value ? [` ${name}: ${value};`] : [];
60
131
 
132
+ /** One mode's resolved accent and action fills. */
133
+ interface ModeFills {
134
+ accent: string;
135
+ action: string | null;
136
+ }
137
+
61
138
  const themeRootCss = (
62
139
  theme: ResolvedConfig["theme"],
63
- options: {
64
- accent: string;
65
- action: string | null;
66
- radius: string;
67
- }
140
+ options: ModeFills & { radius: string }
68
141
  ): string =>
69
142
  [
70
143
  ` --blume-accent: ${options.accent};`,
144
+ ` --blume-accent-foreground: ${readableOn(options.accent, "light")};`,
71
145
  ...cssToken("--blume-action", options.action),
72
146
  ...cssToken(
73
147
  "--blume-action-foreground",
74
- options.action ? "oklch(1 0 0)" : null
148
+ options.action ? readableOn(options.action, "light") : null
75
149
  ),
76
150
  ...cssToken("--blume-background", safeColorOrNull(theme.background?.light)),
77
151
  ...cssToken(
@@ -87,10 +161,7 @@ const themeRootCss = (
87
161
 
88
162
  const themeDarkCss = (
89
163
  theme: ResolvedConfig["theme"],
90
- options: {
91
- accent: string;
92
- action: string | null;
93
- }
164
+ options: ModeFills
94
165
  ): string => {
95
166
  // Mode-shared tokens (accent, action) must be re-declared here: the base
96
167
  // stylesheet's own `:root[data-theme="dark"]` block outranks the `:root`
@@ -98,11 +169,11 @@ const themeDarkCss = (
98
169
  // silently keep its neutral defaults and ignore the config.
99
170
  const tokens = [
100
171
  ` --blume-accent: ${options.accent};`,
101
- " --blume-accent-foreground: oklch(1 0 0);",
172
+ ` --blume-accent-foreground: ${readableOn(options.accent, "dark")};`,
102
173
  ...cssToken("--blume-action", options.action),
103
174
  ...cssToken(
104
175
  "--blume-action-foreground",
105
- options.action ? "oklch(1 0 0)" : null
176
+ options.action ? readableOn(options.action, "dark") : null
106
177
  ),
107
178
  ...cssToken("--blume-background", safeColorOrNull(theme.background?.dark)),
108
179
  ...cssToken(
@@ -118,26 +189,31 @@ ${tokens.join("\n")}
118
189
  `;
119
190
  };
120
191
 
121
- /** Per-mode accent CSS colors. */
122
- export interface AccentColors {
123
- dark: string;
124
- light: string;
125
- }
126
-
127
192
  /**
128
193
  * Resolve the configured accent to per-mode CSS colors. A named accent
129
- * resolves to its preset; any other value is treated as a raw CSS color so
130
- * users can pass arbitrary colors without a config change. A string accent
131
- * has already been normalized by the config schema to the same color for
132
- * both modes.
194
+ * resolves to its preset's shade for each mode; any other value is treated as
195
+ * a raw CSS color so users can pass arbitrary colors without a config change.
196
+ * A string accent has already been normalized by the config schema to the
197
+ * same value for both modes.
133
198
  */
134
199
  export const resolveAccent = (
135
200
  theme: ResolvedConfig["theme"]
136
201
  ): AccentColors => ({
137
- dark: presetOrColor(theme.accent.dark),
138
- light: presetOrColor(theme.accent.light),
202
+ dark: presetOrColor(theme.accent.dark, "dark"),
203
+ light: presetOrColor(theme.accent.light, "light"),
139
204
  });
140
205
 
206
+ /** Resolve the configured `action` fill per mode, or `null` when unset. */
207
+ export const resolveAction = (
208
+ theme: ResolvedConfig["theme"]
209
+ ): AccentColors | null =>
210
+ theme.action
211
+ ? {
212
+ dark: presetOrColor(theme.action, "dark"),
213
+ light: presetOrColor(theme.action, "light"),
214
+ }
215
+ : null;
216
+
141
217
  /** Resolve the configured radius preset to a CSS length. */
142
218
  export const resolveRadius = (theme: ResolvedConfig["theme"]): string =>
143
219
  RADII[theme.radius];
@@ -145,20 +221,20 @@ export const resolveRadius = (theme: ResolvedConfig["theme"]): string =>
145
221
  /**
146
222
  * Compile theme config into CSS custom properties. A named accent resolves to
147
223
  * its preset; any other value is treated as a raw CSS color so users can pass
148
- * arbitrary colors without a config change.
224
+ * arbitrary colors without a config change. Labels on accent and action fills
225
+ * take whichever of white or dark ink reads ({@link readableOn}).
149
226
  */
150
227
  export const buildThemeCss = (theme: ResolvedConfig["theme"]): string => {
151
228
  const accent = resolveAccent(theme);
152
- const action = theme.action ? presetOrColor(theme.action) : null;
153
- const radius = RADII[theme.radius];
229
+ const action = resolveAction(theme);
154
230
  const root = themeRootCss(theme, {
155
231
  accent: accent.light,
156
- action,
157
- radius,
232
+ action: action?.light ?? null,
233
+ radius: RADII[theme.radius],
158
234
  });
159
235
  const dark = themeDarkCss(theme, {
160
236
  accent: accent.dark,
161
- action,
237
+ action: action?.dark ?? null,
162
238
  });
163
239
 
164
240
  return `/* Generated by Blume from theme config. */
@@ -64,6 +64,7 @@ ${previousTranslation}`;
64
64
  Rules:
65
65
  - Translate the prose: headings, paragraphs, list items, table cells, admonitions, and image alt text.
66
66
  - In the YAML frontmatter, translate ONLY the values of these keys: ${KEY_LIST}. Copy every other frontmatter key and value exactly as written.
67
+ - Keep the frontmatter valid YAML: if a translated value contains a colon followed by a space (\`: \`) or a space followed by \`#\`, or starts with a quote, a backtick, or another YAML indicator character, write it as a double-quoted string and escape any double quotes inside it.
67
68
  - Never translate or alter: code blocks, inline code, import/export statements, JSX/MDX component names and their attributes, URLs, link targets, HTML tags, or frontmatter keys.
68
69
  - A heading may end with anchor markers: \`[#some-id]\`, \`{#some-id}\` (also written \`\\{#some-id\\}\`), \`[!toc]\`, or \`[toc]\`. Copy every marker exactly as written, in the same position at the end of the translated heading — never translate, reorder, or drop a marker, and never change the id inside \`[#...]\` or \`{#...}\` (anchors must stay identical across languages).
69
70
 
@@ -132,8 +132,14 @@ export const validateTranslation = (
132
132
  let parsed: { content: string; data: FrontmatterData };
133
133
  try {
134
134
  parsed = matter(candidate);
135
- } catch {
136
- return { ok: false, reason: "frontmatter does not parse as YAML" };
135
+ } catch (error) {
136
+ // js-yaml's message leads with the problem and its line:column in the
137
+ // file, then a multi-line code frame; the first line is enough to act on.
138
+ const message = error instanceof Error ? error.message : String(error);
139
+ return {
140
+ ok: false,
141
+ reason: `frontmatter does not parse as YAML: ${message.replace(/\n[\s\S]*$/u, "")}`,
142
+ };
137
143
  }
138
144
 
139
145
  const rawBody = ensureTrailingNewline(parsed.content.replace(/^\r?\n/u, ""));
@@ -1,8 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { readFile, writeFile } from "node:fs/promises";
3
3
 
4
- import { join, relative, resolve } from "pathe";
5
- import { glob } from "tinyglobby";
4
+ import { join, relative } from "pathe";
6
5
  import { z } from "zod";
7
6
 
8
7
  import {
@@ -10,17 +9,9 @@ import {
10
9
  ComponentOverridesError,
11
10
  } from "../core/component-overrides.ts";
12
11
  import { ConfigValidationError, loadConfig } from "../core/config.ts";
13
- import { BlumeError, locateFrontmatterKey } from "../core/diagnostics.ts";
14
- import matter from "../core/frontmatter.ts";
15
- import { createModuleLoader } from "../core/load-module.ts";
12
+ import { BlumeError } from "../core/diagnostics.ts";
16
13
  import { findComponentsFile, findConfigFile } from "../core/project.ts";
17
- import { pageMetaSchema } from "../core/schema.ts";
18
- import { baselineScanIgnore } from "../core/sources/watch.ts";
19
14
  import type { Diagnostic } from "../core/types.ts";
20
- import {
21
- DEFAULT_CONTENT_EXCLUDE,
22
- DEFAULT_CONTENT_INCLUDE,
23
- } from "../sources/filesystem.ts";
24
15
 
25
16
  /**
26
17
  * `blume upgrade`'s logic, kept out of the command module so it runs (and is
@@ -280,163 +271,6 @@ const scriptFindings = async (root: string): Promise<Diagnostic[]> => {
280
271
  });
281
272
  };
282
273
 
283
- // ---------------------------------------------------------------------------
284
- // Removed front matter fields
285
- // ---------------------------------------------------------------------------
286
-
287
- /** Where a project's local content lives, as its config names it. */
288
- interface ContentGlobs {
289
- exclude: string[];
290
- include: string[];
291
- root: string;
292
- }
293
-
294
- const globFields = {
295
- exclude: z.array(z.string()).optional(),
296
- include: z.array(z.string()).optional(),
297
- root: z.string().optional(),
298
- };
299
-
300
- /**
301
- * A filesystem source in either form a config being upgraded may hold: the
302
- * `filesystem()` descriptor, or Blume 1's `{ type: "filesystem" }` object.
303
- */
304
- const rawFilesystemSourceSchema = z.union([
305
- z
306
- .looseObject({
307
- kind: z.literal("filesystem"),
308
- options: z.looseObject(globFields).default({}),
309
- })
310
- .transform((source) => source.options),
311
- z.looseObject({ type: z.literal("filesystem"), ...globFields }),
312
- ]);
313
-
314
- /** The `content` slice of a config as written, before validation. */
315
- const rawContentSchema = z.looseObject({
316
- content: z
317
- .looseObject({ ...globFields, sources: z.array(z.unknown()).optional() })
318
- .optional(),
319
- });
320
-
321
- /**
322
- * The content roots to scan, read from the config as written rather than the
323
- * validated config: the upgrade runs on configs that don't validate yet. Its
324
- * filesystem sources when it lists any, else the `content.root` shorthand,
325
- * else the zero-config `docs` folder.
326
- */
327
- export const contentGlobs = ({
328
- content,
329
- }: z.infer<typeof rawContentSchema>): ContentGlobs[] => {
330
- const sources = (content?.sources ?? []).flatMap((source) => {
331
- const filesystem = rawFilesystemSourceSchema.safeParse(source);
332
- return filesystem.success ? [filesystem.data] : [];
333
- });
334
- return (sources.length > 0 ? sources : [content ?? {}]).map((globs) => ({
335
- exclude: globs.exclude ?? DEFAULT_CONTENT_EXCLUDE,
336
- include: globs.include ?? DEFAULT_CONTENT_INCLUDE,
337
- root: globs.root ?? "docs",
338
- }));
339
- };
340
-
341
- /** The content roots the project's config names, loaded as written. */
342
- const configContentGlobs = async (root: string): Promise<ContentGlobs[]> => {
343
- const file = findConfigFile(root);
344
- let raw: z.infer<typeof rawContentSchema> = {};
345
- if (file) {
346
- try {
347
- const parsed = rawContentSchema.safeParse(
348
- await createModuleLoader()(file)
349
- );
350
- raw = parsed.success ? parsed.data : {};
351
- } catch {
352
- // A config that won't load is already reported by the config check;
353
- // its content still gets the zero-config scan.
354
- }
355
- }
356
- return contentGlobs(raw);
357
- };
358
-
359
- const isPathKey = (segment: PropertyKey): segment is number | string =>
360
- typeof segment !== "symbol";
361
-
362
- // Zod's own wording for an unknown key; a removed field's hint replaces it.
363
- const PLAIN_UNKNOWN_KEY = "Unrecognized key";
364
-
365
- /**
366
- * The removed fields among one page's front matter issues, each at its own
367
- * line. Only issues the page schema words as a removed-field hint count: a
368
- * key a project declares through `frontmatter.extend` is unknown to the bare
369
- * schema, and any other invalid value was already an error on Blume 1.
370
- */
371
- const removedFieldFindings = (
372
- file: string,
373
- text: string,
374
- issues: readonly z.core.$ZodIssue[]
375
- ): Diagnostic[] =>
376
- issues.flatMap((issue) => {
377
- if (
378
- issue.code !== "unrecognized_keys" ||
379
- issue.message.startsWith(PLAIN_UNKNOWN_KEY)
380
- ) {
381
- return [];
382
- }
383
- const path = issue.path.filter(isPathKey);
384
- const position =
385
- locateFrontmatterKey(text, [...path, ...issue.keys.slice(0, 1)]) ??
386
- locateFrontmatterKey(text, path);
387
- return [
388
- {
389
- code: "BLUME_FRONTMATTER_INVALID",
390
- column: position?.column,
391
- file,
392
- line: position?.line,
393
- message: issue.message,
394
- severity: "error",
395
- } satisfies Diagnostic,
396
- ];
397
- });
398
-
399
- /** The removed front matter fields in one page, or none it can't parse. */
400
- const pageFindings = async (file: string): Promise<Diagnostic[]> => {
401
- const text = await readFile(file, "utf-8");
402
- let parsed: ReturnType<typeof pageMetaSchema.safeParse>;
403
- try {
404
- parsed = pageMetaSchema.safeParse(matter(text).data);
405
- } catch {
406
- // Unparseable front matter fails the build with its own diagnostic.
407
- return [];
408
- }
409
- return parsed.success
410
- ? []
411
- : removedFieldFindings(file, text, parsed.error.issues);
412
- };
413
-
414
- /**
415
- * A finding for each front matter field Blume 2 removed, across the project's
416
- * local content. A page with one fails validation and drops out of the build,
417
- * which the config and components checks alone would report as ready.
418
- */
419
- const frontmatterFindings = async (root: string): Promise<Diagnostic[]> => {
420
- const roots = await configContentGlobs(root);
421
- const matches = await Promise.all(
422
- roots.map((globs) => {
423
- const cwd = resolve(root, globs.root);
424
- return existsSync(cwd)
425
- ? glob(globs.include, {
426
- absolute: true,
427
- cwd,
428
- ignore: [...globs.exclude, ...baselineScanIgnore()],
429
- onlyFiles: true,
430
- })
431
- : [];
432
- })
433
- );
434
- // Two sources can share a folder; each page is checked once.
435
- const files = [...new Set(matches.flat())].toSorted();
436
- const findings = await Promise.all(files.map(pageFindings));
437
- return findings.flat();
438
- };
439
-
440
274
  /**
441
275
  * Run one check, turning the {@link BlumeError} it throws into its findings:
442
276
  * each config issue or `components.ts` entry on its own, or the one diagnostic
@@ -466,8 +300,8 @@ const findingsOf = async (
466
300
  * Check a project against this version of Blume: its config through the
467
301
  * loader (every invalid field, each with its line and replacement), its
468
302
  * `components.ts` through the static override planner (each entry at its
469
- * line), its pages' front matter for removed fields, and its package.json
470
- * scripts for `blume build` flags that no longer exist. Returns the failures;
303
+ * line), and its package.json scripts for `blume build` flags that no longer
304
+ * exist. Returns the failures;
471
305
  * an empty list means the project is ready.
472
306
  */
473
307
  export const collectUpgradeFindings = async (
@@ -486,7 +320,6 @@ export const collectUpgradeFindings = async (
486
320
  );
487
321
  })
488
322
  : []),
489
- ...(await frontmatterFindings(root)),
490
323
  ...(await scriptFindings(root)),
491
324
  ];
492
325
  };
@@ -1,75 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- needsPlaygroundProxy,
4
- resolveAskBackend
5
- } from "./chunk-pv29h0wf.js";
6
-
7
- // src/core/server-features.ts
8
- var serverFeatures = (config) => {
9
- const features = [];
10
- if (config.ai.assistant?.enabled && !config.ai.assistant.endpoint) {
11
- features.push("Assistant");
12
- }
13
- if (config.agents.mcp.enabled) {
14
- features.push("MCP server");
15
- }
16
- if (needsPlaygroundProxy(config)) {
17
- features.push("API playground proxy");
18
- }
19
- if (config.search.provider.mode === "server") {
20
- features.push(`Search (${config.search.provider.kind})`);
21
- }
22
- return features;
23
- };
24
-
25
- // src/cli/required-secrets.ts
26
- var checkRequiredSecrets = (config) => {
27
- const diagnostics = [];
28
- const requireSecret = (feature, env, note) => {
29
- if (process.env[env]) {
30
- return;
31
- }
32
- const noteSuffix = note ? ` (${note})` : "";
33
- diagnostics.push({
34
- code: "BLUME_MISSING_SECRET",
35
- message: `${feature} is enabled but ${env} is not set${noteSuffix}.`,
36
- severity: "warning",
37
- suggestion: `Set ${env} in .env.local for local dev, or in your host's environment for production.`
38
- });
39
- };
40
- if (config.ai.assistant?.enabled && !config.ai.assistant.endpoint) {
41
- const { provider } = config.ai.assistant;
42
- const backend = resolveAskBackend(provider);
43
- for (const env of provider.requiredSecrets) {
44
- requireSecret(`Assistant (${backend.label})`, env, backend.secretNote);
45
- }
46
- }
47
- const { provider } = config.search;
48
- for (const env of provider.requiredSecrets) {
49
- requireSecret(`Search (${provider.kind})`, env);
50
- }
51
- for (const adapter of config.analytics) {
52
- for (const env of adapter.requiredSecrets) {
53
- requireSecret(`Analytics (${adapter.kind})`, env);
54
- }
55
- }
56
- for (const source of config.content.sources) {
57
- for (const env of source.requiredSecrets) {
58
- requireSecret(`Content source (${source.kind})`, env);
59
- }
60
- }
61
- for (const adapter of config.reference) {
62
- for (const env of adapter.requiredSecrets) {
63
- requireSecret(`API reference (${adapter.kind})`, env);
64
- }
65
- }
66
- for (const env of config.deployment.requiredSecrets) {
67
- requireSecret(`Deployment (${config.deployment.kind})`, env);
68
- }
69
- return diagnostics;
70
- };
71
-
72
- export { serverFeatures, checkRequiredSecrets };
73
-
74
- //# debugId=26CFBC953FC234CC64756E2164756E21
75
- //# sourceMappingURL=chunk-364znk6q.js.map
@@ -1,11 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/core/server-features.ts", "../src/cli/required-secrets.ts"],
4
- "sourcesContent": [
5
- "import { needsPlaygroundProxy } from \"../openapi/references.ts\";\nimport type { ResolvedConfig } from \"./schema.ts\";\n\n/**\n * List the enabled features that require Astro server output. Static builds\n * fail clearly when any of these are enabled.\n */\nexport const serverFeatures = (config: ResolvedConfig): string[] => {\n const features: string[] = [];\n if (config.ai.assistant?.enabled && !config.ai.assistant.endpoint) {\n features.push(\"Assistant\");\n }\n // The hosted MCP server is a live JSON-RPC endpoint, so it needs a runtime.\n if (config.agents.mcp.enabled) {\n features.push(\"MCP server\");\n }\n // The built-in playground proxy (`playground.proxy: true` on an `openapi()`\n // or `graphql()` adapter) is a live fetch endpoint at `/_api-proxy`; an\n // external proxy URL (string) or a proxy-less playground stays fully static.\n if (needsPlaygroundProxy(config)) {\n features.push(\"API playground proxy\");\n }\n // A `server` adapter (Mixedbread) proxies queries through a secret server\n // endpoint, so it can't run on a static build.\n if (config.search.provider.mode === \"server\") {\n features.push(`Search (${config.search.provider.kind})`);\n }\n return features;\n};\n",
6
- "import { resolveAskBackend } from \"../ai/ask.ts\";\nimport type { ResolvedConfig } from \"../core/schema.ts\";\nimport type { Diagnostic } from \"../core/types.ts\";\n\n/**\n * Warn early when an enabled feature needs a secret env var that isn't set, so\n * the failure surfaces at `blume dev`/`build` instead of at the first request in\n * production. These are runtime secrets (the endpoint reads them on the server),\n * so this warns rather than hard-fails — the value may live only in the deploy\n * environment. Build-time secrets (search-index sync) already warn during sync.\n */\nexport const checkRequiredSecrets = (config: ResolvedConfig): Diagnostic[] => {\n const diagnostics: Diagnostic[] = [];\n const requireSecret = (feature: string, env: string, note?: string): void => {\n if (process.env[env]) {\n return;\n }\n const noteSuffix = note ? ` (${note})` : \"\";\n diagnostics.push({\n code: \"BLUME_MISSING_SECRET\",\n message: `${feature} is enabled but ${env} is not set${noteSuffix}.`,\n severity: \"warning\",\n suggestion: `Set ${env} in .env.local for local dev, or in your host's environment for production.`,\n });\n };\n\n if (config.ai.assistant?.enabled && !config.ai.assistant.endpoint) {\n // The adapter descriptor names the env vars its route reads.\n const { provider } = config.ai.assistant;\n const backend = resolveAskBackend(provider);\n for (const env of provider.requiredSecrets) {\n requireSecret(`Assistant (${backend.label})`, env, backend.secretNote);\n }\n }\n\n // Each search adapter declares the secrets its generated runtime reads.\n const { provider } = config.search;\n for (const env of provider.requiredSecrets) {\n requireSecret(`Search (${provider.kind})`, env);\n }\n\n // Adapters name their own secrets; the built-in analytics adapters ship\n // public tokens in the page and declare none.\n for (const adapter of config.analytics) {\n for (const env of adapter.requiredSecrets) {\n requireSecret(`Analytics (${adapter.kind})`, env);\n }\n }\n\n // Each content source adapter declares the env vars its fetch reads.\n for (const source of config.content.sources) {\n for (const env of source.requiredSecrets) {\n requireSecret(`Content source (${source.kind})`, env);\n }\n }\n\n // Adapters name their own secrets; the built-in reference adapters read\n // public specs and declare none.\n for (const adapter of config.reference) {\n for (const env of adapter.requiredSecrets) {\n requireSecret(`API reference (${adapter.kind})`, env);\n }\n }\n\n // The deployment adapter names its own secrets; the built-in host adapters\n // read platform-injected env and declare none.\n for (const env of config.deployment.requiredSecrets) {\n requireSecret(`Deployment (${config.deployment.kind})`, env);\n }\n\n return diagnostics;\n};\n"
7
- ],
8
- "mappings": ";;;;;;;AAOO,IAAM,iBAAiB,CAAC,WAAqC;AAAA,EAClE,MAAM,WAAqB,CAAC;AAAA,EAC5B,IAAI,OAAO,GAAG,WAAW,WAAW,CAAC,OAAO,GAAG,UAAU,UAAU;AAAA,IACjE,SAAS,KAAK,WAAW;AAAA,EAC3B;AAAA,EAEA,IAAI,OAAO,OAAO,IAAI,SAAS;AAAA,IAC7B,SAAS,KAAK,YAAY;AAAA,EAC5B;AAAA,EAIA,IAAI,qBAAqB,MAAM,GAAG;AAAA,IAChC,SAAS,KAAK,sBAAsB;AAAA,EACtC;AAAA,EAGA,IAAI,OAAO,OAAO,SAAS,SAAS,UAAU;AAAA,IAC5C,SAAS,KAAK,WAAW,OAAO,OAAO,SAAS,OAAO;AAAA,EACzD;AAAA,EACA,OAAO;AAAA;;;AChBF,IAAM,uBAAuB,CAAC,WAAyC;AAAA,EAC5E,MAAM,cAA4B,CAAC;AAAA,EACnC,MAAM,gBAAgB,CAAC,SAAiB,KAAa,SAAwB;AAAA,IAC3E,IAAI,QAAQ,IAAI,MAAM;AAAA,MACpB;AAAA,IACF;AAAA,IACA,MAAM,aAAa,OAAO,KAAK,UAAU;AAAA,IACzC,YAAY,KAAK;AAAA,MACf,MAAM;AAAA,MACN,SAAS,GAAG,0BAA0B,iBAAiB;AAAA,MACvD,UAAU;AAAA,MACV,YAAY,OAAO;AAAA,IACrB,CAAC;AAAA;AAAA,EAGH,IAAI,OAAO,GAAG,WAAW,WAAW,CAAC,OAAO,GAAG,UAAU,UAAU;AAAA,IAEjE,QAAQ,aAAa,OAAO,GAAG;AAAA,IAC/B,MAAM,UAAU,kBAAkB,QAAQ;AAAA,IAC1C,WAAW,OAAO,SAAS,iBAAiB;AAAA,MAC1C,cAAc,cAAc,QAAQ,UAAU,KAAK,QAAQ,UAAU;AAAA,IACvE;AAAA,EACF;AAAA,EAGA,QAAQ,aAAa,OAAO;AAAA,EAC5B,WAAW,OAAO,SAAS,iBAAiB;AAAA,IAC1C,cAAc,WAAW,SAAS,SAAS,GAAG;AAAA,EAChD;AAAA,EAIA,WAAW,WAAW,OAAO,WAAW;AAAA,IACtC,WAAW,OAAO,QAAQ,iBAAiB;AAAA,MACzC,cAAc,cAAc,QAAQ,SAAS,GAAG;AAAA,IAClD;AAAA,EACF;AAAA,EAGA,WAAW,UAAU,OAAO,QAAQ,SAAS;AAAA,IAC3C,WAAW,OAAO,OAAO,iBAAiB;AAAA,MACxC,cAAc,mBAAmB,OAAO,SAAS,GAAG;AAAA,IACtD;AAAA,EACF;AAAA,EAIA,WAAW,WAAW,OAAO,WAAW;AAAA,IACtC,WAAW,OAAO,QAAQ,iBAAiB;AAAA,MACzC,cAAc,kBAAkB,QAAQ,SAAS,GAAG;AAAA,IACtD;AAAA,EACF;AAAA,EAIA,WAAW,OAAO,OAAO,WAAW,iBAAiB;AAAA,IACnD,cAAc,eAAe,OAAO,WAAW,SAAS,GAAG;AAAA,EAC7D;AAAA,EAEA,OAAO;AAAA;",
9
- "debugId": "26CFBC953FC234CC64756E2164756E21",
10
- "names": []
11
- }