blume 2.0.2 → 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 (601) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +113 -0
  3. package/README.md +1 -1
  4. package/dist/cli/{chunk-6k4ftwze.js → chunk-0gz36akr.js} +18 -2
  5. package/dist/cli/{chunk-6k4ftwze.js.map → chunk-0gz36akr.js.map} +3 -3
  6. package/dist/cli/{chunk-zp79m0ts.js → chunk-1n228xqb.js} +2 -2
  7. package/dist/cli/{chunk-ddndchfr.js → chunk-2f3ndkpw.js} +57 -29
  8. package/dist/cli/chunk-2f3ndkpw.js.map +14 -0
  9. package/dist/cli/{chunk-fsmrqk8a.js → chunk-2f7n4qzt.js} +8 -2
  10. package/dist/cli/{chunk-fsmrqk8a.js.map → chunk-2f7n4qzt.js.map} +3 -3
  11. package/dist/cli/{chunk-ppzjqwx2.js → chunk-2n4ps1b3.js} +17 -18
  12. package/dist/cli/{chunk-ppzjqwx2.js.map → chunk-2n4ps1b3.js.map} +3 -3
  13. package/dist/cli/{chunk-5r8g91qn.js → chunk-43zcf4gz.js} +398 -159
  14. package/dist/cli/chunk-43zcf4gz.js.map +36 -0
  15. package/dist/cli/chunk-4ejxbzee.js +39 -0
  16. package/dist/cli/chunk-4ejxbzee.js.map +10 -0
  17. package/dist/cli/{chunk-hr8ne106.js → chunk-4h8z9vv5.js} +296 -77
  18. package/dist/cli/chunk-4h8z9vv5.js.map +16 -0
  19. package/dist/cli/{chunk-k7pj68a8.js → chunk-5cg2rzgf.js} +18 -16
  20. package/dist/cli/{chunk-k7pj68a8.js.map → chunk-5cg2rzgf.js.map} +2 -2
  21. package/dist/cli/{chunk-h2ez8dzb.js → chunk-5ffywsmb.js} +4 -4
  22. package/dist/cli/{chunk-g698a744.js → chunk-5wj2qwn2.js} +5 -5
  23. package/dist/cli/chunk-6bm0xpgd.js +18 -0
  24. package/dist/cli/chunk-6bm0xpgd.js.map +10 -0
  25. package/dist/cli/{chunk-3yce002v.js → chunk-713mngdq.js} +15 -8
  26. package/dist/cli/chunk-713mngdq.js.map +14 -0
  27. package/dist/cli/{chunk-91ws1n6j.js → chunk-9geymqns.js} +17 -15
  28. package/dist/cli/{chunk-91ws1n6j.js.map → chunk-9geymqns.js.map} +2 -2
  29. package/dist/cli/{chunk-6dtt0zfn.js → chunk-9xr4dgee.js} +27 -18
  30. package/dist/cli/chunk-9xr4dgee.js.map +10 -0
  31. package/dist/cli/{chunk-sqw4ekg1.js → chunk-amrb6hgh.js} +2 -2
  32. package/dist/cli/chunk-cm89scdv.js +443 -0
  33. package/dist/cli/chunk-cm89scdv.js.map +11 -0
  34. package/dist/cli/{chunk-wdrt2k2v.js → chunk-cmtcnh9f.js} +90 -26
  35. package/dist/cli/chunk-cmtcnh9f.js.map +10 -0
  36. package/dist/cli/chunk-cy5bm0j0.js +104 -0
  37. package/dist/cli/chunk-cy5bm0j0.js.map +11 -0
  38. package/dist/cli/{chunk-7mbqtmgb.js → chunk-e7vvk5ya.js} +21 -12
  39. package/dist/cli/chunk-e7vvk5ya.js.map +10 -0
  40. package/dist/cli/{chunk-qkb5a8sa.js → chunk-g2z9x01v.js} +6 -98
  41. package/dist/cli/chunk-g2z9x01v.js.map +10 -0
  42. package/dist/cli/{chunk-273ygyr4.js → chunk-ga0pf4aj.js} +7 -7
  43. package/dist/cli/{chunk-273ygyr4.js.map → chunk-ga0pf4aj.js.map} +3 -3
  44. package/dist/cli/{chunk-h7k3nq3v.js → chunk-gp84za0h.js} +2 -2
  45. package/dist/cli/{chunk-hqp2ajnh.js → chunk-h2a48yhd.js} +195 -73
  46. package/dist/cli/chunk-h2a48yhd.js.map +36 -0
  47. package/dist/cli/{chunk-pbg5a4s3.js → chunk-jnwj5kjj.js} +71 -47
  48. package/dist/cli/chunk-jnwj5kjj.js.map +19 -0
  49. package/dist/cli/chunk-kwrg63tm.js +31 -0
  50. package/dist/cli/chunk-kwrg63tm.js.map +10 -0
  51. package/dist/cli/{chunk-8g8ytmgx.js → chunk-nd1821sk.js} +21 -19
  52. package/dist/cli/{chunk-8g8ytmgx.js.map → chunk-nd1821sk.js.map} +2 -2
  53. package/dist/cli/{chunk-w4bxdvsa.js → chunk-ntv4qrt7.js} +17 -15
  54. package/dist/cli/{chunk-w4bxdvsa.js.map → chunk-ntv4qrt7.js.map} +2 -2
  55. package/dist/cli/{chunk-bfwp9vp6.js → chunk-p804f3pe.js} +7 -7
  56. package/dist/cli/{chunk-4e9b9ra6.js → chunk-py62fewh.js} +6 -6
  57. package/dist/cli/{chunk-4e9b9ra6.js.map → chunk-py62fewh.js.map} +1 -1
  58. package/dist/cli/chunk-q3wxxq39.js +126 -0
  59. package/dist/cli/chunk-q3wxxq39.js.map +11 -0
  60. package/dist/cli/{chunk-j85scx15.js → chunk-rekqz4qg.js} +142 -46
  61. package/dist/cli/chunk-rekqz4qg.js.map +10 -0
  62. package/dist/cli/{chunk-00gs3wqs.js → chunk-ta27feev.js} +1 -1
  63. package/dist/cli/{chunk-v6ya5kcb.js → chunk-xkz5xbtv.js} +4031 -1132
  64. package/dist/cli/chunk-xkz5xbtv.js.map +213 -0
  65. package/dist/cli/{chunk-bbnwccaz.js → chunk-y4ykbark.js} +2 -2
  66. package/dist/cli/{chunk-n1yg3tj3.js → chunk-y5h4r2y0.js} +6 -6
  67. package/dist/cli/{chunk-n1yg3tj3.js.map → chunk-y5h4r2y0.js.map} +3 -3
  68. package/dist/cli/{chunk-nfcyttvj.js → chunk-yj17vs39.js} +9 -9
  69. package/dist/cli/{chunk-nfcyttvj.js.map → chunk-yj17vs39.js.map} +1 -1
  70. package/dist/cli/{chunk-7vtckvaw.js → chunk-yxmk4pec.js} +16 -14
  71. package/dist/cli/{chunk-7vtckvaw.js.map → chunk-yxmk4pec.js.map} +2 -2
  72. package/dist/cli/{chunk-gs7r695n.js → chunk-zccbjcj0.js} +22 -8
  73. package/dist/cli/{chunk-gs7r695n.js.map → chunk-zccbjcj0.js.map} +3 -3
  74. package/dist/cli/{chunk-xh43dwgw.js → chunk-zf748avv.js} +415 -225
  75. package/dist/cli/chunk-zf748avv.js.map +37 -0
  76. package/dist/cli/{chunk-d1v5rhy0.js → chunk-zhvd6adm.js} +16 -14
  77. package/dist/cli/{chunk-d1v5rhy0.js.map → chunk-zhvd6adm.js.map} +2 -2
  78. package/dist/cli/index.js +28 -20
  79. package/dist/cli/index.js.map +5 -5
  80. package/dist/types/ai/agent-surface.d.ts +8 -7
  81. package/dist/types/ai/ai-catalog.d.ts +7 -0
  82. package/dist/types/ai/ask-context.d.ts +22 -0
  83. package/dist/types/ai/ask.d.ts +271 -58
  84. package/dist/types/ai/index.d.ts +2 -2
  85. package/dist/types/ai/link-headers.d.ts +8 -1
  86. package/dist/types/ai/openapi-components.d.ts +5 -2
  87. package/dist/types/ai/relative-links.d.ts +9 -7
  88. package/dist/types/ai/site-skill.d.ts +26 -0
  89. package/dist/types/ai/skills.d.ts +20 -1
  90. package/dist/types/ai/tar.d.ts +1 -3
  91. package/dist/types/analytics/index.d.ts +2 -0
  92. package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
  93. package/dist/types/analytics/schema.d.ts +14 -0
  94. package/dist/types/astro/integration.d.ts +11 -2
  95. package/dist/types/captcha/hcaptcha.d.ts +27 -0
  96. package/dist/types/captcha/index.d.ts +28 -0
  97. package/dist/types/captcha/schema.d.ts +29 -0
  98. package/dist/types/captcha/turnstile.d.ts +28 -0
  99. package/dist/types/components/content/api-field.d.ts +59 -0
  100. package/dist/types/components/content/api-page.d.ts +95 -0
  101. package/dist/types/components/layout/nav-utils.d.ts +26 -0
  102. package/dist/types/components/openapi/helpers.d.ts +137 -0
  103. package/dist/types/components/openapi/security.d.ts +85 -0
  104. package/dist/types/consent/ethyca.d.ts +48 -0
  105. package/dist/types/consent/index.d.ts +37 -0
  106. package/dist/types/consent/native.d.ts +28 -0
  107. package/dist/types/consent/osano.d.ts +42 -0
  108. package/dist/types/consent/schema.d.ts +110 -0
  109. package/dist/types/core/base-path.d.ts +21 -7
  110. package/dist/types/core/config-input.d.ts +196 -27
  111. package/dist/types/core/data.d.ts +49 -4
  112. package/dist/types/core/directive-diagnostics.d.ts +12 -0
  113. package/dist/types/core/footer.d.ts +8 -0
  114. package/dist/types/core/heading-markers.d.ts +5 -7
  115. package/dist/types/core/i18n-ui.d.ts +86 -0
  116. package/dist/types/core/i18n.d.ts +2 -0
  117. package/dist/types/core/includes.d.ts +8 -2
  118. package/dist/types/core/last-modified.d.ts +10 -0
  119. package/dist/types/core/localizable.d.ts +7 -0
  120. package/dist/types/core/meta.d.ts +8 -0
  121. package/dist/types/core/page-modes.d.ts +29 -0
  122. package/dist/types/core/redirect-patterns.d.ts +144 -0
  123. package/dist/types/core/related.d.ts +40 -0
  124. package/dist/types/core/schema.d.ts +558 -56
  125. package/dist/types/core/sources/lower.d.ts +29 -16
  126. package/dist/types/core/sources/normalize.d.ts +13 -1
  127. package/dist/types/core/sources/read.d.ts +5 -0
  128. package/dist/types/core/sources/watch.d.ts +12 -5
  129. package/dist/types/core/standard-schema.d.ts +5 -0
  130. package/dist/types/core/types.d.ts +1 -1
  131. package/dist/types/core/variables.d.ts +42 -0
  132. package/dist/types/deploy/artifacts.d.ts +6 -4
  133. package/dist/types/deploy/headers.d.ts +5 -0
  134. package/dist/types/deploy/node-headers.d.ts +13 -2
  135. package/dist/types/deploy/platforms/cloudflare.d.ts +5 -0
  136. package/dist/types/deploy/platforms/netlify.d.ts +7 -0
  137. package/dist/types/deploy/platforms/types.d.ts +8 -0
  138. package/dist/types/deploy/platforms/vercel.d.ts +6 -0
  139. package/dist/types/deploy/redirects.d.ts +61 -22
  140. package/dist/types/deploy/vercel-negotiation.d.ts +9 -0
  141. package/dist/types/markdown/code-title.d.ts +17 -0
  142. package/dist/types/markdown/directives.d.ts +62 -0
  143. package/dist/types/markdown/features.d.ts +24 -2
  144. package/dist/types/markdown/mdast.d.ts +63 -0
  145. package/dist/types/narration/build.d.ts +70 -0
  146. package/dist/types/narration/provider.d.ts +26 -0
  147. package/dist/types/narration/script.d.ts +154 -0
  148. package/dist/types/openapi/asyncapi.d.ts +4 -2
  149. package/dist/types/openapi/model.d.ts +12 -6
  150. package/dist/types/openapi/overlay.d.ts +54 -0
  151. package/dist/types/openapi/parse.d.ts +13 -0
  152. package/dist/types/openapi/references.d.ts +14 -4
  153. package/dist/types/ratelimit/cloudflare.d.ts +39 -0
  154. package/dist/types/ratelimit/index.d.ts +27 -0
  155. package/dist/types/ratelimit/memory.d.ts +36 -0
  156. package/dist/types/ratelimit/schema.d.ts +111 -0
  157. package/dist/types/ratelimit/upstash.d.ts +21 -0
  158. package/dist/types/ratelimit/wrangler.d.ts +23 -0
  159. package/dist/types/reference/asyncapi.d.ts +10 -10
  160. package/dist/types/reference/graphql.d.ts +13 -10
  161. package/dist/types/reference/openapi.d.ts +33 -12
  162. package/dist/types/reference/options.d.ts +45 -5
  163. package/dist/types/reference/scalar.d.ts +13 -0
  164. package/dist/types/reference/schema.d.ts +60 -36
  165. package/dist/types/search/documents.d.ts +12 -1
  166. package/dist/types/search/orama-index.d.ts +4 -0
  167. package/dist/types/seo/metatags.d.ts +20 -0
  168. package/docs/02-deployment.mdx +44 -6
  169. package/docs/03-upgrading.mdx +4 -4
  170. package/docs/04-migrating.mdx +1 -1
  171. package/docs/08-faq.mdx +1 -1
  172. package/docs/advanced/changelog.mdx +2 -2
  173. package/docs/advanced/custom-pages.mdx +3 -3
  174. package/docs/advanced/skills.mdx +14 -0
  175. package/docs/cli/audit.mdx +38 -2
  176. package/docs/cli/evals.mdx +3 -3
  177. package/docs/cli/index.mdx +1 -0
  178. package/docs/cli/translate.mdx +3 -3
  179. package/docs/cli/version.mdx +1 -1
  180. package/docs/configuration/analytics.mdx +22 -1
  181. package/docs/configuration/assistant.mdx +188 -36
  182. package/docs/configuration/consent.mdx +100 -0
  183. package/docs/configuration/customization.mdx +6 -4
  184. package/docs/configuration/index.mdx +63 -5
  185. package/docs/configuration/meta.ts +3 -0
  186. package/docs/configuration/narration.mdx +119 -0
  187. package/docs/configuration/rate-limiting.mdx +69 -0
  188. package/docs/configuration/search.mdx +30 -2
  189. package/docs/configuration/theming.mdx +3 -1
  190. package/docs/content/components.mdx +107 -1
  191. package/docs/content/frontmatter.mdx +77 -1
  192. package/docs/content/i18n.mdx +40 -3
  193. package/docs/content/includes.mdx +16 -0
  194. package/docs/content/index.mdx +4 -2
  195. package/docs/content/islands.mdx +1 -1
  196. package/docs/content/meta.mdx +4 -1
  197. package/docs/content/meta.ts +1 -0
  198. package/docs/content/navigation.mdx +28 -6
  199. package/docs/content/sources/contentful.mdx +32 -0
  200. package/docs/content/sources/custom.mdx +39 -0
  201. package/docs/content/sources/github-releases.mdx +31 -0
  202. package/docs/content/sources/index.mdx +91 -0
  203. package/docs/content/sources/meta.ts +16 -0
  204. package/docs/content/sources/notion.mdx +32 -0
  205. package/docs/content/sources/obsidian.mdx +37 -0
  206. package/docs/content/sources/payload.mdx +30 -0
  207. package/docs/content/sources/remote-mdx.mdx +40 -0
  208. package/docs/content/sources/sanity.mdx +29 -0
  209. package/docs/content/sources/strapi.mdx +31 -0
  210. package/docs/content/syntax.mdx +81 -2
  211. package/docs/content/variables.mdx +41 -0
  212. package/docs/content/versioning.mdx +1 -1
  213. package/docs/discoverability/agent-discovery.mdx +30 -3
  214. package/docs/discoverability/index.mdx +3 -2
  215. package/docs/discoverability/llms-txt.mdx +1 -1
  216. package/docs/discoverability/markdown.mdx +2 -2
  217. package/docs/discoverability/metadata.mdx +17 -0
  218. package/docs/discoverability/open-graph.mdx +5 -3
  219. package/docs/discoverability/rss.mdx +1 -1
  220. package/docs/references/api-pages.mdx +74 -0
  221. package/docs/references/asyncapi.mdx +2 -2
  222. package/docs/references/graphql.mdx +3 -3
  223. package/docs/references/meta.ts +1 -1
  224. package/docs/references/openapi.mdx +106 -5
  225. package/docs/references/scalar.mdx +3 -1
  226. package/package.json +36 -1
  227. package/skills/blume/SKILL.md +3 -0
  228. package/skills/blume-migrate/SKILL.md +5 -5
  229. package/skills/blume-migrate/references/docusaurus.md +3 -3
  230. package/skills/blume-migrate/references/fumadocs.md +1 -1
  231. package/skills/blume-migrate/references/mintlify.md +37 -19
  232. package/skills/blume-migrate/references/nextra.md +3 -3
  233. package/skills/blume-migrate/references/starlight.md +2 -1
  234. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +67 -16
  235. package/skills/blume-write-skill/SKILL.md +82 -0
  236. package/src/ai/agent-readability.ts +4 -3
  237. package/src/ai/agent-surface.ts +9 -7
  238. package/src/ai/ai-catalog.ts +12 -5
  239. package/src/ai/api/handlers.ts +2 -2
  240. package/src/ai/api/spec.ts +2 -2
  241. package/src/ai/api-catalog.ts +6 -2
  242. package/src/ai/ask-context.ts +73 -20
  243. package/src/ai/ask-data.ts +6 -0
  244. package/src/ai/ask-tools.ts +142 -0
  245. package/src/ai/ask.ts +354 -76
  246. package/src/ai/changelog-markdown.ts +2 -2
  247. package/src/ai/component-markdown.ts +75 -0
  248. package/src/ai/cors.ts +2 -0
  249. package/src/ai/index.ts +12 -0
  250. package/src/ai/link-headers.ts +14 -5
  251. package/src/ai/llms.ts +24 -9
  252. package/src/ai/markdown.ts +2 -1
  253. package/src/ai/mcp/data.ts +6 -0
  254. package/src/ai/mcp/discovery.ts +2 -2
  255. package/src/ai/mcp/query.ts +2 -2
  256. package/src/ai/mcp/server.ts +2 -2
  257. package/src/ai/openapi-components.ts +31 -9
  258. package/src/ai/relative-links.ts +42 -26
  259. package/src/ai/serializers.ts +2 -1
  260. package/src/ai/site-skill.ts +274 -0
  261. package/src/ai/skills.ts +49 -3
  262. package/src/ai/tar.ts +139 -12
  263. package/src/ai/write-skill.ts +97 -0
  264. package/src/analytics/head.ts +4 -0
  265. package/src/analytics/index.ts +5 -0
  266. package/src/analytics/one-dollar-stats.ts +86 -0
  267. package/src/analytics/schema.ts +2 -0
  268. package/src/astro/generate.ts +133 -19
  269. package/src/astro/include-hmr.ts +31 -12
  270. package/src/astro/include-refresh.ts +19 -8
  271. package/src/astro/index.ts +1 -0
  272. package/src/astro/integration.ts +143 -14
  273. package/src/astro/module-types.ts +6 -0
  274. package/src/astro/runtime-modules.ts +28 -13
  275. package/src/astro/templates.ts +364 -67
  276. package/src/astro/variables.ts +31 -0
  277. package/src/audit/catalog.ts +19 -0
  278. package/src/audit/checks/contrast.ts +183 -0
  279. package/src/audit/checks/i18n.ts +2 -3
  280. package/src/audit/checks/indexability.ts +2 -3
  281. package/src/audit/checks/links.ts +13 -13
  282. package/src/audit/checks/sitemap.ts +2 -3
  283. package/src/audit/graph.ts +3 -1
  284. package/src/audit/redirects.ts +46 -15
  285. package/src/audit/run.ts +14 -9
  286. package/src/audit/snapshot.ts +5 -0
  287. package/src/audit/types.ts +2 -1
  288. package/src/blume-modules.d.ts +7 -0
  289. package/src/captcha/client.ts +152 -0
  290. package/src/captcha/hcaptcha.ts +36 -0
  291. package/src/captcha/index.ts +28 -0
  292. package/src/captcha/schema.ts +32 -0
  293. package/src/captcha/turnstile.ts +38 -0
  294. package/src/captcha/verify.ts +71 -0
  295. package/src/cli/args.ts +32 -0
  296. package/src/cli/command-meta.ts +5 -0
  297. package/src/cli/commands/audit.ts +4 -1
  298. package/src/cli/commands/doctor.ts +25 -17
  299. package/src/cli/commands/eval.ts +19 -11
  300. package/src/cli/commands/skill.ts +96 -0
  301. package/src/cli/commands/translate.ts +9 -12
  302. package/src/cli/commands/validate.ts +3 -1
  303. package/src/cli/dev-lock.ts +157 -37
  304. package/src/cli/index.ts +5 -0
  305. package/src/cli/report-format.ts +11 -6
  306. package/src/cli/required-secrets.ts +71 -29
  307. package/src/components/BlumePage.astro +2 -0
  308. package/src/components/colors.ts +19 -0
  309. package/src/components/content/ApiEndpoint.astro +18 -0
  310. package/src/components/content/ApiField.astro +79 -0
  311. package/src/components/content/ApiPlayground.astro +62 -0
  312. package/src/components/content/ApiRail.astro +19 -0
  313. package/src/components/content/Badge.astro +5 -3
  314. package/src/components/content/Color.astro +1 -0
  315. package/src/components/content/Component.astro +2 -2
  316. package/src/components/content/FileTree.astro +1 -0
  317. package/src/components/content/GithubInfo.astro +1 -0
  318. package/src/components/content/Panel.astro +1 -0
  319. package/src/components/content/ParamField.astro +25 -0
  320. package/src/components/content/RequestExample.astro +17 -0
  321. package/src/components/content/ResponseExample.astro +17 -0
  322. package/src/components/content/ResponseField.astro +32 -0
  323. package/src/components/content/Step.astro +1 -0
  324. package/src/components/content/Tab.astro +0 -1
  325. package/src/components/content/Tabs.astro +4 -0
  326. package/src/components/content/Tile.astro +1 -0
  327. package/src/components/content/Tooltip.astro +1 -0
  328. package/src/components/content/Tree.astro +1 -0
  329. package/src/components/content/TypeTable.astro +4 -1
  330. package/src/components/content/View.astro +21 -0
  331. package/src/components/content/ViewSwitcher.astro +168 -0
  332. package/src/components/content/api-field.ts +100 -0
  333. package/src/components/content/api-page.ts +224 -0
  334. package/src/components/content/badge-color.ts +5 -2
  335. package/src/components/content/base-href.ts +13 -36
  336. package/src/components/content/view-switcher.ts +71 -0
  337. package/src/components/index.ts +2 -0
  338. package/src/components/islands/Assistant.astro +10 -1
  339. package/src/components/islands/assistant.tsx +125 -18
  340. package/src/components/islands/base-path.ts +47 -10
  341. package/src/components/islands/code-question.ts +62 -0
  342. package/src/components/islands/hooks.ts +145 -40
  343. package/src/components/islands/support-link.ts +68 -0
  344. package/src/components/islands/webmcp.ts +4 -2
  345. package/src/components/layout/Analytics.astro +11 -2
  346. package/src/components/layout/Banner.astro +14 -10
  347. package/src/components/layout/Breadcrumbs.astro +11 -4
  348. package/src/components/layout/ConsentBanner.astro +62 -0
  349. package/src/components/layout/ConsentHead.astro +38 -0
  350. package/src/components/layout/Directory.astro +94 -0
  351. package/src/components/layout/DiscoveryLinks.astro +9 -5
  352. package/src/components/layout/DrawerSwitchers.astro +51 -0
  353. package/src/components/layout/Empty.astro +2 -2
  354. package/src/components/layout/Header.astro +124 -82
  355. package/src/components/layout/LanguageSwitcher.astro +50 -17
  356. package/src/components/layout/NarrationPlayer.astro +1085 -0
  357. package/src/components/layout/NavSelector.astro +35 -9
  358. package/src/components/layout/NavTabMenu.astro +3 -3
  359. package/src/components/layout/NavTree.astro +16 -6
  360. package/src/components/layout/PageActions.astro +4 -3
  361. package/src/components/layout/PageFeedback.astro +54 -49
  362. package/src/components/layout/PageLayout.astro +78 -9
  363. package/src/components/layout/Pagination.astro +3 -3
  364. package/src/components/layout/ReferenceLayout.astro +17 -6
  365. package/src/components/layout/RelatedPages.astro +42 -0
  366. package/src/components/layout/RootLayout.astro +313 -50
  367. package/src/components/layout/Search.astro +64 -30
  368. package/src/components/layout/SiteFooter.astro +124 -0
  369. package/src/components/layout/SiteMetatags.astro +16 -0
  370. package/src/components/layout/VersionBanner.astro +2 -2
  371. package/src/components/layout/analytics-client.ts +12 -0
  372. package/src/components/layout/consent/native.ts +79 -0
  373. package/src/components/layout/consent/types.ts +37 -0
  374. package/src/components/layout/footer-links.ts +53 -0
  375. package/src/components/layout/footer-socials.ts +87 -0
  376. package/src/components/layout/locale-redirect.ts +107 -0
  377. package/src/components/layout/nav-utils.ts +83 -0
  378. package/src/components/layout/page-feedback.ts +96 -0
  379. package/src/components/layout/search/analytics.ts +98 -0
  380. package/src/components/layout/search/flexsearch.ts +17 -5
  381. package/src/components/layout/search/orama-cloud.ts +26 -14
  382. package/src/components/layout/search/types.ts +20 -0
  383. package/src/components/layout/search/typesense.ts +5 -1
  384. package/src/components/layout/toc-active.ts +41 -0
  385. package/src/components/layout/toc-element.ts +8 -14
  386. package/src/components/openapi/ApiTagOperations.astro +2 -2
  387. package/src/components/openapi/AsyncApiOperation.astro +7 -4
  388. package/src/components/openapi/GraphqlChip.astro +2 -2
  389. package/src/components/openapi/Operation.astro +163 -13
  390. package/src/components/openapi/Playground.astro +4 -4
  391. package/src/components/openapi/RequestBody.astro +6 -4
  392. package/src/components/openapi/RequestPanel.astro +63 -8
  393. package/src/components/openapi/Responses.astro +6 -4
  394. package/src/components/openapi/SchemaTable.astro +7 -0
  395. package/src/components/openapi/async-snippets.ts +4 -4
  396. package/src/components/openapi/async.ts +38 -6
  397. package/src/components/openapi/code-samples.ts +97 -0
  398. package/src/components/openapi/helpers.ts +19 -9
  399. package/src/components/openapi/message-composer.ts +6 -1
  400. package/src/components/openapi/message.ts +17 -2
  401. package/src/components/openapi/operation-model.ts +81 -11
  402. package/src/components/openapi/panel.ts +4 -2
  403. package/src/components/openapi/param-style.ts +181 -0
  404. package/src/components/openapi/playground-client.ts +73 -16
  405. package/src/components/openapi/request.ts +190 -26
  406. package/src/components/openapi/schema-tree.ts +30 -24
  407. package/src/components/openapi/security.ts +6 -3
  408. package/src/components/openapi/snippets.ts +953 -13
  409. package/src/components/openapi/ws-client.ts +18 -2
  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/base-path.ts +62 -16
  421. package/src/core/builtin-tags.ts +5 -0
  422. package/src/core/client-address.ts +19 -0
  423. package/src/core/config-input.ts +203 -27
  424. package/src/core/data.ts +44 -4
  425. package/src/core/diagnostics.ts +5 -2
  426. package/src/core/directive-diagnostics.ts +99 -0
  427. package/src/core/footer.ts +26 -0
  428. package/src/core/frontmatter.ts +21 -18
  429. package/src/core/graph.ts +39 -36
  430. package/src/core/heading-markers.ts +5 -18
  431. package/src/core/i18n-ui.ts +82 -2
  432. package/src/core/i18n.ts +31 -3
  433. package/src/core/includes.ts +20 -3
  434. package/src/core/last-modified.ts +25 -3
  435. package/src/core/links.ts +16 -2
  436. package/src/core/locale-links.ts +5 -1
  437. package/src/core/localizable.ts +26 -0
  438. package/src/core/meta.ts +33 -19
  439. package/src/core/navigation.ts +71 -20
  440. package/src/core/page-modes.ts +56 -0
  441. package/src/core/project-graph.ts +138 -10
  442. package/src/core/redirect-patterns.ts +491 -0
  443. package/src/core/related.ts +131 -0
  444. package/src/core/schema.ts +342 -68
  445. package/src/core/sources/contentful-rich-text.ts +27 -20
  446. package/src/core/sources/filesystem.ts +20 -2
  447. package/src/core/sources/github-releases.ts +25 -6
  448. package/src/core/sources/lexical.ts +23 -18
  449. package/src/core/sources/lower.ts +201 -34
  450. package/src/core/sources/mdx-remote.ts +51 -16
  451. package/src/core/sources/normalize.ts +327 -91
  452. package/src/core/sources/notion.ts +52 -25
  453. package/src/core/sources/obsidian.ts +23 -6
  454. package/src/core/sources/portable-text.ts +38 -21
  455. package/src/core/sources/read.ts +8 -3
  456. package/src/core/sources/strapi-blocks.ts +20 -16
  457. package/src/core/sources/watch.ts +20 -7
  458. package/src/core/standard-schema.ts +10 -6
  459. package/src/core/types.ts +1 -1
  460. package/src/core/ui-packs/ar.ts +43 -0
  461. package/src/core/ui-packs/bg.ts +45 -0
  462. package/src/core/ui-packs/bn.ts +43 -0
  463. package/src/core/ui-packs/ca.ts +46 -0
  464. package/src/core/ui-packs/cs.ts +44 -0
  465. package/src/core/ui-packs/da.ts +45 -0
  466. package/src/core/ui-packs/de.ts +46 -0
  467. package/src/core/ui-packs/el.ts +45 -0
  468. package/src/core/ui-packs/es.ts +46 -0
  469. package/src/core/ui-packs/fa.ts +45 -0
  470. package/src/core/ui-packs/fi.ts +45 -0
  471. package/src/core/ui-packs/fr.ts +46 -0
  472. package/src/core/ui-packs/he.ts +43 -0
  473. package/src/core/ui-packs/hi.ts +44 -0
  474. package/src/core/ui-packs/hr.ts +45 -0
  475. package/src/core/ui-packs/hu.ts +44 -0
  476. package/src/core/ui-packs/id.ts +45 -0
  477. package/src/core/ui-packs/it.ts +45 -0
  478. package/src/core/ui-packs/ja.ts +45 -0
  479. package/src/core/ui-packs/ko.ts +44 -0
  480. package/src/core/ui-packs/nl.ts +46 -0
  481. package/src/core/ui-packs/no.ts +44 -0
  482. package/src/core/ui-packs/pl.ts +45 -0
  483. package/src/core/ui-packs/pt-br.ts +46 -0
  484. package/src/core/ui-packs/pt.ts +45 -0
  485. package/src/core/ui-packs/ro.ts +45 -0
  486. package/src/core/ui-packs/ru.ts +45 -0
  487. package/src/core/ui-packs/sk.ts +44 -0
  488. package/src/core/ui-packs/sr.ts +45 -0
  489. package/src/core/ui-packs/sv.ts +44 -0
  490. package/src/core/ui-packs/th.ts +43 -0
  491. package/src/core/ui-packs/tr.ts +45 -0
  492. package/src/core/ui-packs/uk.ts +45 -0
  493. package/src/core/ui-packs/vi.ts +45 -0
  494. package/src/core/ui-packs/zh-tw.ts +43 -0
  495. package/src/core/ui-packs/zh.ts +43 -0
  496. package/src/core/variables.ts +103 -0
  497. package/src/core/version-cut.ts +52 -15
  498. package/src/deploy/artifacts.ts +104 -14
  499. package/src/deploy/cloudflare-negotiation.ts +39 -17
  500. package/src/deploy/headers.ts +10 -5
  501. package/src/deploy/node-headers.ts +64 -10
  502. package/src/deploy/platforms/cloudflare.ts +44 -3
  503. package/src/deploy/platforms/netlify.ts +34 -1
  504. package/src/deploy/platforms/node.ts +1 -0
  505. package/src/deploy/platforms/static.ts +1 -0
  506. package/src/deploy/platforms/types.ts +8 -0
  507. package/src/deploy/platforms/vercel.ts +38 -2
  508. package/src/deploy/redirects.ts +139 -36
  509. package/src/deploy/robots.ts +2 -2
  510. package/src/deploy/rss.ts +4 -3
  511. package/src/deploy/sitemap.ts +7 -5
  512. package/src/deploy/vercel-negotiation.ts +36 -0
  513. package/src/markdown/api-rail.ts +259 -0
  514. package/src/markdown/base-links.ts +34 -36
  515. package/src/markdown/code-title.ts +35 -9
  516. package/src/markdown/directives.ts +242 -36
  517. package/src/markdown/features.ts +20 -2
  518. package/src/markdown/fence-meta.ts +2 -0
  519. package/src/markdown/include.ts +11 -1
  520. package/src/markdown/index.ts +35 -11
  521. package/src/markdown/math.ts +4 -4
  522. package/src/markdown/mdast.ts +5 -2
  523. package/src/markdown/relative-links.ts +12 -4
  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 +136 -11
  531. package/src/og/derive.ts +41 -31
  532. package/src/og/index.ts +1 -0
  533. package/src/openapi/asyncapi.ts +4 -2
  534. package/src/openapi/model.ts +77 -36
  535. package/src/openapi/overlay.ts +256 -0
  536. package/src/openapi/parse.ts +55 -2
  537. package/src/openapi/proxy.ts +63 -10
  538. package/src/openapi/references.ts +21 -5
  539. package/src/openapi/render-mdx.ts +46 -3
  540. package/src/openapi/scalar.ts +40 -6
  541. package/src/openapi/source.ts +1 -1
  542. package/src/ratelimit/cloudflare.ts +54 -0
  543. package/src/ratelimit/index.ts +30 -0
  544. package/src/ratelimit/memory.ts +45 -0
  545. package/src/ratelimit/runtime.ts +229 -0
  546. package/src/ratelimit/schema.ts +28 -0
  547. package/src/ratelimit/upstash.ts +30 -0
  548. package/src/ratelimit/wrangler.ts +70 -0
  549. package/src/reference/asyncapi.ts +2 -2
  550. package/src/reference/graphql.ts +5 -2
  551. package/src/reference/openapi.ts +21 -7
  552. package/src/reference/options.ts +51 -7
  553. package/src/reference/scalar.ts +33 -8
  554. package/src/registry/eject.ts +201 -28
  555. package/src/registry/registry.ts +7 -0
  556. package/src/search/adapters/version-scope.ts +30 -0
  557. package/src/search/documents.ts +93 -28
  558. package/src/search/orama-index.ts +28 -3
  559. package/src/search/pagefind-ranking.ts +39 -0
  560. package/src/search/popular.ts +2 -1
  561. package/src/search/sync/algolia.ts +15 -4
  562. package/src/search/sync/orama-cloud.ts +3 -0
  563. package/src/search/sync/typesense.ts +5 -0
  564. package/src/seo/jsonld.ts +7 -3
  565. package/src/seo/metatags.ts +67 -0
  566. package/src/theme/chrome-icons.ts +1 -0
  567. package/src/theme/color.ts +500 -0
  568. package/src/theme/entry.ts +56 -3
  569. package/src/theme/palette.ts +121 -45
  570. package/src/translate/meta.ts +68 -24
  571. package/src/translate/prompts.ts +1 -0
  572. package/src/translate/run.ts +3 -3
  573. package/src/translate/validate.ts +12 -3
  574. package/src/translate/work-list.ts +56 -17
  575. package/src/upgrade/upgrade.ts +4 -171
  576. package/dist/cli/chunk-3yce002v.js.map +0 -14
  577. package/dist/cli/chunk-5r8g91qn.js.map +0 -34
  578. package/dist/cli/chunk-6dtt0zfn.js.map +0 -10
  579. package/dist/cli/chunk-7mbqtmgb.js.map +0 -10
  580. package/dist/cli/chunk-ddndchfr.js.map +0 -14
  581. package/dist/cli/chunk-esh98wmb.js +0 -23
  582. package/dist/cli/chunk-esh98wmb.js.map +0 -10
  583. package/dist/cli/chunk-hqp2ajnh.js.map +0 -35
  584. package/dist/cli/chunk-hr8ne106.js.map +0 -13
  585. package/dist/cli/chunk-j85scx15.js.map +0 -10
  586. package/dist/cli/chunk-mqc662a6.js +0 -75
  587. package/dist/cli/chunk-mqc662a6.js.map +0 -11
  588. package/dist/cli/chunk-pbg5a4s3.js.map +0 -19
  589. package/dist/cli/chunk-qkb5a8sa.js.map +0 -10
  590. package/dist/cli/chunk-v6ya5kcb.js.map +0 -189
  591. package/dist/cli/chunk-wdrt2k2v.js.map +0 -10
  592. package/dist/cli/chunk-xh43dwgw.js.map +0 -36
  593. package/docs/content/sources.mdx +0 -338
  594. /package/dist/cli/{chunk-zp79m0ts.js.map → chunk-1n228xqb.js.map} +0 -0
  595. /package/dist/cli/{chunk-h2ez8dzb.js.map → chunk-5ffywsmb.js.map} +0 -0
  596. /package/dist/cli/{chunk-g698a744.js.map → chunk-5wj2qwn2.js.map} +0 -0
  597. /package/dist/cli/{chunk-sqw4ekg1.js.map → chunk-amrb6hgh.js.map} +0 -0
  598. /package/dist/cli/{chunk-h7k3nq3v.js.map → chunk-gp84za0h.js.map} +0 -0
  599. /package/dist/cli/{chunk-bfwp9vp6.js.map → chunk-p804f3pe.js.map} +0 -0
  600. /package/dist/cli/{chunk-00gs3wqs.js.map → chunk-ta27feev.js.map} +0 -0
  601. /package/dist/cli/{chunk-bbnwccaz.js.map → chunk-y4ykbark.js.map} +0 -0
