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
@@ -0,0 +1,86 @@
1
+ import { z } from "zod";
2
+
3
+ import type { AdapterDescriptor } from "../core/adapter.ts";
4
+ import { adapterDescriptorSchema } from "../core/adapter.ts";
5
+ import type { HeadScript } from "./head.ts";
6
+
7
+ /** The script OneDollarStats' install snippet loads. */
8
+ export const ONE_DOLLAR_STATS_SCRIPT_SRC =
9
+ "https://assets.onedollarstats.com/stonks.js";
10
+
11
+ /** The options {@link oneDollarStats} checks itself. */
12
+ export interface OneDollarStatsNamedOptions {
13
+ /**
14
+ * A bare host name, e.g. `docs.example.com`. The tracker reports every
15
+ * event under it on every host, not just `localhost`.
16
+ */
17
+ hostname?: string;
18
+ }
19
+
20
+ /**
21
+ * Options for {@link oneDollarStats}: any tracker setting, forwarded as a
22
+ * `data-` attribute on the tag (`hostname` → `data-hostname`, `devmode`,
23
+ * `url`, `autocollect`, `"hash-routing"`, …).
24
+ */
25
+ export type OneDollarStatsOptions = OneDollarStatsNamedOptions & {
26
+ [setting: string]: string;
27
+ };
28
+
29
+ export const oneDollarStatsOptionsSchema = z
30
+ .object({
31
+ hostname: z
32
+ .string()
33
+ .regex(/^[\p{L}\p{N}-]+(?:\.[\p{L}\p{N}-]+)*(?::\d+)?$/u, {
34
+ message:
35
+ "`hostname` must be a bare host name like `docs.example.com`, without `https://`, a path, a query, or a fragment.",
36
+ })
37
+ .optional(),
38
+ })
39
+ .catchall(z.string());
40
+
41
+ export type OneDollarStatsAdapter = AdapterDescriptor<
42
+ "one-dollar-stats",
43
+ OneDollarStatsOptions
44
+ >;
45
+
46
+ export const oneDollarStatsAdapterSchema = adapterDescriptorSchema(
47
+ "one-dollar-stats",
48
+ oneDollarStatsOptionsSchema
49
+ );
50
+
51
+ /**
52
+ * OneDollarStats. Needs no keys — the dashboard matches events to a site by
53
+ * the domain they come from.
54
+ */
55
+ export const oneDollarStats = (
56
+ options: OneDollarStatsOptions = {}
57
+ ): OneDollarStatsAdapter => ({
58
+ kind: "one-dollar-stats",
59
+ options,
60
+ requiredSecrets: [],
61
+ runtimeDeps: [],
62
+ });
63
+
64
+ /**
65
+ * The deferred tag from the install instructions, with every option as its
66
+ * own `data-` attribute. The tracker reads them from `document.currentScript`,
67
+ * so the tag stays a classic external script. It hooks `pushState` and
68
+ * `popstate` itself, so client-router navigations need no extra hook.
69
+ *
70
+ * The tracker turns hash routing on whenever `data-hash-routing` is present,
71
+ * whatever its value, so `"hash-routing": "false"` leaves the attribute off.
72
+ */
73
+ export const oneDollarStatsHead = (
74
+ options: OneDollarStatsOptions
75
+ ): HeadScript[] => {
76
+ const attributes: HeadScript["attributes"] = {};
77
+ for (const [setting, value] of Object.entries(options)) {
78
+ if (setting === "hash-routing" && value === "false") {
79
+ continue;
80
+ }
81
+ attributes[`data-${setting}`] = value;
82
+ }
83
+ attributes.defer = true;
84
+ attributes.src = ONE_DOLLAR_STATS_SCRIPT_SRC;
85
+ return [{ attributes, content: null }];
86
+ };
@@ -14,6 +14,7 @@ import { hightouchAdapterSchema } from "./hightouch.ts";
14
14
  import { hotjarAdapterSchema } from "./hotjar.ts";
15
15
  import { logrocketAdapterSchema } from "./logrocket.ts";
