blume 2.0.3 → 2.1.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 (607) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +142 -0
  3. package/README.md +1 -1
  4. package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
  5. package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
  6. package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
  7. package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
  8. package/dist/cli/chunk-150jk7km.js +52 -0
  9. package/dist/cli/chunk-150jk7km.js.map +10 -0
  10. package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
  11. package/dist/cli/chunk-313vnn40.js.map +10 -0
  12. package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
  13. package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
  14. package/dist/cli/chunk-3x6x3pph.js.map +10 -0
  15. package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
  16. package/dist/cli/chunk-42t4jxdx.js.map +12 -0
  17. package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
  18. package/dist/cli/chunk-54ztw1nj.js.map +10 -0
  19. package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
  20. package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
  21. package/dist/cli/chunk-66w9j7p6.js +322 -0
  22. package/dist/cli/chunk-66w9j7p6.js.map +14 -0
  23. package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
  24. package/dist/cli/chunk-7ppf1rva.js.map +10 -0
  25. package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
  26. package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
  27. package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
  28. package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
  29. package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
  30. package/dist/cli/chunk-cfyg47zg.js.map +10 -0
  31. package/dist/cli/chunk-cm89scdv.js +443 -0
  32. package/dist/cli/chunk-cm89scdv.js.map +11 -0
  33. package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
  34. package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
  35. package/dist/cli/chunk-e6atmn4h.js.map +36 -0
  36. package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
  37. package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
  38. package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
  39. package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
  40. package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
  41. package/dist/cli/chunk-ehweg4fr.js.map +218 -0
  42. package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
  43. package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
  44. package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
  45. package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
  46. package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
  47. package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
  48. package/dist/cli/chunk-gb420vvz.js.map +17 -0
  49. package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
  50. package/dist/cli/chunk-hebn0tpx.js.map +14 -0
  51. package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
  52. package/dist/cli/chunk-htrwgabr.js.map +15 -0
  53. package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
  54. package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
  55. package/dist/cli/chunk-j134vrp2.js +65 -0
  56. package/dist/cli/chunk-j134vrp2.js.map +10 -0
  57. package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
  58. package/dist/cli/chunk-kwrg63tm.js +31 -0
  59. package/dist/cli/chunk-kwrg63tm.js.map +10 -0
  60. package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
  61. package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
  62. package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
  63. package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
  64. package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
  65. package/dist/cli/chunk-ncj7w596.js.map +35 -0
  66. package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
  67. package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
  68. package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
  69. package/dist/cli/chunk-nrns10mj.js.map +10 -0
  70. package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
  71. package/dist/cli/chunk-t2m5j4pr.js +104 -0
  72. package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
  73. package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
  74. package/dist/cli/chunk-tphac74f.js +126 -0
  75. package/dist/cli/chunk-tphac74f.js.map +11 -0
  76. package/dist/cli/chunk-w1r4vase.js +18 -0
  77. package/dist/cli/chunk-w1r4vase.js.map +10 -0
  78. package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
  79. package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
  80. package/dist/cli/index.js +31 -20
  81. package/dist/cli/index.js.map +5 -5
  82. package/dist/types/ai/agent-surface.d.ts +8 -7
  83. package/dist/types/ai/ai-catalog.d.ts +7 -0
  84. package/dist/types/ai/ask-context.d.ts +26 -0
  85. package/dist/types/ai/ask.d.ts +271 -58
  86. package/dist/types/ai/component-markdown.d.ts +2 -0
  87. package/dist/types/ai/index.d.ts +2 -2
  88. package/dist/types/ai/openapi-components.d.ts +4 -1
  89. package/dist/types/ai/site-skill.d.ts +26 -0
  90. package/dist/types/ai/skills.d.ts +16 -0
  91. package/dist/types/astro/integration.d.ts +9 -0
  92. package/dist/types/astro/markdown-negotiation.d.ts +3 -0
  93. package/dist/types/astro/pages.d.ts +10 -0
  94. package/dist/types/captcha/hcaptcha.d.ts +27 -0
  95. package/dist/types/captcha/index.d.ts +28 -0
  96. package/dist/types/captcha/schema.d.ts +29 -0
  97. package/dist/types/captcha/turnstile.d.ts +28 -0
  98. package/dist/types/cli/init/scaffold.d.ts +1 -1
  99. package/dist/types/components/content/api-field.d.ts +62 -0
  100. package/dist/types/components/content/api-page.d.ts +100 -0
  101. package/dist/types/components/layout/nav-utils.d.ts +26 -0
  102. package/dist/types/components/openapi/code-samples.d.ts +29 -0
  103. package/dist/types/components/openapi/helpers.d.ts +158 -0
  104. package/dist/types/components/openapi/security.d.ts +95 -0
  105. package/dist/types/components/openapi/snippets.d.ts +60 -0
  106. package/dist/types/consent/ethyca.d.ts +48 -0
  107. package/dist/types/consent/index.d.ts +37 -0
  108. package/dist/types/consent/native.d.ts +28 -0
  109. package/dist/types/consent/osano.d.ts +42 -0
  110. package/dist/types/consent/schema.d.ts +110 -0
  111. package/dist/types/core/changelog-index.d.ts +8 -0
  112. package/dist/types/core/config-input.d.ts +217 -23
  113. package/dist/types/core/data.d.ts +53 -4
  114. package/dist/types/core/footer.d.ts +8 -0
  115. package/dist/types/core/i18n-ui.d.ts +88 -0
  116. package/dist/types/core/includes.d.ts +8 -2
  117. package/dist/types/core/links.d.ts +8 -0
  118. package/dist/types/core/localizable.d.ts +7 -0
  119. package/dist/types/core/page-modes.d.ts +29 -0
  120. package/dist/types/core/probe.d.ts +2 -0
  121. package/dist/types/core/project-graph.d.ts +6 -0
  122. package/dist/types/core/redirect-patterns.d.ts +152 -0
  123. package/dist/types/core/related.d.ts +40 -0
  124. package/dist/types/core/schema.d.ts +670 -56
  125. package/dist/types/core/sources/cache.d.ts +3 -0
  126. package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
  127. package/dist/types/core/sources/contentful.d.ts +17 -1
  128. package/dist/types/core/sources/lexical.d.ts +5 -0
  129. package/dist/types/core/sources/normalize.d.ts +20 -1
  130. package/dist/types/core/sources/read.d.ts +5 -0
  131. package/dist/types/core/sources/remote.d.ts +37 -10
  132. package/dist/types/core/sources/sanity.d.ts +1 -1
  133. package/dist/types/core/types.d.ts +18 -1
  134. package/dist/types/core/variables.d.ts +42 -0
  135. package/dist/types/deploy/adapter-output.d.ts +2 -1
  136. package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
  137. package/dist/types/deploy/adapters/node.d.ts +58 -23
  138. package/dist/types/deploy/adapters/registry.d.ts +10 -0
  139. package/dist/types/deploy/adapters/types.d.ts +3 -2
  140. package/dist/types/deploy/node-headers.d.ts +13 -2
  141. package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
  142. package/dist/types/deploy/platforms/netlify.d.ts +7 -0
  143. package/dist/types/deploy/platforms/node.d.ts +3 -1
  144. package/dist/types/deploy/platforms/types.d.ts +18 -7
  145. package/dist/types/deploy/platforms/vercel.d.ts +26 -1
  146. package/dist/types/deploy/redirects.d.ts +55 -11
  147. package/dist/types/deploy/sitemap.d.ts +2 -1
  148. package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
  149. package/dist/types/markdown/code-title.d.ts +17 -0
  150. package/dist/types/markdown/features.d.ts +3 -2
  151. package/dist/types/narration/build.d.ts +70 -0
  152. package/dist/types/narration/provider.d.ts +26 -0
  153. package/dist/types/narration/script.d.ts +154 -0
  154. package/dist/types/openapi/checks.d.ts +27 -0
  155. package/dist/types/openapi/graphql.d.ts +6 -0
  156. package/dist/types/openapi/model.d.ts +27 -10
  157. package/dist/types/openapi/overlay.d.ts +54 -0
  158. package/dist/types/openapi/parse.d.ts +16 -0
  159. package/dist/types/openapi/references.d.ts +30 -4
  160. package/dist/types/ratelimit/cloudflare.d.ts +39 -0
  161. package/dist/types/ratelimit/index.d.ts +27 -0
  162. package/dist/types/ratelimit/memory.d.ts +36 -0
  163. package/dist/types/ratelimit/schema.d.ts +119 -0
  164. package/dist/types/ratelimit/upstash.d.ts +46 -0
  165. package/dist/types/ratelimit/wrangler.d.ts +23 -0
  166. package/dist/types/reference/asyncapi.d.ts +10 -10
  167. package/dist/types/reference/graphql.d.ts +89 -11
  168. package/dist/types/reference/index.d.ts +1 -1
  169. package/dist/types/reference/openapi.d.ts +33 -12
  170. package/dist/types/reference/options.d.ts +82 -6
  171. package/dist/types/reference/scalar.d.ts +13 -0
  172. package/dist/types/reference/schema.d.ts +144 -36
  173. package/dist/types/search/adapters/registry.d.ts +3 -0
  174. package/dist/types/search/adapters/typesense.d.ts +14 -4
  175. package/dist/types/search/build.d.ts +3 -1
  176. package/dist/types/search/documents.d.ts +12 -1
  177. package/dist/types/search/orama-index.d.ts +13 -9
  178. package/dist/types/search/sync/algolia.d.ts +5 -2
  179. package/dist/types/search/sync/index.d.ts +3 -1
  180. package/dist/types/search/sync/typesense.d.ts +11 -7
  181. package/dist/types/seo/metatags.d.ts +20 -0
  182. package/dist/types/sources/contentful.d.ts +16 -0
  183. package/dist/types/sources/github-releases.d.ts +8 -1
  184. package/dist/types/sources/payload.d.ts +2 -0
  185. package/dist/types/sources/registry.d.ts +54 -0
  186. package/dist/types/sources/shared.d.ts +3 -0
  187. package/dist/types/sources/strapi.d.ts +2 -0
  188. package/docs/01-quickstart.mdx +4 -2
  189. package/docs/02-deployment.mdx +71 -17
  190. package/docs/03-upgrading.mdx +4 -4
  191. package/docs/04-migrating.mdx +1 -1
  192. package/docs/advanced/changelog.mdx +13 -2
  193. package/docs/advanced/skills.mdx +15 -1
  194. package/docs/cli/audit.mdx +51 -8
  195. package/docs/cli/doctor.mdx +5 -1
  196. package/docs/cli/evals.mdx +4 -4
  197. package/docs/cli/index.mdx +1 -0
  198. package/docs/cli/translate.mdx +1 -0
  199. package/docs/cli/validate.mdx +4 -3
  200. package/docs/configuration/analytics.mdx +3 -1
  201. package/docs/configuration/assistant.mdx +194 -38
  202. package/docs/configuration/consent.mdx +100 -0
  203. package/docs/configuration/customization.mdx +8 -6
  204. package/docs/configuration/export.mdx +5 -3
  205. package/docs/configuration/index.mdx +64 -5
  206. package/docs/configuration/meta.ts +3 -0
  207. package/docs/configuration/narration.mdx +119 -0
  208. package/docs/configuration/rate-limiting.mdx +90 -0
  209. package/docs/configuration/search.mdx +63 -12
  210. package/docs/configuration/theming.mdx +3 -1
  211. package/docs/content/components.mdx +108 -2
  212. package/docs/content/frontmatter.mdx +80 -2
  213. package/docs/content/i18n.mdx +39 -4
  214. package/docs/content/includes.mdx +16 -0
  215. package/docs/content/meta.mdx +1 -0
  216. package/docs/content/meta.ts +1 -0
  217. package/docs/content/navigation.mdx +32 -10
  218. package/docs/content/sources/contentful.mdx +35 -0
  219. package/docs/content/sources/custom.mdx +43 -0
  220. package/docs/content/sources/github-releases.mdx +39 -0
  221. package/docs/content/sources/index.mdx +91 -0
  222. package/docs/content/sources/meta.ts +16 -0
  223. package/docs/content/sources/notion.mdx +32 -0
  224. package/docs/content/sources/obsidian.mdx +37 -0
  225. package/docs/content/sources/payload.mdx +31 -0
  226. package/docs/content/sources/remote-mdx.mdx +44 -0
  227. package/docs/content/sources/sanity.mdx +29 -0
  228. package/docs/content/sources/strapi.mdx +32 -0
  229. package/docs/content/syntax.mdx +69 -4
  230. package/docs/content/variables.mdx +41 -0
  231. package/docs/discoverability/agent-discovery.mdx +29 -2
  232. package/docs/discoverability/index.mdx +2 -2
  233. package/docs/discoverability/json-api.mdx +2 -0
  234. package/docs/discoverability/llms-txt.mdx +2 -2
  235. package/docs/discoverability/markdown.mdx +3 -1
  236. package/docs/discoverability/mcp.mdx +4 -0
  237. package/docs/discoverability/metadata.mdx +17 -0
  238. package/docs/discoverability/sitemap-and-robots.mdx +1 -1
  239. package/docs/references/api-pages.mdx +74 -0
  240. package/docs/references/asyncapi.mdx +4 -2
  241. package/docs/references/graphql.mdx +14 -2
  242. package/docs/references/meta.ts +1 -1
  243. package/docs/references/openapi.mdx +148 -7
  244. package/docs/references/scalar.mdx +3 -1
  245. package/package.json +43 -8
  246. package/skills/blume/SKILL.md +3 -0
  247. package/skills/blume-migrate/SKILL.md +6 -6
  248. package/skills/blume-migrate/references/docusaurus.md +7 -7
  249. package/skills/blume-migrate/references/fumadocs.md +17 -13
  250. package/skills/blume-migrate/references/mintlify.md +37 -19
  251. package/skills/blume-migrate/references/nextra.md +10 -7
  252. package/skills/blume-migrate/references/starlight.md +11 -8
  253. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
  254. package/skills/blume-write-skill/SKILL.md +82 -0
  255. package/src/ai/agent-readability.ts +2 -1
  256. package/src/ai/agent-surface.ts +9 -7
  257. package/src/ai/ai-catalog.ts +6 -3
  258. package/src/ai/ask-context.ts +103 -20
  259. package/src/ai/ask-data.ts +6 -0
  260. package/src/ai/ask-limits.ts +13 -0
  261. package/src/ai/ask-tools.ts +142 -0
  262. package/src/ai/ask.ts +354 -76
  263. package/src/ai/changelog-markdown.ts +11 -6
  264. package/src/ai/component-markdown.ts +76 -1
  265. package/src/ai/cors.ts +14 -3
  266. package/src/ai/index.ts +12 -0
  267. package/src/ai/llms.ts +6 -2
  268. package/src/ai/markdown.ts +2 -1
  269. package/src/ai/mcp/data.ts +6 -0
  270. package/src/ai/mcp/query.ts +14 -6
  271. package/src/ai/openapi-components.ts +36 -6
  272. package/src/ai/relative-links.ts +4 -38
  273. package/src/ai/site-skill.ts +274 -0
  274. package/src/ai/skills.ts +35 -2
  275. package/src/ai/write-skill.ts +97 -0
  276. package/src/astro/generate.ts +210 -66
  277. package/src/astro/index.ts +1 -0
  278. package/src/astro/integration.ts +42 -4
  279. package/src/astro/markdown-negotiation.ts +3 -0
  280. package/src/astro/module-types.ts +9 -1
  281. package/src/astro/pages.ts +23 -0
  282. package/src/astro/templates.ts +406 -108
  283. package/src/astro/variables.ts +31 -0
  284. package/src/audit/catalog.ts +38 -3
  285. package/src/audit/checks/contrast.ts +183 -0
  286. package/src/audit/checks/i18n.ts +2 -3
  287. package/src/audit/checks/indexability.ts +2 -3
  288. package/src/audit/checks/links.ts +19 -13
  289. package/src/audit/checks/network.ts +110 -6
  290. package/src/audit/checks/redirects.ts +6 -4
  291. package/src/audit/checks/robots.ts +58 -2
  292. package/src/audit/checks/sitemap.ts +2 -3
  293. package/src/audit/redirects.ts +46 -15
  294. package/src/audit/run.ts +5 -0
  295. package/src/audit/types.ts +4 -1
  296. package/src/audit/url.ts +14 -5
  297. package/src/blume-modules.d.ts +12 -1
  298. package/src/captcha/client.ts +152 -0
  299. package/src/captcha/hcaptcha.ts +36 -0
  300. package/src/captcha/index.ts +28 -0
  301. package/src/captcha/schema.ts +32 -0
  302. package/src/captcha/turnstile.ts +38 -0
  303. package/src/captcha/verify.ts +71 -0
  304. package/src/cli/args.ts +51 -0
  305. package/src/cli/build-failure.ts +23 -0
  306. package/src/cli/command-meta.ts +5 -0
  307. package/src/cli/commands/audit.ts +10 -1
  308. package/src/cli/commands/dev.ts +18 -2
  309. package/src/cli/commands/doctor.ts +67 -28
  310. package/src/cli/commands/eval.ts +36 -4
  311. package/src/cli/commands/init.ts +6 -4
  312. package/src/cli/commands/skill.ts +96 -0
  313. package/src/cli/commands/validate.ts +10 -1
  314. package/src/cli/index.ts +5 -0
  315. package/src/cli/init/scaffold.ts +3 -3
  316. package/src/cli/prepare.ts +6 -3
  317. package/src/cli/required-secrets.ts +72 -30
  318. package/src/components/BlumePage.astro +2 -0
  319. package/src/components/content/ApiEndpoint.astro +18 -0
  320. package/src/components/content/ApiField.astro +79 -0
  321. package/src/components/content/ApiPlayground.astro +66 -0
  322. package/src/components/content/ApiRail.astro +19 -0
  323. package/src/components/content/Color.astro +1 -0
  324. package/src/components/content/FileTree.astro +1 -0
  325. package/src/components/content/GithubInfo.astro +1 -0
  326. package/src/components/content/Panel.astro +1 -0
  327. package/src/components/content/ParamField.astro +25 -0
  328. package/src/components/content/RequestExample.astro +17 -0
  329. package/src/components/content/ResponseExample.astro +17 -0
  330. package/src/components/content/ResponseField.astro +32 -0
  331. package/src/components/content/Step.astro +1 -0
  332. package/src/components/content/Tile.astro +1 -0
  333. package/src/components/content/Tooltip.astro +1 -0
  334. package/src/components/content/Tree.astro +1 -0
  335. package/src/components/content/TypeTable.astro +4 -1
  336. package/src/components/content/View.astro +21 -0
  337. package/src/components/content/ViewSwitcher.astro +168 -0
  338. package/src/components/content/api-field.ts +103 -0
  339. package/src/components/content/api-page.ts +248 -0
  340. package/src/components/content/mermaid-element.ts +15 -1
  341. package/src/components/content/view-switcher.ts +71 -0
  342. package/src/components/index.ts +2 -0
  343. package/src/components/islands/Assistant.astro +10 -1
  344. package/src/components/islands/assistant.tsx +104 -14
  345. package/src/components/islands/code-question.ts +62 -0
  346. package/src/components/islands/hooks.ts +136 -21
  347. package/src/components/islands/support-link.ts +68 -0
  348. package/src/components/layout/Analytics.astro +11 -2
  349. package/src/components/layout/Banner.astro +14 -10
  350. package/src/components/layout/Breadcrumbs.astro +6 -2
  351. package/src/components/layout/ConsentBanner.astro +62 -0
  352. package/src/components/layout/ConsentHead.astro +38 -0
  353. package/src/components/layout/Directory.astro +94 -0
  354. package/src/components/layout/DrawerSwitchers.astro +51 -0
  355. package/src/components/layout/Empty.astro +2 -2
  356. package/src/components/layout/Header.astro +122 -80
  357. package/src/components/layout/LanguageSwitcher.astro +48 -15
  358. package/src/components/layout/NarrationPlayer.astro +1085 -0
  359. package/src/components/layout/NavSelector.astro +33 -7
  360. package/src/components/layout/PageActions.astro +139 -24
  361. package/src/components/layout/PageFeedback.astro +54 -49
  362. package/src/components/layout/PageLayout.astro +71 -3
  363. package/src/components/layout/ReferenceLayout.astro +17 -6
  364. package/src/components/layout/RelatedPages.astro +42 -0
  365. package/src/components/layout/RootLayout.astro +318 -47
  366. package/src/components/layout/Search.astro +47 -19
  367. package/src/components/layout/SiteFooter.astro +124 -0
  368. package/src/components/layout/SiteMetatags.astro +16 -0
  369. package/src/components/layout/TableOfContents.astro +24 -17
  370. package/src/components/layout/consent/native.ts +79 -0
  371. package/src/components/layout/consent/types.ts +37 -0
  372. package/src/components/layout/footer-links.ts +53 -0
  373. package/src/components/layout/footer-socials.ts +87 -0
  374. package/src/components/layout/head-scripts.ts +6 -1
  375. package/src/components/layout/locale-redirect.ts +107 -0
  376. package/src/components/layout/nav-utils.ts +83 -0
  377. package/src/components/layout/page-feedback.ts +96 -0
  378. package/src/components/layout/search/algolia.ts +10 -1
  379. package/src/components/layout/search/analytics.ts +126 -0
  380. package/src/components/layout/search/endpoint.ts +48 -5
  381. package/src/components/layout/search/flexsearch.ts +17 -5
  382. package/src/components/layout/search/orama-cloud.ts +26 -14
  383. package/src/components/layout/search/pagefind.ts +114 -5
  384. package/src/components/layout/search/types.ts +32 -0
  385. package/src/components/layout/search/typesense.ts +19 -3
  386. package/src/components/openapi/AsyncApiOperation.astro +14 -7
  387. package/src/components/openapi/Authorization.astro +10 -0
  388. package/src/components/openapi/GraphqlOperation.astro +5 -0
  389. package/src/components/openapi/Operation.astro +184 -13
  390. package/src/components/openapi/ParametersTable.astro +8 -4
  391. package/src/components/openapi/Playground.astro +7 -1
  392. package/src/components/openapi/RequestBody.astro +24 -5
  393. package/src/components/openapi/RequestPanel.astro +59 -7
  394. package/src/components/openapi/Responses.astro +7 -4
  395. package/src/components/openapi/SchemaTable.astro +15 -3
  396. package/src/components/openapi/async-snippets.ts +65 -9
  397. package/src/components/openapi/async.ts +123 -29
  398. package/src/components/openapi/code-samples.ts +97 -0
  399. package/src/components/openapi/graphql-helpers.ts +35 -12
  400. package/src/components/openapi/helpers.ts +36 -2
  401. package/src/components/openapi/message-model.ts +54 -11
  402. package/src/components/openapi/message.ts +14 -4
  403. package/src/components/openapi/operation-model.ts +16 -7
  404. package/src/components/openapi/playground-client.ts +24 -5
  405. package/src/components/openapi/playground-schema.ts +1 -1
  406. package/src/components/openapi/schema-tree.ts +44 -14
  407. package/src/components/openapi/security.ts +16 -3
  408. package/src/components/openapi/snippets.ts +873 -10
  409. package/src/components/openapi/validate-json.ts +4 -3
  410. package/src/components/props.ts +6 -0
  411. package/src/consent/client.ts +95 -0
  412. package/src/consent/clients.ts +19 -0
  413. package/src/consent/ethyca.ts +71 -0
  414. package/src/consent/head.ts +24 -0
  415. package/src/consent/index.ts +37 -0
  416. package/src/consent/init.ts +29 -0
  417. package/src/consent/native.ts +36 -0
  418. package/src/consent/osano.ts +59 -0
  419. package/src/consent/schema.ts +30 -0
  420. package/src/core/builtin-tags.ts +5 -0
  421. package/src/core/changelog-index.ts +31 -1
  422. package/src/core/client-address.ts +19 -0
  423. package/src/core/component-diagnostics.ts +53 -0
  424. package/src/core/component-overrides.ts +32 -0
  425. package/src/core/config-input.ts +225 -23
  426. package/src/core/data.ts +46 -4
  427. package/src/core/diagnostics.ts +8 -2
  428. package/src/core/footer.ts +26 -0
  429. package/src/core/graph.ts +39 -36
  430. package/src/core/i18n-ui.ts +84 -2
  431. package/src/core/includes.ts +21 -4
  432. package/src/core/links.ts +63 -19
  433. package/src/core/localizable.ts +26 -0
  434. package/src/core/navigation.ts +43 -12
  435. package/src/core/page-modes.ts +56 -0
  436. package/src/core/probe.ts +26 -6
  437. package/src/core/project-graph.ts +163 -16
  438. package/src/core/redirect-patterns.ts +520 -0
  439. package/src/core/related.ts +131 -0
  440. package/src/core/schema.ts +339 -66
  441. package/src/core/sources/cache.ts +6 -0
  442. package/src/core/sources/contentful-rich-text.ts +29 -6
  443. package/src/core/sources/contentful.ts +135 -25
  444. package/src/core/sources/filesystem.ts +26 -4
  445. package/src/core/sources/github-releases.ts +12 -1
  446. package/src/core/sources/lexical.ts +15 -10
  447. package/src/core/sources/mdx-remote.ts +62 -10
  448. package/src/core/sources/normalize.ts +228 -41
  449. package/src/core/sources/notion.ts +7 -1
  450. package/src/core/sources/obsidian.ts +16 -3
  451. package/src/core/sources/payload.ts +38 -15
  452. package/src/core/sources/read.ts +8 -3
  453. package/src/core/sources/remote.ts +72 -15
  454. package/src/core/sources/resolve.ts +11 -1
  455. package/src/core/sources/sanity.ts +43 -25
  456. package/src/core/sources/strapi.ts +2 -2
  457. package/src/core/types.ts +19 -1
  458. package/src/core/ui-packs/ar.ts +44 -0
  459. package/src/core/ui-packs/bg.ts +46 -0
  460. package/src/core/ui-packs/bn.ts +44 -0
  461. package/src/core/ui-packs/ca.ts +47 -0
  462. package/src/core/ui-packs/cs.ts +45 -0
  463. package/src/core/ui-packs/da.ts +46 -0
  464. package/src/core/ui-packs/de.ts +47 -0
  465. package/src/core/ui-packs/el.ts +46 -0
  466. package/src/core/ui-packs/es.ts +47 -0
  467. package/src/core/ui-packs/fa.ts +46 -0
  468. package/src/core/ui-packs/fi.ts +46 -0
  469. package/src/core/ui-packs/fr.ts +47 -0
  470. package/src/core/ui-packs/he.ts +44 -0
  471. package/src/core/ui-packs/hi.ts +45 -0
  472. package/src/core/ui-packs/hr.ts +46 -0
  473. package/src/core/ui-packs/hu.ts +45 -0
  474. package/src/core/ui-packs/id.ts +46 -0
  475. package/src/core/ui-packs/it.ts +46 -0
  476. package/src/core/ui-packs/ja.ts +46 -0
  477. package/src/core/ui-packs/ko.ts +45 -0
  478. package/src/core/ui-packs/nl.ts +47 -0
  479. package/src/core/ui-packs/no.ts +45 -0
  480. package/src/core/ui-packs/pl.ts +46 -0
  481. package/src/core/ui-packs/pt-br.ts +47 -0
  482. package/src/core/ui-packs/pt.ts +46 -0
  483. package/src/core/ui-packs/ro.ts +46 -0
  484. package/src/core/ui-packs/ru.ts +46 -0
  485. package/src/core/ui-packs/sk.ts +45 -0
  486. package/src/core/ui-packs/sr.ts +46 -0
  487. package/src/core/ui-packs/sv.ts +45 -0
  488. package/src/core/ui-packs/th.ts +44 -0
  489. package/src/core/ui-packs/tr.ts +46 -0
  490. package/src/core/ui-packs/uk.ts +46 -0
  491. package/src/core/ui-packs/vi.ts +46 -0
  492. package/src/core/ui-packs/zh-tw.ts +44 -0
  493. package/src/core/ui-packs/zh.ts +44 -0
  494. package/src/core/variables.ts +103 -0
  495. package/src/deploy/adapter-output.ts +7 -2
  496. package/src/deploy/adapters/cloudflare.ts +7 -5
  497. package/src/deploy/adapters/node.ts +47 -9
  498. package/src/deploy/adapters/types.ts +7 -3
  499. package/src/deploy/artifacts.ts +79 -9
  500. package/src/deploy/cloudflare-negotiation.ts +35 -5
  501. package/src/deploy/headers.ts +2 -1
  502. package/src/deploy/node-headers.ts +63 -9
  503. package/src/deploy/platforms/cloudflare.ts +45 -9
  504. package/src/deploy/platforms/netlify.ts +35 -2
  505. package/src/deploy/platforms/node.ts +12 -2
  506. package/src/deploy/platforms/types.ts +21 -7
  507. package/src/deploy/platforms/vercel.ts +149 -17
  508. package/src/deploy/redirects.ts +151 -24
  509. package/src/deploy/rss.ts +3 -1
  510. package/src/deploy/sitemap.ts +39 -5
  511. package/src/deploy/vercel-negotiation.ts +326 -102
  512. package/src/eval/agents.ts +18 -1
  513. package/src/eval/prompts.ts +6 -3
  514. package/src/eval/report.ts +34 -13
  515. package/src/eval/run.ts +5 -0
  516. package/src/markdown/api-rail.ts +259 -0
  517. package/src/markdown/code-title.ts +35 -9
  518. package/src/markdown/features.ts +3 -2
  519. package/src/markdown/fence-meta.ts +2 -0
  520. package/src/markdown/include.ts +11 -1
  521. package/src/markdown/index.ts +28 -5
  522. package/src/markdown/math.ts +4 -4
  523. package/src/markdown/relative-links.ts +3 -2
  524. package/src/markdown/variables.ts +56 -0
  525. package/src/markdown/views.ts +82 -0
  526. package/src/narration/build.ts +412 -0
  527. package/src/narration/player.ts +249 -0
  528. package/src/narration/provider.ts +29 -0
  529. package/src/narration/script.ts +592 -0
  530. package/src/og/card.ts +7 -6
  531. package/src/openapi/checks.ts +273 -0
  532. package/src/openapi/graphql-build.ts +21 -0
  533. package/src/openapi/graphql.ts +11 -0
  534. package/src/openapi/model.ts +72 -27
  535. package/src/openapi/overlay.ts +256 -0
  536. package/src/openapi/parse.ts +182 -4
  537. package/src/openapi/references.ts +64 -8
  538. package/src/openapi/render-mdx.ts +5 -1
  539. package/src/openapi/scalar.ts +40 -6
  540. package/src/openapi/source.ts +40 -15
  541. package/src/ratelimit/cloudflare.ts +54 -0
  542. package/src/ratelimit/index.ts +30 -0
  543. package/src/ratelimit/memory.ts +45 -0
  544. package/src/ratelimit/runtime.ts +247 -0
  545. package/src/ratelimit/schema.ts +28 -0
  546. package/src/ratelimit/upstash.ts +60 -0
  547. package/src/ratelimit/wrangler.ts +70 -0
  548. package/src/reference/asyncapi.ts +2 -2
  549. package/src/reference/graphql.ts +20 -3
  550. package/src/reference/index.ts +1 -0
  551. package/src/reference/openapi.ts +21 -7
  552. package/src/reference/options.ts +80 -8
  553. package/src/reference/scalar.ts +33 -8
  554. package/src/registry/eject.ts +23 -5
  555. package/src/registry/registry.ts +7 -0
  556. package/src/search/adapters/locale-scope.ts +30 -0
  557. package/src/search/adapters/typesense.ts +14 -4
  558. package/src/search/build.ts +21 -3
  559. package/src/search/documents.ts +26 -2
  560. package/src/search/orama-index.ts +191 -34
  561. package/src/search/pagefind-ranking.ts +39 -0
  562. package/src/search/source-pages.ts +29 -0
  563. package/src/search/sync/algolia.ts +111 -10
  564. package/src/search/sync/index.ts +52 -13
  565. package/src/search/sync/orama-cloud.ts +3 -0
  566. package/src/search/sync/typesense.ts +76 -26
  567. package/src/seo/metatags.ts +67 -0
  568. package/src/sources/contentful.ts +12 -0
  569. package/src/sources/github-releases.ts +7 -1
  570. package/src/sources/shared.ts +3 -0
  571. package/src/theme/chrome-icons.ts +1 -0
  572. package/src/theme/color.ts +500 -0
  573. package/src/theme/entry.ts +85 -6
  574. package/src/theme/palette.ts +121 -45
  575. package/src/translate/prompts.ts +1 -0
  576. package/src/translate/validate.ts +31 -3
  577. package/src/upgrade/upgrade.ts +4 -171
  578. package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
  579. package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
  580. package/dist/cli/chunk-35d4wj9f.js.map +0 -15
  581. package/dist/cli/chunk-364znk6q.js +0 -75
  582. package/dist/cli/chunk-364znk6q.js.map +0 -11
  583. package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
  584. package/dist/cli/chunk-8ktnccpt.js.map +0 -10
  585. package/dist/cli/chunk-9t7a85s3.js.map +0 -10
  586. package/dist/cli/chunk-b07cmahc.js +0 -145
  587. package/dist/cli/chunk-b07cmahc.js.map +0 -11
  588. package/dist/cli/chunk-c8chx29p.js.map +0 -36
  589. package/dist/cli/chunk-e04dxsz1.js +0 -39
  590. package/dist/cli/chunk-e04dxsz1.js.map +0 -10
  591. package/dist/cli/chunk-j85vccga.js.map +0 -36
  592. package/dist/cli/chunk-p3v96n38.js.map +0 -10
  593. package/dist/cli/chunk-pehfxfta.js.map +0 -10
  594. package/dist/cli/chunk-pv29h0wf.js.map +0 -190
  595. package/dist/cli/chunk-q58y5e6a.js.map +0 -10
  596. package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
  597. package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
  598. package/dist/cli/chunk-yfyb25rh.js.map +0 -14
  599. package/docs/content/sources.mdx +0 -334
  600. /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
  601. /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
  602. /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
  603. /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
  604. /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
  605. /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
  606. /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
  607. /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.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
 
