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
package/src/ai/cors.ts CHANGED
@@ -61,6 +61,8 @@ export const preflightResponse = (
61
61
 
62
62
  /** The slice of Astro's `APIContext` the wrapped handler reads. */
63
63
  interface RequestContext {
64
+ /** The reader's address, which the route's rate limit keys on. */
65
+ readonly clientAddress?: string;
64
66
  request: Request;
65
67
  }
66
68
 
package/src/ai/index.ts CHANGED
@@ -20,23 +20,35 @@
20
20
  * nothing here runs at request time.
21
21
  */
22
22
  export {
23
+ anthropic,
23
24
  gateway,
25
+ gemini,
26
+ grok,
24
27
  inkeep,
25
28
  llmgateway,
29
+ openai,
26
30
  openaiCompatible,
27
31
  openrouter,
28
32
  } from "./ask.ts";
29
33
  export type {
30
34
  AssistantAdapter,
31
35
  AssistantAdapterOptions,
36
+ AssistantAnthropicAdapter,
37
+ AssistantAnthropicOptions,
32
38
  AssistantGatewayAdapter,
33
39
  AssistantGatewayOptions,
40
+ AssistantGeminiAdapter,
41
+ AssistantGeminiOptions,
42
+ AssistantGrokAdapter,
43
+ AssistantGrokOptions,
34
44
  AssistantInkeepAdapter,
35
45
  AssistantInkeepOptions,
36
46
  AssistantLlmGatewayAdapter,
37
47
  AssistantLlmGatewayOptions,
48
+ AssistantOpenAIAdapter,
38
49
  AssistantOpenAICompatibleAdapter,
39
50
  AssistantOpenAICompatibleOptions,
51
+ AssistantOpenAIOptions,
40
52
  AssistantOpenRouterAdapter,
41
53
  AssistantOpenRouterOptions,
42
54
  AssistantProviderOptions,
@@ -33,24 +33,33 @@ import { OPENAPI_PATH } from "./api/paths.ts";
33
33
  * headers. Targets are
34
34
  * root-relative under `deployment.base` — RFC 8288 resolves them against the
35
35
  * request URL. Returns null when nothing is advertisable.
36
+ *
37
+ * `surface` is where the header is sent. A deployed site (`"build"`) serves
38
+ * every target. The dev server (`"dev"`) serves the routes — the JSON API's
39
+ * OpenAPI document and the Markdown mirror — but not the files `blume build`
40
+ * writes after the build (the API and AI catalogs, `agent-readability.json`,
41
+ * `llms.txt`), so its header leaves those out rather than point agents at
42
+ * 404s.
36
43
  */
37
44
  export const buildHomeLinkHeader = (
38
45
  config: ResolvedConfig,
39
- routePaths: readonly string[]
46
+ routePaths: readonly string[],
47
+ surface: "build" | "dev" = "build"
40
48
  ): string | null => {
41
49
  const deployBase = normalizeBasePath(config.deployment.options.base);
50
+ const artifacts = surface === "build";
42
51
  const links: string[] = [];
43
52
  // RFC 9727 §3: the api-catalog relation is how a homepage advertises the
44
53
  // well-known catalog. Its type carries the RFC 9727 profile, whose quotes
45
54
  // are escaped inside the quoted `type` value (RFC 8288 quoted-string).
46
- if (hasApiCatalog(config)) {
55
+ if (artifacts && hasApiCatalog(config)) {
47
56
  links.push(
48
57
  `<${deployBase}${API_CATALOG_PATH}>; rel="api-catalog"; type="${API_CATALOG_TYPE.replaceAll('"', String.raw`\"`)}"`
49
58
  );
50
59
  }
51
60
  // The ai-catalog spec's own relation for its well-known document, the
52
61
  // header form of the `<link rel="ai-catalog">` every page carries.
53
- if (hasAiCatalog(config)) {
62
+ if (artifacts && hasAiCatalog(config)) {
54
63
  links.push(
55
64
  `<${deployBase}${AI_CATALOG_PATH}>; rel="ai-catalog"; type="${AI_CATALOG_TYPE}"`
56
65
  );
@@ -62,12 +71,12 @@ export const buildHomeLinkHeader = (
62
71
  `<${deployBase}${OPENAPI_PATH}>; rel="service-desc"; type="application/json"`
63
72
  );
64
73
  }
65
- if (config.agents.agentReadability) {
74
+ if (artifacts && config.agents.agentReadability) {
66
75
  links.push(
67
76
  `<${deployBase}/agent-readability.json>; rel="describedby"; type="application/json"`
68
77
  );
69
78
  }
70
- if (config.agents.llmsTxt.enabled) {
79
+ if (artifacts && config.agents.llmsTxt.enabled) {
71
80
  links.push(
72
81
  `<${deployBase}/llms.txt>; rel="describedby"; type="text/plain"`
73
82
  );
package/src/ai/llms.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { normalizeBasePath, withBasePath } from "../core/base-path.ts";
1
+ import { mountBasePath, normalizeBasePath } from "../core/base-path.ts";
2
2
  import { rewriteRelativeImages } from "../core/content-assets.ts";
3
3
  import matter from "../core/frontmatter.ts";
4
4
  import type { BlumeProject } from "../core/project-graph.ts";
@@ -12,19 +12,31 @@ import { API_PAGES_PATH, OPENAPI_PATH } from "./api/paths.ts";
12
12
  import { downlevelComponents } from "./component-markdown.ts";
13
13
  import { relativeLinkRewriter } from "./relative-links.ts";
14
14
  import { projectComponentSerializers } from "./serializers.ts";
15
- import { AGENT_SKILLS_DIR, AGENT_SKILLS_INDEX_PATH } from "./skills.ts";
15
+ import {
16
+ AGENT_SKILLS_DIR,
17
+ AGENT_SKILLS_INDEX_PATH,
18
+ servesSkillsIndex,
19
+ } from "./skills.ts";
16
20
  import type { SkillArtifact } from "./skills.ts";
17
21
  import { applyAgentVisibility } from "./visibility.ts";
18
22
 
19
23
  // Routes carry `basePath`; a `deployment.base` subdirectory is layered on top —
20
- // with or without a `site` (the mcp.json convention) — so the emitted URL
21
- // matches where the page is served. Encoded like the sitemap: a route with
22
- // spaces or non-ASCII must still yield a valid Markdown link.
24
+ // with or without a `site` (the mcp.json convention), and even over a route
25
+ // that starts with the base's own name — so the emitted URL matches where the
26
+ // page is served. Encoded like the sitemap: a route with spaces or non-ASCII
27
+ // must still yield a valid Markdown link.
23
28
  const pageUrl = (route: string, site?: string, base = ""): string => {
24
- const path = withBasePath(base, route);
29
+ const path = mountBasePath(base, route);
25
30
  return encodeURI(site ? absoluteUrl(site, path) : path);
26
31
  };
27
32
 
33
+ /**
34
+ * A title as Markdown link text. An unescaped bracket in it — `[Beta] Webhooks`
35
+ * — closes or nests the text early, and the line stops being a link.
36
+ */
37
+ const linkText = (title: string): string =>
38
+ title.replaceAll(/[\\[\]]/gu, String.raw`\$&`);
39
+
28
40
  /** Inputs only the build has: the published skills, collected once per build. */
29
41
  export interface LlmsIndexOptions {
30
42
  /**
@@ -67,7 +79,7 @@ const agentResourceLines = (project: BlumeProject): string[] => {
67
79
  `- [MCP server](${url(config.agents.mcp.route)}): Streamable HTTP Model Context Protocol server with search_docs, get_page, list_pages, and get_navigation tools, plus every page as a resource. Discovery document: ${url("/.well-known/mcp.json")}`
68
80
  );
69
81
  }
70
- if (config.agents.skills) {
82
+ if (servesSkillsIndex(config)) {
71
83
  lines.push(
72
84
  `- [Agent skills](${url(AGENT_SKILLS_INDEX_PATH)}): Agent Skills discovery index of the skills this site publishes.`
73
85
  );
@@ -176,7 +188,7 @@ export const buildLlmsIndex = (
176
188
  const line = (page: PageRecord): string => {
177
189
  seen.add(page.route);
178
190
  const summary = page.description ? `: ${page.description}` : "";
179
- return `- [${page.title}](${pageUrl(page.route, site, base)})${summary}`;
191
+ return `- [${linkText(page.title)}](${pageUrl(page.route, site, base)})${summary}`;
180
192
  };
181
193
 
182
194
  // One nav level -> Markdown blocks: the level's loose pages as a link list,
@@ -259,7 +271,10 @@ export const buildLlmsIndex = (
259
271
  blocks.push(
260
272
  "## RSS Feeds",
261
273
  feeds
262
- .map((feed) => `- [${feed.title}](${pageUrl(feed.path, site, base)})`)
274
+ .map(
275
+ (feed) =>
276
+ `- [${linkText(feed.title)}](${pageUrl(feed.path, site, base)})`
277
+ )
263
278
  .join("\n")
264
279
  );
265
280
  }
@@ -14,6 +14,7 @@ import { downlevelComponents } from "./component-markdown.ts";
14
14
  import { buildLlmsIndex } from "./llms.ts";
15
15
  import { relativeLinkRewriter } from "./relative-links.ts";
16
16
  import { projectComponentSerializers } from "./serializers.ts";
17
+ import { servesSkillsIndex } from "./skills.ts";
17
18
  import { applyAgentVisibility } from "./visibility.ts";
18
19
 
19
20
  /** One route's raw-Markdown variants. */
@@ -115,7 +116,7 @@ export const buildRawMarkdown = async (
115
116
  config: advertisedConfig(project.config, {
116
117
  mcp: servesMcp(project, userPages),
117
118
  // Skills are collected at the end of the build, after this runs.
118
- skills: Boolean(project.config.agents.skills),
119
+ skills: servesSkillsIndex(project.config),
119
120
  }),
120
121
  }),
121
122
  };
@@ -130,6 +130,12 @@ export const buildMcpData = async (project: BlumeProject): Promise<McpData> => {
130
130
  if (doc.facets) {
131
131
  document.facets = doc.facets;
132
132
  }
133
+ if (doc.boost !== undefined) {
134
+ document.boost = doc.boost;
135
+ }
136
+ if (doc.keywords) {
137
+ document.keywords = doc.keywords;
138
+ }
133
139
  return document;
134
140
  }),
135
141
  instructions: config.agents.mcp.instructions,
@@ -1,4 +1,4 @@
1
- import { withBasePath } from "../../core/base-path.ts";
1
+ import { mountBasePath } from "../../core/base-path.ts";
2
2
  import { absoluteUrl, siteRoot } from "../../core/site-url.ts";
3
3
  import { trimChar } from "../../core/trim.ts";
4
4
  import { MCP_TOOLS } from "./tools.ts";
@@ -18,7 +18,7 @@ export interface McpDiscoveryInput {
18
18
  const serverUrl = (input: McpDiscoveryInput): string => {
19
19
  // The endpoint is a generated Astro page, so it's served under
20
20
  // `deployment.base` like every other route (the sitemap/llms.txt convention).
21
- const path = withBasePath(input.base, input.route);
21
+ const path = mountBasePath(input.base, input.route);
22
22
  // Concatenate rather than `new URL(path, site)` — a root-absolute path
23
23
  // would drop the base path of a subpath deployment (`acme.com/docs`).
24
24
  return input.site ? absoluteUrl(input.site, path) : path;
@@ -1,9 +1,9 @@
1
1
  import { z } from "zod";
2
2
 
3
3
  import {
4
+ mountBasePath,
4
5
  normalizeRoute as normalizePageRoute,
5
6
  stripBasePath,
6
- withBasePath,
7
7
  } from "../../core/base-path.ts";
8
8
  import { absoluteUrl } from "../../core/site-url.ts";
9
9
  import { trimEnd } from "../../core/trim.ts";
@@ -244,7 +244,7 @@ export const normalizeRoute = (input: string, data: McpData): string => {
244
244
  export const urlFor = (route: string, data: McpData): string => {
245
245
  // Routes are base-less manifest paths; layer `deployment.base` on top so the
246
246
  // URL matches where the page is served (the sitemap/llms.txt convention).
247
- const path = withBasePath(data.base, route);
247
+ const path = mountBasePath(data.base, route);
248
248
  // Concatenate rather than `new URL(path, site)` — a root-absolute path
249
249
  // would drop the base path of a subpath deployment (`acme.com/docs`).
250
250
  return data.site ? absoluteUrl(data.site, path) : path;
@@ -10,7 +10,7 @@ import {
10
10
  } from "@modelcontextprotocol/sdk/types.js";
11
11
  import { z } from "zod";
12
12
 
13
- import { withBasePath } from "../../core/base-path.ts";
13
+ import { mountBasePath } from "../../core/base-path.ts";
14
14
  import { readCappedText } from "../../core/request-body.ts";
15
15
  import type { McpData } from "./data.ts";
16
16
  import {
@@ -104,7 +104,7 @@ interface PageResource {
104
104
  const resourceUri = (route: string, data: McpData): string =>
105
105
  data.site
106
106
  ? urlFor(route, data)
107
- : `${LOCAL_RESOURCE_SCHEME}${withBasePath(data.base, route)}`;
107
+ : `${LOCAL_RESOURCE_SCHEME}${mountBasePath(data.base, route)}`;
108
108
 
109
109
  /** The `pages` key a resource URI (either form, or a bare route) names. */
110
110
  const resourceRoute = (uri: string, data: McpData): string =>
@@ -1,3 +1,4 @@
1
+ import { mountBasePath, normalizeBasePath } from "../core/base-path.ts";
1
2
  import type { ApiOperationRef, OpenApiData } from "../openapi/model.ts";
2
3
  import { operationOf, specAddresses, specOf } from "../openapi/model.ts";
3
4
  import { asSentence } from "../openapi/sentence.ts";
@@ -20,10 +21,14 @@ const inlineText = (text: string): string =>
20
21
  .replaceAll(/\s+/gu, " ")
21
22
  .replaceAll(/[\\`*_[\]<>~]/gu, String.raw`\$&`);
22
23
 
23
- /** One operation as a link, for the tag listings. */
24
+ /**
25
+ * One operation as a link, for the tag listings. `href` is the operation's
26
+ * served URL: its route under the deployment base.
27
+ */
24
28
  const listItem = (
25
29
  signature: string,
26
- operation: Pick<ApiOperationRef, "deprecated" | "route" | "summary">
30
+ href: string,
31
+ operation: Pick<ApiOperationRef, "deprecated" | "summary">
27
32
  ): string => {
28
33
  const tail = [
29
34
  // Title-like summaries ("Get a flag") need their own period before the
@@ -33,7 +38,7 @@ const listItem = (
33
38
  ]
34
39
  .filter(Boolean)
35
40
  .join(" ");
36
- return `- [${inlineCode(signature)}](${linkDestination(operation.route)})${tail ? ` — ${tail}` : ""}`;
41
+ return `- [${inlineCode(signature)}](${linkDestination(href)})${tail ? ` — ${tail}` : ""}`;
37
42
  };
38
43
 
39
44
  /**
@@ -60,9 +65,16 @@ const listItem = (
60
65
  * endpoint and what it does is the part that was missing altogether.
61
66
  *
62
67
  * `specs` is the parsed `blume:openapi` data — empty when the project has no
63
- * API reference, in which case every serializer declines.
68
+ * API reference, in which case every serializer declines. `deployBase` is the
69
+ * configured `deployment.base`: operation routes carry `basePath` but not it,
70
+ * and the links written here are made after the agent surfaces rebase the
71
+ * page's own links, so they take it here, as the rendered page's do.
64
72
  */
65
- export const openapiComponentSerializers = (specs: OpenApiData) => {
73
+ export const openapiComponentSerializers = (
74
+ specs: OpenApiData,
75
+ deployBase?: string
76
+ ) => {
77
+ const base = normalizeBasePath(deployBase);
66
78
  const spec = (source: EvaluatedValue) =>
67
79
  isString(source) ? specOf(specs, source) : undefined;
68
80
 
@@ -97,7 +109,11 @@ export const openapiComponentSerializers = (specs: OpenApiData) => {
97
109
  const items = Object.values(data.operations)
98
110
  .filter((operation) => operation.tagSlug === tag)
99
111
  .map((operation) =>
100
- listItem(operationSignature(data, operation), operation)
112
+ listItem(
113
+ operationSignature(data, operation),
114
+ mountBasePath(base, operation.route),
115
+ operation
116
+ )
101
117
  );
102
118
  return items.length > 0 ? items.join("\n") : null;
103
119
  },
@@ -118,9 +134,15 @@ export const openapiComponentSerializers = (specs: OpenApiData) => {
118
134
  return null;
119
135
  }
120
136
  const signature = inlineCode(operationSignature(data, operation));
121
- return operation.deprecated
122
- ? `${signature}\n\n**Deprecated.**`
123
- : signature;
137
+ const notes = [
138
+ // An agent reading the page must not take a webhook for an endpoint
139
+ // it can call.
140
+ operation.webhook
141
+ ? "**Webhook.** The API sends this request to your endpoint."
142
+ : "",
143
+ operation.deprecated ? "**Deprecated.**" : "",
144
+ ].filter(Boolean);
145
+ return [signature, ...notes].join("\n\n");
124
146
  },
125
147
  } satisfies Record<string, ComponentMarkdown>;
126
148
  };
@@ -2,9 +2,10 @@ import { basename } from "pathe";
2
2
 
3
3
  import {
4
4
  isInternalPath,
5
+ mountBasePath,
5
6
  normalizeBasePath,
7
+ withAuthoredBasePath,
6
8
  withBasePath,
7
- withComposedBasePath,
8
9
  } from "../core/base-path.ts";
9
10
  import { nextFenceState } from "../core/code-fences.ts";
10
11
  import type { FenceState } from "../core/code-fences.ts";
@@ -16,7 +17,7 @@ import {
16
17
  routeOfLinkedFile,
17
18
  } from "../core/links.ts";
18
19
  import type { RelativeLinkBase } from "../core/links.ts";
19
- import { localizeHref } from "../core/locale-links.ts";
20
+ import { localizeHref, servesRoute } from "../core/locale-links.ts";
20
21
  import type { BlumeProject } from "../core/project-graph.ts";
21
22
  import { extractLinks } from "../core/sources/normalize.ts";
22
23
 
@@ -27,14 +28,16 @@ import { extractLinks } from "../core/sources/normalize.ts";
27
28
  * link lands on `/install`; the rendered page rewrites it to the route it
28
29
  * means (`markdown/relative-links.ts`), and the Markdown an agent reads gets
29
30
  * the same rewrite from the same resolver (`resolveRelativeHref`), so both
30
- * point at one page. Root-relative page links (`[x](/guide)`,
31
- * `<Card href="/guide">`) get what the rendered page gives them too: the
32
- * `deployment.base` + `basePath` prefix (`markdown/base-links.ts`,
33
- * `components/content/base-href.ts`) and, on a page in a prefixed locale,
31
+ * point at one page. Root-relative links (`[x](/guide)`,
32
+ * `<Card href="/guide">`, `![logo](/logo.png)`) get what the rendered page
33
+ * gives them too (`markdown/base-links.ts`,
34
+ * `components/content/base-href.ts`): a page link the `deployment.base` +
35
+ * `basePath` prefix, a public file (`/spec.pdf`) or image the
36
+ * `deployment.base` alone, and, on a page in a prefixed locale, a page link
34
37
  * that locale's copy of the route when it is served
35
- * (`components/layout/LocaleLinks.astro`). Inline links, component `href`s,
36
- * and reference definitions are rewritten; fenced and inline code, images,
37
- * asset links, and external URLs are left as written.
38
+ * (`components/layout/LocaleLinks.astro`). Inline links, images, component
39
+ * `href`s, and reference definitions are rewritten; fenced and inline code,
40
+ * relative images and asset links, and external URLs are left as written.
38
41
  */
39
42
 
40
43
  /** The page a Markdown text was written for. */
@@ -67,13 +70,6 @@ const MAYBE_RELATIVE =
67
70
  const MAYBE_PAGE_LINK =
68
71
  /\]\([\t ]*<?(?![a-z][\d+.a-z-]*:|\/\/|#)|^ {0,3}\[[^\]\n]+\]:[\t ]*<?(?![a-z][\d+.a-z-]*:|\/\/|#)|\shref=["'](?![a-z][\d+.a-z-]*:|\/\/|#)/imu;
69
72
 
70
- /**
71
- * A path whose final segment carries a file extension — a `public/` asset or
72
- * a raw `.md` twin, which the rendered page neither bases nor localizes (see
73
- * `markdown/base-links.ts`).
74
- */
75
- const ASSET_PATH = /\.[\da-z]+$/iu;
76
-
77
73
  interface Splice {
78
74
  column: number;
79
75
  length: number;
@@ -109,18 +105,23 @@ const definitionSplice = (
109
105
  return { column: lead.length + angled, length: target.length, text: route };
110
106
  };
111
107
 
112
- /** Every routed splice in `text`, by 0-based line: links, then definitions. */
108
+ /**
109
+ * Every routed splice in `text`, by 0-based line: links and images, then
110
+ * definitions. An image target goes through `imaged`, everything else through
111
+ * `routed`.
112
+ */
113
113
  const collectSplices = (
114
114
  text: string,
115
115
  lines: readonly string[],
116
- routed: (target: string) => string | undefined
116
+ routed: (target: string) => string | undefined,
117
+ imaged: (target: string) => string | undefined
117
118
  ): Map<number, Splice[]> => {
118
119
  const splices = new Map<number, Splice[]>();
119
120
  const add = (index: number, splice: Splice): void => {
120
121
  splices.set(index, [...(splices.get(index) ?? []), splice]);
121
122
  };
122
123
  for (const link of extractLinks(text)) {
123
- const route = link.image ? undefined : routed(link.target);
124
+ const route = (link.image ? imaged : routed)(link.target);
124
125
  if (route !== undefined) {
125
126
  add(link.line - 1, {
126
127
  column: link.column - 1,
@@ -186,14 +187,19 @@ export const relativeLinkRewriter = (
186
187
  const navPath = navPathBySource.get(sourcePath) ?? basename(sourcePath);
187
188
  const resolveFile = (path: string): string | undefined =>
188
189
  routeOfLinkedFile(fileRoutes, { navPath, sourcePath }, path);
190
+ // A resolved route is one Blume serves, so the deployment base goes on
191
+ // unconditionally — even over a route that starts with the base's name.
189
192
  return (target) => {
190
193
  const route = resolveRelativeHref(target, from, resolveFile, (path) =>
191
194
  routes.has(path)
192
195
  );
193
- return route === undefined ? undefined : withBasePath(deployBase, route);
196
+ return route === undefined ? undefined : mountBasePath(deployBase, route);
194
197
  };
195
198
  };
196
199
 
200
+ /** Whether a page is served at a based, fragment-less path. */
201
+ const servesPage = (route: string): boolean => servesRoute(routes, route);
202
+
197
203
  return (text, page) => {
198
204
  const locale = localeByRoute.get(page.route);
199
205
  // The page's locale moves root links only when it has a URL prefix.
@@ -212,21 +218,31 @@ export const relativeLinkRewriter = (
212
218
  return text;
213
219
  }
214
220
  const relative = relativeRoute(page);
215
- // What the rendered page makes of `/guide`: based, then moved into the
221
+ // What the rendered page makes of `/guide`: based (a public file like
222
+ // `/spec.pdf` under the deployment base alone), then moved into the
216
223
  // page's locale when that route is served.
217
224
  const rooted = (target: string): string | undefined => {
218
- if (ASSET_PATH.test(target.replace(/[#?].*$/u, ""))) {
219
- return undefined;
220
- }
221
- const based = withComposedBasePath(deployBase, basePath, target);
225
+ const based = withAuthoredBasePath(
226
+ deployBase,
227
+ basePath,
228
+ target,
229
+ servesPage
230
+ );
222
231
  const href = localize ? localizeHref(based, localize) : based;
223
232
  return href === target ? undefined : href;
224
233
  };
225
234
  const routed = (target: string): string | undefined =>
226
235
  isInternalPath(target) ? rooted(target) : relative?.(target);
236
+ // An image is always a file: `public/` (or a generated asset endpoint),
237
+ // served under the deployment base but never `basePath`. A relative one
238
+ // is left to `core/content-assets.ts`.
239
+ const imaged = (target: string): string | undefined => {
240
+ const based = withBasePath(deployBase, target);
241
+ return based === target ? undefined : based;
242
+ };
227
243
 
228
244
  const lines = text.split("\n");
229
- const splices = collectSplices(text, lines, routed);
245
+ const splices = collectSplices(text, lines, routed, imaged);
230
246
 
231
247
  return lines
232
248
  .map((line, index) => {
@@ -18,7 +18,8 @@ export const projectComponentSerializers = (
18
18
  ({
19
19
  ...exampleComponentSerializers(project.examples ?? {}),
20
20
  ...openapiComponentSerializers(
21
- project.sources.find(isOpenApiSource)?.openApiData() ?? {}
21
+ project.sources.find(isOpenApiSource)?.openApiData() ?? {},
22
+ project.config.deployment.options.base
22
23
  ),
23
24
  ...project.config.agents.markdownComponents,
24
25
  }) satisfies Record<string, ComponentMarkdown>;