16
16
  import { mixpanelAdapterSchema } from "./mixpanel.ts";
17
+ import { oneDollarStatsAdapterSchema } from "./one-dollar-stats.ts";
17
18
  import { pirschAdapterSchema } from "./pirsch.ts";
18
19
  import { plausibleAdapterSchema } from "./plausible.ts";
19
20
  import { posthogAdapterSchema } from "./posthog.ts";
@@ -37,6 +38,7 @@ export const analyticsAdapterSchema = z.discriminatedUnion("kind", [
37
38
  hotjarAdapterSchema,
38
39
  logrocketAdapterSchema,
39
40
  mixpanelAdapterSchema,
41
+ oneDollarStatsAdapterSchema,
40
42
  pirschAdapterSchema,
41
43
  plausibleAdapterSchema,
42
44
  posthogAdapterSchema,
@@ -27,6 +27,8 @@ import type { RawMarkdownEntry } from "../ai/markdown.ts";
27
27
  import { buildMcpData } from "../ai/mcp/data.ts";
28
28
  import type { McpData } from "../ai/mcp/data.ts";
29
29
  import { buildMcpDiscovery, buildMcpServerCard } from "../ai/mcp/discovery.ts";
30
+ import { captchaSettings } from "../captcha/schema.ts";
31
+ import { parseApiEndpoint } from "../components/content/api-page.ts";
30
32
  import {
31
33
  hasDeferrableGroups,
32
34
  navVariants,
@@ -44,6 +46,7 @@ import {
44
46
  } from "../core/content-assets.ts";
45
47
  import type {
46
48
  BlumeBanner,
49
+ BlumeDataConfig,
47
50
  BlumeData,
48
51
  BlumeFavicon,
49
52
  BlumeLogo,
@@ -58,6 +61,7 @@ import {
58
61
  import { EN_UI, resolveUIStrings } from "../core/i18n-ui.ts";
59
62
  import { resolveFallbackLocale } from "../core/i18n.ts";
60
63
  import { buildIncludeGraph } from "../core/includes.ts";
64
+ import { resolveLocalizable } from "../core/localizable.ts";
61
65
  import {
62
66
  validateNavTargets,
63
67
  validateSearchPopularIcons,
@@ -85,6 +89,7 @@ import type { AsyncApiSpecValue } from "../openapi/asyncapi.ts";
85
89
  import type { ApiSpecData, HttpMethod, OpenApiData } from "../openapi/model.ts";
86
90
  import { HTTP_METHODS, withServerDefaults } from "../openapi/model.ts";
87
91
  import {
92
+ apiPagesUseBuiltinProxy,
88
93
  builtinProxyReferences,
89
94
  hasScalarReferences,
90
95
  needsPlaygroundProxy,
@@ -159,6 +164,7 @@ import {
159
164
  runtimeTsconfigTemplate,
160
165
  featuresTemplate,
161
166
  navFragmentTemplate,
167
+ consentClientTemplate,
162
168
  searchClientTemplate,
163
169
  searchEndpointTemplate,
164
170
  stagedContentDir,
@@ -749,12 +755,12 @@ const isStringShorthand = <T>(value: T | string): value is string =>
749
755
  typeof value === "string";
750
756
 
751
757
  /**
752
- * The URL behind the header's repo mark. A string is used as-is: `github`
753
- * drives the per-page edit link, the header mark and the manifest's
758
+ * The URL behind the footer's repo mark. A string is used as-is: `github`
759
+ * drives the per-page edit link, the footer mark and the manifest's
754
760
  * `repository` together, so a project whose docs repo is private has to unset
755
761
  * all three, and would otherwise have no way to point the mark at anything.
756
762
  */
757
- const headerRepoUrl = (
763
+ const footerRepoUrl = (
758
764
  repo: boolean | string,
759
765
  derived: string | null
760
766
  ): string | null => {
@@ -961,11 +967,53 @@ const resolveBanner = (config: ResolvedConfig): BlumeBanner | null => {
961
967
  return {
962
968
  content: banner.content,
963
969
  dismissible: banner.dismissible,
964
- key: banner.id ?? banner.content,
970
+ key:
971
+ banner.id ??
972
+ resolveLocalizable(banner.content, undefined, config.i18n?.defaultLocale),
965
973
  link: banner.link,
966
974
  };
967
975
  };
968
976
 
977
+ /** The URL the built-in proxy is injected at (see {@link planPlaygroundProxy}). */
978
+ export const playgroundProxyPattern = (config: ResolvedConfig): string =>
979
+ withBasePath(config.basePath, "/_api-proxy");
980
+
981
+ /**
982
+ * The hand-written endpoint defaults for the runtime, the playground's
983
+ * `proxy: true` resolved to the built-in route's URL, as an OpenAPI
984
+ * reference's is.
985
+ */
986
+ const resolveApiPages = (config: ResolvedConfig): BlumeDataConfig["api"] => {
987
+ const { auth, playground, server } = config.api;
988
+ const resolved: BlumeDataConfig["api"] = {
989
+ playground: {
990
+ enabled: playground.enabled,
991
+ proxy:
992
+ playground.proxy === true
993
+ ? playgroundProxyPattern(config)
994
+ : playground.proxy,
995
+ },
996
+ };
997
+ if (auth) {
998
+ resolved.auth = auth;
999
+ }
1000
+ if (server) {
1001
+ resolved.server = server;
1002
+ }
1003
+ return resolved;
1004
+ };
1005
+
1006
+ /** The footer config for the runtime: `null` when unset or empty, so no bare border renders. */
1007
+ const resolveFooter = (
1008
+ config: ResolvedConfig
1009
+ ): ResolvedConfig["footer"] | null => {
1010
+ const { footer } = config;
1011
+ return footer &&
1012
+ (footer.links.length > 0 || Object.keys(footer.socials).length > 0)
1013
+ ? footer
1014
+ : null;
1015
+ };
1016
+
969
1017
  /**
970
1018
  * The OG card's brand mark: a `seo.og.logo` of `false` opts out of any mark,
971
1019
  * a configured SVG wins over the site logo, and a non-SVG value resolves to
@@ -1036,6 +1084,22 @@ const resolveGithubData = (
1036
1084
  }
1037
1085
  : null;
1038
1086
 
1087
+ /** The assistant's snapshot: what the panel needs, never a secret. */
1088
+ const resolveAssistant = (
1089
+ config: ResolvedConfig
1090
+ ): BlumeDataConfig["assistant"] => {
1091
+ const { assistant } = config.ai;
1092
+ if (!assistant?.enabled) {
1093
+ return null;
1094
+ }
1095
+ return {
1096
+ captcha: assistant.captcha ? captchaSettings(assistant.captcha) : null,
1097
+ endpoint: assistant.endpoint ?? null,
1098
+ suggestions: assistant.suggestions,
1099
+ support: assistant.support ?? null,
1100
+ };
1101
+ };
1102
+
1039
1103
  /** Serialize the content graph into the data module the runtime consumes. */
1040
1104
  export const buildRuntimeData = (project: BlumeProject): string => {
1041
1105
  const { config, context, graph, manifest } = project;
@@ -1067,10 +1131,10 @@ export const buildRuntimeData = (project: BlumeProject): string => {
1067
1131
 
1068
1132
  const { i18n } = config;
1069
1133
 
1070
- // Resolve the header repo link per locale. API references no longer add a tab
1134
+ // Resolve the footer's repo link per locale. API references no longer add a tab
1071
1135
  // automatically — authors point a `navigation.tabs` entry at the reference
1072
1136
  // route to surface it (see `referenceRoutes`).
1073
- const markUrl = headerRepoUrl(config.navigation.repo, repoUrl);
1137
+ const markUrl = footerRepoUrl(config.navigation.repo, repoUrl);
1074
1138
  const withRepoUrl = (nav: Navigation): Navigation => ({
1075
1139
  ...nav,
1076
1140
  repoUrl: markUrl,
@@ -1117,17 +1181,14 @@ export const buildRuntimeData = (project: BlumeProject): string => {
1117
1181
  const data: BlumeData = {
1118
1182
  config: {
1119
1183
  analytics: config.analytics,
1184
+ api: resolveApiPages(config),
1120
1185
  appleIcon: resolveAppleIcon(project),
1121
- assistant: config.ai.assistant?.enabled
1122
- ? {
1123
- endpoint: config.ai.assistant.endpoint ?? null,
1124
- suggestions: config.ai.assistant.suggestions,
1125
- }
1126
- : null,
1186
+ assistant: resolveAssistant(config),
1127
1187
  banner: resolveBanner(config),
1128
1188
  basePath: config.basePath,
1129
1189
  codeThemes: config.markdown.code.theme,
1130
1190
  codeWrap: config.markdown.code.wrap,
1191
+ consent: config.consent,
1131
1192
  dateFormat: config.dateFormat,
1132
1193
  description: config.description,
1133
1194
  discovery: {
@@ -1139,7 +1200,9 @@ export const buildRuntimeData = (project: BlumeProject): string => {
1139
1200
  sitemap: config.seo.sitemap && Boolean(config.deployment.options.site),
1140
1201
  },
1141
1202
  favicon: resolveFavicon(project),
1142
- feedback: config.feedback,
1203
+ feedback: config.feedback.enabled,
1204
+ feedbackComments: config.feedback.comments,
1205
+ footer: resolveFooter(config),
1143
1206
  github: resolveGithubData(github),
1144
1207
  i18n: i18n
1145
1208
  ? {
@@ -1153,6 +1216,7 @@ export const buildRuntimeData = (project: BlumeProject): string => {
1153
1216
  dir,
1154
1217
  label,
1155
1218
  })),
1219
+ routeByBrowserLanguage: i18n.routeByBrowserLanguage,
1156
1220
  }
1157
1221
  : null,
1158
1222
  // `undefined` members drop out of the JSON snapshot; the null keeps the
@@ -1172,6 +1236,10 @@ export const buildRuntimeData = (project: BlumeProject): string => {
1172
1236
  route: config.agents.mcp.route,
1173
1237
  }
1174
1238
  : null,
1239
+ metatags: config.seo.metatags ?? null,
1240
+ narration: config.narration.enabled
1241
+ ? { generated: config.narration.provider !== null }
1242
+ : null,
1175
1243
  // `og.enabled` is resolved to a definite boolean in `loadConfig`; coerce
1176
1244
  // the optional schema type so the serialized shape stays `boolean`.
1177
1245
  // Card fonts are baked into the generated OG endpoint (they can carry
@@ -1496,10 +1564,6 @@ const writeApiFiles = async (
1496
1564
  /** The proxy endpoint's file under the Astro `src/` dir (eject writes it too). */
1497
1565
  export const PLAYGROUND_PROXY_ENTRY = join("blume-openapi", "api-proxy.ts");
1498
1566
 
1499
- /** The URL the built-in proxy is injected at (see {@link planPlaygroundProxy}). */
1500
- export const playgroundProxyPattern = (config: ResolvedConfig): string =>
1501
- withBasePath(config.basePath, "/_api-proxy");
1502
-
1503
1567
  /**
1504
1568
  * Decide whether to generate the playground's built-in CORS proxy endpoint.
1505
1569
  * Only the Blume renderer's playground with `proxy: true` needs it — a proxy
@@ -1592,6 +1656,47 @@ type DocumentPathItem = { servers?: DocumentServer[] } & Partial<
1592
1656
  export const specOrigins = (data: OpenApiData): string[] =>
1593
1657
  [...new Set(Object.values(data).flatMap(specOriginsOf))].toSorted();
1594
1658
 
1659
+ /** The origin of an absolute URL, or `null` for a path or anything unparsable. */
1660
+ const originOf = (url: string): string | null => {
1661
+ try {
1662
+ return new URL(url).origin;
1663
+ } catch {
1664
+ return null;
1665
+ }
1666
+ };
1667
+
1668
+ /**
1669
+ * The origins hand-written endpoint pages send to through the built-in
1670
+ * proxy: the site's `api.server`, and every page whose `api` names a full
1671
+ * URL. Empty unless those pages use the built-in proxy.
1672
+ */
1673
+ export const apiPageOrigins = (project: BlumeProject): string[] => {
1674
+ const { config } = project;
1675
+ if (!apiPagesUseBuiltinProxy(config)) {
1676
+ return [];
1677
+ }
1678
+ const targets = project.graph.pages.map(
1679
+ (page) => parseApiEndpoint(page.meta.api ?? "")?.target ?? ""
1680
+ );
1681
+ return [config.api.server ?? "", ...targets].flatMap((target) => {
1682
+ const origin = originOf(target);
1683
+ return origin ? [origin] : [];
1684
+ });
1685
+ };
1686
+
1687
+ /**
1688
+ * A warning when the hand-written endpoint pages send through the built-in
1689
+ * proxy but name no absolute origin for it to allow, so it would refuse every
1690
+ * request they send.
1691
+ */
1692
+ export const apiPageProxyWarnings = (project: BlumeProject): string[] =>
1693
+ apiPagesUseBuiltinProxy(project.config) &&
1694
+ apiPageOrigins(project).length === 0
1695
+ ? [
1696
+ "api.playground.proxy is true, but api.server isn't an absolute URL and no page's api frontmatter names one, so the built-in proxy has no origin to allow and will refuse every request the endpoint pages send. Set api.server to the API's URL, like https://api.acme.com/v1.",
1697
+ ]
1698
+ : [];
1699
+
1595
1700
  /**
1596
1701
  * Build-time diagnostics for playground sends the built-in proxy would refuse.
1597
1702
  * The baked-in allowlist pools every documented origin, but each spec's
@@ -1644,9 +1749,12 @@ const writeAskFiles = async (
1644
1749
  await write(
1645
1750
  join(srcDir, "pages", "api", "ask.ts"),
1646
1751
  askEndpointTemplate(backend, {
1752
+ captcha: assistant.captcha,
1647
1753
  cors: assistant.cors,
1648
1754
  instructions: assistant.instructions,
1755
+ rateLimit: project.config.rateLimit,
1649
1756
  retrieval: assistant.retrieval,
1757
+ tools: assistant.tools ?? backend.toolsByDefault,
1650
1758
  })
1651
1759
  );
1652
1760
  };
@@ -1863,6 +1971,7 @@ export const generateRuntime = async (
1863
1971
  const askPath = join(srcDir, "generated", "Ask.astro");
1864
1972
  const themePath = join(srcDir, "generated", "app.css");
1865
1973
  const searchClientPath = join(srcDir, "generated", "search-client.ts");
1974
+ const consentClientPath = join(srcDir, "generated", "consent-client.ts");
1866
1975
  const featuresPath = join(srcDir, "generated", "features.ts");
1867
1976
  const examplesPath = join(srcDir, "generated", "examples.ts");
1868
1977
  const examplesThemePath = join(srcDir, "generated", "examples.css");
@@ -1887,7 +1996,7 @@ export const generateRuntime = async (
1887
1996
  // `astro.config.mjs` — which would restart the dev server in place.
1888
1997
  const contentRoutes = markdownRoutePaths(project);
1889
1998
  const homeLinkHeader =
1890
- buildHomeLinkHeader(config, contentRoutes) ?? undefined;
1999
+ buildHomeLinkHeader(config, contentRoutes, "dev") ?? undefined;
1891
2000
 
1892
2001
  const assistantEnabled = config.ai.assistant?.enabled ?? false;
1893
2002
  const exportPdf = config.export.pdf;
@@ -2000,7 +2109,9 @@ export const generateRuntime = async (
2000
2109
  // Computed once: the endpoint template bakes it in below. A spec that
2001
2110
  // contributes no origin of its own gets a per-spec diagnostic
2002
2111
  // (`proxyAllowlistWarnings`) — the proxy would refuse its every send.
2003
- const proxyOrigins = specOrigins(openApiData);
2112
+ const proxyOrigins = [
2113
+ ...new Set([...specOrigins(openApiData), ...apiPageOrigins(project)]),
2114
+ ].toSorted();
2004
2115
 
2005
2116
  const hasStaged = staged.size > 0;
2006
2117
  // Only emit a project-scanning `docs` collection when a filesystem source
@@ -2022,6 +2133,7 @@ export const generateRuntime = async (
2022
2133
  aliases: resolveTsconfigAliases(context.root),
2023
2134
  askPath,
2024
2135
  config,
2136
+ consentClientPath,
2025
2137
  contentRoot: docsCollection.base,
2026
2138
  contentRoutes,
2027
2139
  context,
@@ -2186,6 +2298,7 @@ export const generateRuntime = async (
2186
2298
  }),
2187
2299
  writeNotFoundPage(write, srcDir, pages, project.graph.pages),
2188
2300
  write(searchClientPath, searchClientTemplate(config)),
2301
+ write(consentClientPath, consentClientTemplate(config.consent)),
2189
2302
  write(featuresPath, featuresTemplate(clientFeatures)),
2190
2303
  ]);
2191
2304
 
@@ -2258,6 +2371,7 @@ export const generateRuntime = async (
2258
2371
  const warnings: string[] = [
2259
2372
  ...(depsLinkWarning ? [depsLinkWarning] : []),
2260
2373
  ...proxyAllowlistWarnings(config, openApiData),
2374
+ ...apiPageProxyWarnings(project),
2261
2375
  ...reactCompilerWarnings(config, needsReact, reactCompilerPath),
2262
2376
  ...mcp.warnings,
2263
2377
  ...islandDiscovery.warnings,
@@ -1,5 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
 
3
+ import { resolve } from "pathe";
4
+
3
5
  import { refreshBlumeContent } from "./integration.ts";
4
6
 
5
7
  /**
@@ -18,12 +20,21 @@ import { refreshBlumeContent } from "./integration.ts";
18
20
  */
19
21
 
20
22
  /** The Vite module-graph slice the plugin touches (structurally typed, like
21
- * every Blume-authored Vite plugin — see `serverAppResolvePlugin`). */
23
+ * every Blume-authored Vite plugin — see `serverAppResolvePlugin`). Every
24
+ * environment keeps its own graph, and the server's own `moduleGraph` only
25
+ * covers `client` and `ssr`: with `@astrojs/cloudflare` the content pages
26
+ * render in the `prerender` environment instead. */
22
27
  interface IncludeHmrServer {
23
- moduleGraph: {
24
- getModulesByFile: (file: string) => Set<unknown> | undefined;
25
- invalidateModule: (mod: never) => void;
26
- };
28
+ config: { root: string };
29
+ environments: Record<
30
+ string,
31
+ {
32
+ moduleGraph: {
33
+ getModulesByFile: (file: string) => Set<unknown> | undefined;
34
+ invalidateModule: (mod: never) => void;
35
+ };
36
+ }
37
+ >;
27
38
  ws: { send: (payload: { type: "full-reload" }) => void };
28
39
  }
29
40
 
@@ -51,16 +62,24 @@ export const includeHmrPlugin = (graphPath: string): IncludeHmrPlugin => ({
51
62
  // No graph yet (first run) — nothing to invalidate.
52
63
  return;
53
64
  }
54
- const includers = graph[ctx.file];
65
+ // An ejected app's graph is relative to the project, its Vite root; the
66
+ // hidden runtime's is absolute, which resolving leaves as it is.
67
+ const { config, environments, ws } = ctx.server;
68
+ const includers = Object.entries(graph).find(
69
+ ([partial]) => resolve(config.root, partial) === ctx.file
70
+ )?.[1];
55
71
  if (!includers || includers.length === 0) {
56
72
  return;
57
73
  }
58
- const { moduleGraph, ws } = ctx.server;
59
- for (const includer of includers) {
60
- for (const mod of moduleGraph.getModulesByFile(includer) ?? []) {
61
- // SAFETY: the module came out of this module graph; `never` only
62
- // reflects that the structural slice doesn't model the node type.
63
- moduleGraph.invalidateModule(mod as never);
74
+ for (const { moduleGraph } of Object.values(environments)) {
75
+ for (const includer of includers) {
76
+ for (const mod of moduleGraph.getModulesByFile(
77
+ resolve(config.root, includer)
78
+ ) ?? []) {
79
+ // SAFETY: the module came out of this module graph; `never` only
80
+ // reflects that the structural slice doesn't model the node type.
81
+ moduleGraph.invalidateModule(mod as never);
82
+ }
64
83
  }
65
84
  }
66
85
  // Plain `.md` pages have no Vite module: their HTML lives in the
@@ -29,7 +29,10 @@ type StoreEntry = ReturnType<LoaderContext["store"]["entries"]>[number][1];
29
29
  /** Meta-store key holding the recorded partials digest of an includer. */
30
30
  const stateKey = (id: string): string => `blume:include-state:${id}`;
31
31
 
32
- /** The generated include graph: absolute partial → absolute including pages. */
32
+ /**
33
+ * The generated include graph: partial → including pages, absolute in the
34
+ * hidden runtime and relative to the project root in an ejected app.
35
+ */
33
36
  type IncludeGraph = Record<string, string[]>;
34
37
 
35
38
  /**
@@ -47,14 +50,22 @@ const readGraph = (graphPath: string): IncludeGraph => {
47
50
  }
48
51
  };
49
52
 
50
- /** Invert the graph: absolute including page → its partials, sorted. */
51
- const partialsByPage = (graph: IncludeGraph): Map<string, string[]> => {
53
+ /**
54
+ * Invert the graph: absolute including page → its absolute partials, sorted.
55
+ * Each path resolves against the Astro root, which leaves the hidden runtime's
56
+ * absolute paths as they are.
57
+ */
58
+ const partialsByPage = (
59
+ graph: IncludeGraph,
60
+ root: string
61
+ ): Map<string, string[]> => {
52
62
  const byPage = new Map<string, string[]>();
53
63
  for (const [partial, pages] of Object.entries(graph)) {
54
64
  for (const page of pages) {
55
- const partials = byPage.get(page) ?? [];
56
- partials.push(partial);
57
- byPage.set(page, partials);
65
+ const abs = resolve(root, page);
66
+ const partials = byPage.get(abs) ?? [];
67
+ partials.push(resolve(root, partial));
68
+ byPage.set(abs, partials);
58
69
  }
59
70
  }
60
71
  for (const partials of byPage.values()) {
@@ -123,11 +134,11 @@ export const evictStaleIncluders = (
123
134
  context: LoaderContext,
124
135
  graphPath: string
125
136
  ): string[] => {
126
- const byPage = partialsByPage(readGraph(graphPath));
137
+ const root = fileURLToPath(context.config.root);
138
+ const byPage = partialsByPage(readGraph(graphPath), root);
127
139
  if (byPage.size === 0) {
128
140
  return [];
129
141
  }
130
- const root = fileURLToPath(context.config.root);
131
142
  const evicted: string[] = [];
132
143
  for (const [id, entry] of context.store.entries()) {
133
144
  if (evictIfStale(context, byPage, root, id, entry)) {
@@ -2,6 +2,7 @@ export { withAdapterRoot } from "./adapter-root.ts";
2
2
  export { generateRuntime, prerenderDepsPlugin } from "./generate.ts";
3
3
  export { includeHmrPlugin } from "./include-hmr.ts";
4
4
  export { withIncludeRefresh } from "./include-refresh.ts";
5
+ export { variablesVitePlugin } from "./variables.ts";
5
6
  export type { GenerateResult } from "./generate.ts";
6
7
  export {
7
8
  blumeIntegration,