@@ -2,15 +2,20 @@ import type { AstroIntegration } from "astro";
2
2
  import type { z } from "zod";
3
3
 
4
4
  import type { AskRetrievalOptions } from "../ai/ask-context.ts";
5
- import type { AssistantAdapter } from "../ai/ask.ts";
5
+ import type { AssistantAdapter, AssistantGatewayAdapter } from "../ai/ask.ts";
6
6
  import type { ComponentMarkdown } from "../ai/component-markdown.ts";
7
7
  import type { AnalyticsAdapter } from "../analytics/schema.ts";
8
+ import type { CaptchaAdapter } from "../captcha/schema.ts";
9
+ import type { ConsentAdapter } from "../consent/schema.ts";
8
10
  import type { DeploymentInput } from "../deploy/adapters/registry.ts";
9
11
  import type { CodeTheme } from "../markdown/themes.ts";
12
+ import type { RateLimitAdapter } from "../ratelimit/schema.ts";
13
+ import type { PlaygroundOptions } from "../reference/options.ts";
10
14
  import type { ReferenceAdapter } from "../reference/schema.ts";
11
15
  import type { AnySearchAdapter } from "../search/adapters/registry.ts";
12
16
  import type { SourceAdapterInput } from "../sources/registry.ts";
13
17
  import type { FontSlug } from "../theme/fonts.ts";