@@ -7,7 +7,8 @@ import { TRANSLATABLE_KEY_PATHS } from "./prompts.ts";
7
7
  * structure: the final frontmatter is *reconstructed* from the source (clone
8
8
  * the source data, overlay only the translatable string values), so invented
9
9
  * keys are dropped, deleted keys are restored, and slugs/icons/orders/dates
10
- * stay source-verbatim by construction. Only then is the file written.
10
+ * stay source-verbatim by construction. The one source key left out is
11
+ * `seo.canonical` (see `dropCanonical`). Only then is the file written.
11
12
  */
12
13
 
13
14
  export type ValidationResult =
@@ -93,6 +94,26 @@ const setPath = (
93
94
  parent[path.at(-1) as string] = value;
94
95
  };
95
96
 
97
+ /**
98
+ * Drop `seo.canonical`, and `seo` with it when nothing else is left. The
99
+ * source's canonical names a page in the source language (most often the
100
+ * source page itself); copied into a translation, it would canonicalize the
101
+ * translation to another language and take it out of search. Without it the
102
+ * translation gets Blume's default canonical: its own URL.
103
+ */
104
+ const dropCanonical = (data: FrontmatterData): void => {
105
+ const { seo } = data;
106
+ if (!isKeyedObject(seo) || !("canonical" in seo)) {
107
+ return;
108
+ }
109
+ const { canonical: _canonical, ...rest } = seo;
110
+ if (Object.keys(rest).length > 0) {
111
+ data.seo = rest;
112
+ } else {
113
+ delete data.seo;
114
+ }
115
+ };
116
+
96
117
  const ensureTrailingNewline = (text: string): string =>
97
118
  text.endsWith("\n") ? text : `${text}\n`;
98
119
 
@@ -132,8 +153,14 @@ export const validateTranslation = (
132
153
  let parsed: { content: string; data: FrontmatterData };
133
154
  try {
134
155
  parsed = matter(candidate);
135
- } catch {
136
- return { ok: false, reason: "frontmatter does not parse as YAML" };
156
+ } catch (error) {
157
+ // js-yaml's message leads with the problem and its line:column in the
158
+ // file, then a multi-line code frame; the first line is enough to act on.
159
+ const message = error instanceof Error ? error.message : String(error);
160
+ return {
161
+ ok: false,
162
+ reason: `frontmatter does not parse as YAML: ${message.replace(/\n[\s\S]*$/u, "")}`,
163
+ };
137
164
  }
138
165
 
139
166
  const rawBody = ensureTrailingNewline(parsed.content.replace(/^\r?\n/u, ""));
@@ -175,6 +202,7 @@ export const validateTranslation = (
175
202
  setPath(data, path, translated);
176
203
  }
177
204
  }
205
+ dropCanonical(data);
178
206
 
179
207
  return {
180
208
  ok: true,
@@ -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
  };