18
+ import type { FooterSocial } from "./footer.ts";
14
19
  import type {
15
20
  blumeConfigSchema,
16
21
  OpenInChatProvider,
@@ -92,21 +97,64 @@ export type LogoConfig =
92
97
  export type BannerConfig =
93
98
  | string
94
99
  | {
95
- /** The banner message. */
96
- content: string;
100
+ /** The banner message, or a map of locale code to message. */
101
+ content: LocalizableLabel;
97
102
  /** Show a dismiss button; the choice is remembered per visitor. */
98
103
  dismissible?: boolean;
99
- /** Stable key for remembering dismissal; defaults to the content. */
104
+ /**
105
+ * Stable key for remembering dismissal; defaults to the content (the
106
+ * default locale's, for a per-locale map).
107
+ */
100
108
  id?: string;
101
109
  /** An optional call-to-action link. */
102
110
  link?: {
103
111
  /** Link target (internal route or external URL). */
104
112
  href: string;
105
- /** Link text. */
106
- text: string;
113
+ /** Link text, or a map of locale code to text. */
114
+ text: LocalizableLabel;
107
115
  };
108
116
  };
109
117
 
118
+ /** Defaults for hand-written endpoint pages, the ones with `api` frontmatter. */
119
+ export interface ApiConfig {
120
+ /** How requests authenticate, unless a page sets `authMethod`. Defaults to none. */
121
+ auth?: {
122
+ method: "bearer" | "basic" | "key" | "none";
123
+ /** The header an API key goes in. Defaults to `x-api-key`. */
124
+ name?: string;
125
+ };
126
+ /**
127
+ * The Try it panel: `false` hides it, and `{ proxy }` sends requests through
128
+ * a CORS proxy, a URL or `true` for the built-in `/_api-proxy` route (server
129
+ * output only). Defaults to `true`, sending directly.
130
+ */
131
+ playground?: PlaygroundOptions;
132
+ /** The base URL an `api` path joins, like `https://api.acme.com/v1`. */
133
+ server?: string;
134
+ }
135
+
136
+ /** A link in the footer's row. */
137
+ export interface FooterLink {
138
+ /** Link target (internal route or external URL). An external href opens in a new tab. */
139
+ href: string;
140
+ /** Link text, or a map of locale code to text. */
141
+ label: LocalizableLabel;
142
+ }
143
+
144
+ /**
145
+ * The site footer, below the content on every page: a row of links on one
146
+ * side, and social profile icons on the other.
147
+ */
148
+ export interface FooterConfig {
149
+ /** Links in one row, left to right. */
150
+ links?: FooterLink[];
151
+ /**
152
+ * Social profiles, platform to URL, shown as icons in the order written:
153
+ * `{ github: "https://github.com/acme", x: "https://x.com/acme" }`.
154
+ */
155
+ socials?: Partial<Record<FooterSocial, string>>;
156
+ }
157
+
110
158
  /**
111
159
  * Where content lives and how it's discovered. `root`/`include`/`exclude` are
112
160
  * zero-config shorthand for a single `filesystem()` source; set `sources` to
@@ -203,7 +251,8 @@ export interface ContentTypeConfig {
203
251
  // ---------------------------------------------------------------------------
204
252
 
205
253
  /**
206
- * A header label, optionally per locale: a plain string, or a map of locale
254
+ * A label, optionally per locale (header tabs and links, the banner, the
255
+ * footer): a plain string, or a map of locale
207
256
  * code to label (`{ en: "Docs", ja: "ドキュメント" }`). The active locale's
208
257
  * entry wins, then the default locale's, then the map's first entry.
209
258
  */
@@ -286,8 +335,8 @@ export interface FeaturedLink {
286
335
  href: string;
287
336
  /** Lucide icon name shown beside the label. */
288
337
  icon?: string;
289
- /** Link label. */
290
- label: string;
338
+ /** Link label, or a map of locale code to label. */
339
+ label: LocalizableLabel;
291
340
  }
292
341
 
293
342
  /**
@@ -312,8 +361,8 @@ export type SidebarConfig =
312
361
  export interface HeaderAction {
313
362
  /** Link target. An external href opens in a new tab. */
314
363
  href: string;
315
- /** Link label. */
316
- label: string;
364
+ /** Link label, or a map of locale code to label. */
365
+ label: LocalizableLabel;
317
366
  }
318
367
 
319
368
  /** Header, sidebar, tabs, and switcher configuration. */
@@ -325,7 +374,7 @@ export interface NavigationConfig {
325
374
  /** Pinned links shown above the generated sidebar sections. */
326
375
  featured?: FeaturedLink[];
327
376
  /**
328
- * The GitHub link in the header. `true` derives it from `github` (the
377
+ * The GitHub link in the footer. `true` derives it from `github` (the
329
378
  * default), `false` hides it, and an absolute URL points it anywhere on
330
379
  * GitHub — an organization, say, when the docs repo itself is private.
331
380
  */
@@ -520,6 +569,13 @@ export interface AssistantRetrievalConfig {
520
569
 
521
570
  /** The chat assistant. */
522
571
  export interface AssistantConfig {
572
+ /**
573
+ * A bot check from `blume/captcha` — `turnstile({ siteKey })` or
574
+ * `hcaptcha({ siteKey })`. The panel sends a token with each question and
575
+ * the generated route verifies it (with `TURNSTILE_SECRET_KEY` or
576
+ * `HCAPTCHA_SECRET_KEY`) before the model runs.
577
+ */
578
+ captcha?: CaptchaAdapter;
523
579
  /**
524
580
  * Origins allowed to call the generated endpoint from another site — a
525
581
  * marketing page that embeds an ask box, for example — or `"*"` to allow
@@ -548,10 +604,10 @@ export interface AssistantConfig {
548
604
  instructions?: string;
549
605
  /**
550
606
  * Which backend answers: the descriptor an adapter factory returns —
551
- * `gateway({ model })`, `openrouter({ model, reasoning })`,
552
- * `llmgateway({ model })`, `inkeep({ model })`, or
553
- * `openaiCompatible({ baseUrl, name, model, apiKeyEnv })`, all exported
554
- * from `blume/ai`. Each adapter owns its model, key env var, reasoning
607
+ * `openai({ model, baseUrl })`, `anthropic({ model })`,
608
+ * `gemini({ model })`, `grok({ model })`, `gateway({ model })`,
609
+ * `openrouter({ model, reasoning })`, `llmgateway({ model })`, or
610
+ * `inkeep({ model })`, all exported from `blume/ai`. Each adapter owns its model, key env var, reasoning
555
611
  * mapping, and `providerOptions` passthrough. Defaults to
556
612
  * `gateway({ model: "openai/gpt-5.5" })`.
557
613
  */
@@ -562,8 +618,23 @@ export interface AssistantConfig {
562
618
  * backend — at the cost of recall. Defaults keep the built-in behavior.
563
619
  */
564
620
  retrieval?: AssistantRetrievalConfig;
621
+ /**
622
+ * A Contact support link in the panel once there's a conversation: a
623
+ * `mailto:` address starts an email with the conversation as its body; a
624
+ * URL or root-relative path gets the conversation's `thread` id, which the
625
+ * assistant's analytics events carry too.
626
+ */
627
+ support?: string;
565
628
  /** Starter prompts shown before the first question. */
566
629
  suggestions?: AssistantSuggestion[];
630
+ /**
631
+ * Let the model search the docs and read whole pages itself, over several
632
+ * steps, instead of answering only from the excerpts retrieved up front.
633
+ * Defaults to `true`, except for `openai()` with a `baseUrl`, whose model
634
+ * may not support tool calling. `inkeep()` does its own retrieval and
635
+ * ignores it.
636
+ */
637
+ tools?: boolean;
567
638
  }
568
639
 
569
640
  /** What the AI Catalog (ARD) manifest carries. */
@@ -693,6 +764,12 @@ export interface I18nConfig {
693
764
  locales: LocaleConfigInput[];
694
765
  /** `dir`: locale directories (`fr/page.mdx`). `dot`: filename suffix (`page.fr.mdx`). */
695
766
  parser?: "dir" | "dot";
767
+ /**
768
+ * Send a visitor who lands on the default language's home page to the home
769
+ * page in their browser's preferred language, until they pick a language
770
+ * with the switcher. Defaults to `false`.
771
+ */
772
+ routeByBrowserLanguage?: boolean;
696
773
  /**
697
774
  * Per-locale UI string overrides, e.g.
698
775
  * `{ fr: { search: { button: "Rechercher" } } }`.
@@ -802,11 +879,19 @@ type RedirectStatus = RedirectStatusPermanent | RedirectStatusTemporary;
802
879
 
803
880
  /** A URL redirect rule. */
804
881
  export interface RedirectConfig {
805
- /** Path to redirect from. */
882
+ /**
883
+ * Path to redirect from: an exact path, or a pattern. `:name` matches one
884
+ * segment, `:name*` as the last segment the rest of the path
885
+ * (`/beta/:slug*`), and `*` ending a segment the rest from there
886
+ * (`/old/article-*`).
887
+ */
806
888
  from: string;
807
889
  /** HTTP status. Defaults to `301`. */
808
890
  status?: RedirectStatus;
809
- /** Path or URL to redirect to. */
891
+ /**
892
+ * Path or URL to redirect to. Reads `from`'s captures as `/:name` (or `*`
893
+ * for what `*` matched): `/v2/:slug*`.
894
+ */
810
895
  to: string;
811
896
  }
812
897
 
@@ -890,6 +975,13 @@ export interface AgentsConfig {
890
975
  markdownComponents?: Record<string, ComponentMarkdown>;
891
976
  /** Expose the docs as an MCP server for agents. */
892
977
  mcp?: McpConfig;
978
+ /**
979
+ * Generate the site's own agent skill: a `SKILL.md` named after the site,
980
+ * built from its navigation and page descriptions, served at `/skill.md`
981
+ * and in the skills discovery index. Needs `deployment.site`. A skill in
982
+ * `agents.skills` with the same name replaces it. Defaults to `true`.
983
+ */
984
+ skillMd?: boolean;
893
985
  /**
894
986
  * Publish Agent Skills for discovery: a directory (resolved against the
895
987
  * project root) whose subdirectories each hold a `SKILL.md`. Skills are
@@ -958,13 +1050,15 @@ export interface OgConfig {
958
1050
  */
959
1051
  enabled?: boolean;
960
1052
  /**
961
- * Fonts for the generated card, extending Takumi's Latin-only default so
962
- * non-Latin titles (CJK, and so on) render instead of tofu. A bare string is
963
- * a Google Fonts family fetched at build; the name-only object form pins
964
- * weights (`700`, `[400, 700]`, or a `"100..900"` variable range) and
965
- * styles; the `src` form reads a local font file from the project instead.
966
- * When omitted and `theme.fonts` is explicitly configured, the theme's
967
- * display and body fonts are used automatically — pass `[]` to opt out.
1053
+ * Fonts for the generated card, replacing the default stack: Takumi's
1054
+ * Latin-only built-in font plus a Noto fallback per script, which a card
1055
+ * fetches only when its text needs one. A bare string is a Google Fonts
1056
+ * family fetched at build; the name-only object form pins weights (`700`,
1057
+ * `[400, 700]`, or a `"100..900"` variable range) and styles; the `src`
1058
+ * form reads a local font file from the project instead. When omitted and
1059
+ * `theme.fonts` is explicitly configured, the theme's display and body
1060
+ * fonts are used automatically, ahead of the fallbacks — pass `[]` to opt
1061
+ * out of both.
968
1062
  */
969
1063
  fonts?: (
970
1064
  | string
@@ -1068,6 +1162,23 @@ export interface SoftwareConfig {
1068
1162
 
1069
1163
  /** Discoverability: OG images, feeds, sitemap, robots, and structured data. */
1070
1164
  export interface SeoConfig {
1165
+ /**
1166
+ * Meta tags written into every page's head, name to content: site
1167
+ * verification tokens, `theme-color`, an app banner, and anything else
1168
+ * Blume has no setting for. `og:*`, `fb:*`, and `article:*` tags render
1169
+ * with `property`, the rest with `name`. A tag Blume writes itself
1170
+ * (`description`, `robots`, `og:image`, `twitter:card`, …) is refused.
1171
+ *
1172
+ * ```ts
1173
+ * seo: {
1174
+ * metatags: {
1175
+ * "google-site-verification": "abc123",
1176
+ * "theme-color": "#0b5fff",
1177
+ * },
1178
+ * }
1179
+ * ```
1180
+ */
1181
+ metatags?: Record<string, string>;
1071
1182
  /** Per-page Open Graph image generation. */
1072
1183
  og?: OgConfig;
1073
1184
  /**
@@ -1239,6 +1350,37 @@ export type ExportConfig =
1239
1350
  pdf?: boolean;
1240
1351
  };
1241
1352
 
1353
+ /** Page feedback: the rating, and an optional written comment after it. */
1354
+ export interface FeedbackConfig {
1355
+ /**
1356
+ * After the rating, offer a box to say more. The comment is sent as a
1357
+ * `feedback_comment` event through every analytics adapter with an event
1358
+ * API. Defaults to `false`.
1359
+ */
1360
+ comments?: boolean;
1361
+ /** Show the rating. Defaults to `true`. */
1362
+ enabled?: boolean;
1363
+ }
1364
+
1365
+ /**
1366
+ * "Listen to this page". `true` reads pages aloud with the reader's browser
1367
+ * voices (no key, any host). The object form's `provider` generates neural
1368
+ * audio at build instead, one cached clip per sentence, and falls back to
1369
+ * browser voices where no clips exist. Defaults to `false`.
1370
+ */
1371
+ export type NarrationConfig =
1372
+ | boolean
1373
+ | {
1374
+ /** Show the player. Defaults to `true` in the object form. */
1375
+ enabled?: boolean;
1376
+ /**
1377
+ * Generate audio at build with a speech model:
1378
+ * `gateway({ model: "openai/tts-1-hd", voice: "alloy" })` from
1379
+ * `blume/ai`. Without it, pages are read with browser voices.
1380
+ */
1381
+ provider?: AssistantGatewayAdapter;
1382
+ };
1383
+
1242
1384
  /**
1243
1385
  * Opt-in custom frontmatter keys. Page frontmatter is strictly validated —
1244
1386
  * an unknown key fails the build so typos are caught — and `extend` carves
@@ -1333,6 +1475,8 @@ export interface BlumeConfig {
1333
1475
  agents?: AgentsConfig;
1334
1476
  /** Model-facing features: the assistant and the "Open in chat" action. */
1335
1477
  ai?: AiConfig;
1478
+ /** Defaults for hand-written endpoint pages (`api` frontmatter). */
1479
+ api?: ApiConfig;
1336
1480
  /**
1337
1481
  * Analytics adapters from `blume/analytics`, emitted into `<head>` of every
1338
1482
  * production page in this order: `[posthog({ key }), vercel(),
@@ -1351,6 +1495,14 @@ export interface BlumeConfig {
1351
1495
  * compose: with both set, a page lands at `{deployment.base}/{basePath}/page`.
1352
1496
  */
1353
1497
  basePath?: string;
1498
+ /**
1499
+ * Ask readers before analytics runs, with an adapter from `blume/consent`:
1500
+ * `native()` for Blume's own banner, or a hosted consent manager
1501
+ * (`osano({ customerId, configId })`, `ethyca({ privacyCenter })`). Every
1502
+ * `analytics` adapter waits until the reader allows analytics. Unset runs
1503
+ * analytics as it loads.
1504
+ */
1505
+ consent?: ConsentAdapter;
1354
1506
  /** Where content lives and how it's discovered. */
1355
1507
  content?: ContentConfig;
1356
1508
  /**
@@ -1374,8 +1526,17 @@ export interface BlumeConfig {
1374
1526
  examples?: string | ExamplesConfig;
1375
1527
  /** Reader-facing PDF/EPUB export actions. Defaults to `false`. */
1376
1528
  export?: ExportConfig;
1377
- /** Show the per-page "Was this helpful?" widget. Defaults to `true`. */
1378
- feedback?: boolean;
1529
+ /**
1530
+ * The "Was this page helpful?" rating at the foot of each page. On by
1531
+ * default; `false` hides it. `{ comments: true }` also asks for a written
1532
+ * comment after the rating, sent through your analytics adapters.
1533
+ */
1534
+ feedback?: boolean | FeedbackConfig;
1535
+ /**
1536
+ * The site footer: social profile icons and up to four link columns. Unset,
1537
+ * the site has no footer.
1538
+ */
1539
+ footer?: FooterConfig;
1379
1540
  /** Opt-in custom frontmatter keys, validated by schemas you supply. */
1380
1541
  frontmatter?: FrontmatterConfig;
1381
1542
  /** Source repository (Edit-this-page links and the header repo link). */
@@ -1392,8 +1553,17 @@ export interface BlumeConfig {
1392
1553
  logo?: LogoConfig;
1393
1554
  /** Markdown / MDX rendering behavior. */
1394
1555
  markdown?: MarkdownConfig;
1556
+ /** "Listen to this page" narration. Defaults to `false`. */
1557
+ narration?: NarrationConfig;
1395
1558
  /** Header, sidebar, tabs, and switchers. */
1396
1559
  navigation?: NavigationConfig;
1560
+ /**
1561
+ * Limit how often one reader (by IP address) can call the server routes —
1562
+ * the assistant, the API playground proxy, server-side search — with an
1563
+ * adapter from `blume/ratelimit`: `memory()` (the default, 30 requests per
1564
+ * 10 minutes), `upstash()`, or `cloudflare()`. `false` turns it off.
1565
+ */
1566
+ rateLimit?: false | RateLimitAdapter;
1397
1567
  /** React island behavior (compiler auto-memoization). */
1398
1568
  react?: ReactConfig;
1399
1569
  /** URL redirect rules. */
@@ -1414,6 +1584,12 @@ export interface BlumeConfig {
1414
1584
  title?: string;
1415
1585
  /** On-page table of contents. Defaults to on (H2–H3). */
1416
1586
  toc?: TocConfig;
1587
+ /**
1588
+ * Content variables: `{{name}}` in a page reads the value, in prose, code,
1589
+ * and links alike. Names take letters, digits, `_`, and `-`; an undefined
1590
+ * name in prose fails the build. Defaults to none.
1591
+ */
1592
+ variables?: Record<string, string>;
1417
1593
  /** Docs versioning (opt-in frozen snapshots with a version switcher). */
1418
1594
  versions?: VersionsConfig;
1419
1595
  }
package/src/core/data.ts CHANGED
@@ -1,8 +1,10 @@
1
+ import type { CaptchaSettings } from "../captcha/schema.ts";
2
+ import type { EndpointAuth } from "../components/content/api-page.ts";
1
3
  import type { SearchAdapterKind } from "../search/adapters/registry.ts";
2
4
  import type { StructuredDataIdentity } from "../seo/jsonld.ts";
3
5
  import type { FontHead } from "../theme/fonts.ts";
4
6
  import type { UIStrings } from "./i18n-ui.ts";
5
- import type { ResolvedConfig } from "./schema.ts";
7
+ import type { LocalizableLabel, ResolvedConfig } from "./schema.ts";
6
8
  import type { Navigation, RouteAlternate, VersionAlternate } from "./types.ts";
7
9
 
8
10
  /**
@@ -42,10 +44,14 @@ export interface BlumeFavicon {
42
44
  dark?: { href: string; type?: string };
43
45
  }
44
46
 
45
- /** Announcement banner, normalized from its config (string shorthand or object). */
47
+ /**
48
+ * Announcement banner, normalized from its config (string shorthand or
49
+ * object). `content` and the link's `text` may be per-locale maps, resolved
50
+ * when the banner renders (see `core/localizable.ts`).
51
+ */
46
52
  export interface BlumeBanner {
47
- content: string;
48
- link?: { href: string; text: string };
53
+ content: LocalizableLabel;
54
+ link?: { href: string; text: LocalizableLabel };
49
55
  dismissible: boolean;
50
56
  /** Dismissal key: the configured id, else the content itself. */
51
57
  key: string;
@@ -71,6 +77,8 @@ export interface BlumeDataI18n {
71
77
  fallbackLocale: string | null;
72
78
  hideDefaultLocalePrefix: boolean;
73
79
  locales: BlumeDataLocale[];
80
+ /** Send visitors from the default home page to their browser's language. */
81
+ routeByBrowserLanguage: boolean;
74
82
  }
75
83
 
76
84
  /** A single content route, with the metadata custom pages can read. */
@@ -124,9 +132,23 @@ export interface BlumeDataConfig {
124
132
  appleIcon: BlumeFavicon | null;
125
133
  /** The assistant's empty-state suggestions, or `null` when the assistant is off. */
126
134
  assistant: {
135
+ /** The bot check's public settings, or `null` without one. */
136
+ captcha: CaptchaSettings | null;
127
137
  endpoint: string | null;
128
138
  suggestions: NonNullable<ResolvedConfig["ai"]["assistant"]>["suggestions"];
139
+ /** The Contact support link (`ai.assistant.support`), or `null`. */
140
+ support: string | null;
129
141
  } | null;
142
+ /**
143
+ * Defaults for hand-written endpoint pages (`api` frontmatter): the server a
144
+ * path joins, the default auth, and the playground, its `proxy` resolved to
145
+ * the URL sends go through (the built-in route under `basePath`) or `false`.
146
+ */
147
+ api: {
148
+ auth?: EndpointAuth;
149
+ playground: { enabled: boolean; proxy: string | false };
150
+ server?: string;
151
+ };
130
152
  banner: BlumeBanner | null;
131
153
  /** Site-wide route mount point, normalized to `""` or `/seg` (see config). */
132
154
  basePath: string;
@@ -134,6 +156,11 @@ export interface BlumeDataConfig {
134
156
  codeThemes: ResolvedConfig["markdown"]["code"]["theme"];
135
157
  /** `markdown.code.wrap`: wrap long code lines instead of scrolling. */
136
158
  codeWrap: boolean;
159
+ /**
160
+ * The consent adapter's descriptor, or `null` without one. When set, the
161
+ * layouts hold analytics until the reader allows it.
162
+ */
163
+ consent: ResolvedConfig["consent"];
137
164
  /** `dateFormat`: `Intl.DateTimeFormat` options for the date stamps. */
138
165
  dateFormat: ResolvedConfig["dateFormat"];
139
166
  description: string | undefined;
@@ -156,7 +183,12 @@ export interface BlumeDataConfig {
156
183
  sitemap: boolean;
157
184
  };
158
185
  favicon: BlumeFavicon;
186
+ /** Whether pages end with the "Was this page helpful?" rating. */
159
187
  feedback: boolean;
188
+ /** Whether the rating asks for a written comment after it (`feedback.comments`). */
189
+ feedbackComments: boolean;
190
+ /** `footer`: social profile icons and link columns, or `null` when unset. */
191
+ footer: ResolvedConfig["footer"] | null;
160
192
  /**
161
193
  * Repo coordinates for content components that address the API or build
162
194
  * their own repo links (`<GithubInfo>`, the OG card's footer slug), carrying
@@ -176,6 +208,14 @@ export interface BlumeDataConfig {
176
208
  logo: BlumeLogo | null;
177
209
  /** Hosted MCP server, or `null` when MCP is off. */
178
210
  mcp: { name: string; route: string } | null;
211
+ /** `seo.metatags`: the site's own tags for every page's head, or `null`. */
212
+ metatags: Record<string, string> | null;
213
+ /**
214
+ * "Listen to this page": `generated` when a `narration.provider` makes
215
+ * `blume build` write audio clips the player should look for, else the
216
+ * player reads with browser voices. `null` when narration is off.
217
+ */
218
+ narration: { generated: boolean } | null;
179
219
  /**
180
220
  * Open Graph image generation. Card fonts are baked into the generated OG
181
221
  * endpoint (they can carry absolute build-machine paths) and deliberately
@@ -24,6 +24,7 @@ const DOCS_BASE = "https://useblume.dev";
24
24
  const DOCS_DEPLOYMENT = "/docs/deployment";
25
25
  const DOCS_CLI_VALIDATE = "/docs/cli/validate";
26
26
  const DOCS_CONTENT_SOURCES = "/docs/content/sources";
27
+ const DOCS_CONTENT_SOURCES_OBSIDIAN = "/docs/content/sources/obsidian";
27
28
  const DOCS_CONTENT_NAVIGATION = "/docs/content/navigation";
28
29
  const DOCS_CONTENT_INCLUDES = "/docs/content/includes";
29
30
 
@@ -69,10 +70,12 @@ const DOCS_PATHS = new Map(
69
70
  BLUME_TRANSLATE_MISSING: "/docs/cli/translate",
70
71
  BLUME_TRANSLATE_STALE: "/docs/cli/translate",
71
72
  BLUME_UNKNOWN_COMPONENT: "/docs/configuration/customization",
73
+ BLUME_UNKNOWN_DIRECTIVE: "/docs/content/syntax",
72
74
  BLUME_UNKNOWN_ICON: DOCS_CONTENT_NAVIGATION,
73
75
  BLUME_UNKNOWN_OPTION: "/docs/cli",
74
- BLUME_WIKILINK_AMBIGUOUS: DOCS_CONTENT_SOURCES,
75
- BLUME_WIKILINK_UNRESOLVED: DOCS_CONTENT_SOURCES,
76
+ BLUME_UNLOADABLE_FILE_NAME: "/docs/content",
77
+ BLUME_WIKILINK_AMBIGUOUS: DOCS_CONTENT_SOURCES_OBSIDIAN,
78
+ BLUME_WIKILINK_UNRESOLVED: DOCS_CONTENT_SOURCES_OBSIDIAN,
76
79
  BLUME_YARN_PNP: "/docs/quickstart",
77
80
  })
78
81
  );
@@ -0,0 +1,99 @@
1
+ import type { Nodes } from "mdast";
2
+ import { mdxToMdast } from "satteri";
3
+
4
+ import {
5
+ CALLOUT_ALIASES,
6
+ CALLOUT_TYPES,
7
+ calloutTypeFor,
8
+ } from "../markdown/directives.ts";
9
+ import { MDX_BODY_FEATURES } from "../markdown/features.ts";
10
+ import { strippedLineOffset } from "./sources/normalize.ts";
11
+ import type { SourceEntry } from "./sources/types.ts";
12
+ import type { Diagnostic } from "./types.ts";
13
+
14
+ // A line that may open a container directive: a colon fence and a name, after
15
+ // any quote or list indentation. A page is parsed only when one of these
16
+ // names something other than a callout, so pages without one cost a scan.
17
+ const CONTAINER_OPENING = /^[\t >]*:{3,}(?<name>[a-z][\w-]*)/gimu;
18
+
19
+ const codeList = (names: Iterable<string>): string =>
20
+ [...names].map((name) => `\`${name}\``).join(", ");
21
+
22
+ const CALLOUT_NAMES = `${codeList(CALLOUT_TYPES)} (or the aliases ${codeList(Object.keys(CALLOUT_ALIASES))})`;
23
+
24
+ /** A container directive that isn't a callout, and its line in `text`. */
25
+ interface UnknownContainer {
26
+ line: number;
27
+ name: string;
28
+ }
29
+
30
+ /**
31
+ * Every container directive in an `.mdx` body whose name isn't a callout, in
32
+ * source order. The body is parsed as the renderer reads it, so a fence in a
33
+ * code block or a `::: name` that isn't a directive at all never counts. A
34
+ * body MDX can't parse fails to render anyway, with its own error.
35
+ */
36
+ const unknownContainers = (text: string): UnknownContainer[] => {
37
+ const named = [...text.matchAll(CONTAINER_OPENING)].some(
38
+ (match) => calloutTypeFor(match.groups?.name ?? "") === null
39
+ );
40
+ if (!named) {
41
+ return [];
42
+ }
43
+ let tree: Nodes;
44
+ try {
45
+ tree = mdxToMdast(text, { features: MDX_BODY_FEATURES });
46
+ } catch {
47
+ return [];
48
+ }
49
+ const found: UnknownContainer[] = [];
50
+ const walk = (node: Nodes): void => {
51
+ if (
52
+ node.type === "containerDirective" &&
53
+ calloutTypeFor(node.name) === null
54
+ ) {
55
+ found.push({ line: node.position?.start.line ?? 1, name: node.name });
56
+ }
57
+ if ("children" in node) {
58
+ for (const child of node.children) {
59
+ walk(child);
60
+ }
61
+ }
62
+ };
63
+ walk(tree);
64
+ return found;
65
+ };
66
+
67
+ /**
68
+ * Warn about each `:::name` container in an `.mdx` entry that isn't a callout.
69
+ * The page keeps its content — the body renders between the literal `:::`
70
+ * lines (see `markdown/directives.ts`) — but a typo like `:::warnig`, or a
71
+ * `:::details` carried over from another docs tool, should read as the
72
+ * mistake it is rather than as a finished page. Lines point into the file
73
+ * the author wrote, a partial's own file for a container an `<include>`
74
+ * brought in.
75
+ */
76
+ export const unknownDirectiveDiagnostics = (
77
+ entry: SourceEntry,
78
+ sourceName: string
79
+ ): Diagnostic[] => {
80
+ if (entry.body.format !== "mdx") {
81
+ return [];
82
+ }
83
+ const page = entry.sourcePath ?? `${sourceName}:${entry.ref}`;
84
+ const offset =
85
+ entry.bodyLineOffset ?? strippedLineOffset(entry.raw, entry.body.text);
86
+ return unknownContainers(entry.expanded?.text ?? entry.body.text).map(
87
+ ({ line, name }) => {
88
+ const origin = entry.expanded?.origins[line - 1];
89
+ return {
90
+ code: "BLUME_UNKNOWN_DIRECTIVE",
91
+ file: origin?.file ?? page,
92
+ line: origin?.line ?? line + offset,
93
+ message: `\`:::${name}\` isn't a callout type, so the page shows its \`:::\` lines as written around its content.`,
94
+ severity: "warning",
95
+ suggestion: `Use a callout type — ${CALLOUT_NAMES} — or remove the \`:::\` lines to keep the content as plain prose.`,
96
+ };
97
+ }
98
+ );
99
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The social platforms `footer.socials` links to, each shown by its brand
3
+ * icon: Mintlify's set, without its aliases (`twitter` and `x-twitter` are
4
+ * `x`, `earth-americas` is `website`).
5
+ */
6
+ export const FOOTER_SOCIALS = [
7
+ "bluesky",
8
+ "discord",
9
+ "facebook",
10
+ "github",
11
+ "hacker-news",
12
+ "instagram",
13
+ "linkedin",
14
+ "medium",
15
+ "podcast",
16
+ "reddit",
17
+ "slack",
18
+ "telegram",
19
+ "threads",
20
+ "website",
21
+ "x",
22
+ "youtube",
23
+ ] as const;
24
+
25
+ /** A platform `footer.socials` links to. */
26
+ export type FooterSocial = (typeof FOOTER_SOCIALS)[number];