blume 2.0.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (455) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +48 -0
  3. package/README.md +1 -1
  4. package/dist/cli/{chunk-1d7ve1dm.js → chunk-0gz36akr.js} +18 -2
  5. package/dist/cli/{chunk-1d7ve1dm.js.map → chunk-0gz36akr.js.map} +3 -3
  6. package/dist/cli/{chunk-2eytanqx.js → chunk-1n228xqb.js} +2 -2
  7. package/dist/cli/{chunk-yfyb25rh.js → chunk-2f3ndkpw.js} +24 -8
  8. package/dist/cli/chunk-2f3ndkpw.js.map +14 -0
  9. package/dist/cli/{chunk-r20tn01b.js → chunk-2f7n4qzt.js} +8 -2
  10. package/dist/cli/{chunk-r20tn01b.js.map → chunk-2f7n4qzt.js.map} +3 -3
  11. package/dist/cli/{chunk-35d4wj9f.js → chunk-2n4ps1b3.js} +7 -7
  12. package/dist/cli/{chunk-j85vccga.js → chunk-43zcf4gz.js} +97 -57
  13. package/dist/cli/{chunk-j85vccga.js.map → chunk-43zcf4gz.js.map} +6 -6
  14. package/dist/cli/{chunk-e04dxsz1.js → chunk-4ejxbzee.js} +1 -1
  15. package/dist/cli/{chunk-5m5nmvyq.js → chunk-4h8z9vv5.js} +233 -39
  16. package/dist/cli/chunk-4h8z9vv5.js.map +16 -0
  17. package/dist/cli/{chunk-5f86nr5m.js → chunk-5cg2rzgf.js} +18 -16
  18. package/dist/cli/{chunk-5f86nr5m.js.map → chunk-5cg2rzgf.js.map} +2 -2
  19. package/dist/cli/{chunk-tzmab476.js → chunk-5ffywsmb.js} +4 -4
  20. package/dist/cli/{chunk-2z928egk.js → chunk-5wj2qwn2.js} +5 -5
  21. package/dist/cli/chunk-6bm0xpgd.js +18 -0
  22. package/dist/cli/chunk-6bm0xpgd.js.map +10 -0
  23. package/dist/cli/{chunk-vg9r4eb9.js → chunk-713mngdq.js} +12 -5
  24. package/dist/cli/{chunk-vg9r4eb9.js.map → chunk-713mngdq.js.map} +3 -3
  25. package/dist/cli/{chunk-5xvm6tfj.js → chunk-9geymqns.js} +17 -15
  26. package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-9geymqns.js.map} +2 -2
  27. package/dist/cli/{chunk-q58y5e6a.js → chunk-9xr4dgee.js} +26 -17
  28. package/dist/cli/chunk-9xr4dgee.js.map +10 -0
  29. package/dist/cli/{chunk-b07cmahc.js → chunk-amrb6hgh.js} +2 -2
  30. package/dist/cli/chunk-cm89scdv.js +443 -0
  31. package/dist/cli/chunk-cm89scdv.js.map +11 -0
  32. package/dist/cli/{chunk-akbpwfxc.js → chunk-cmtcnh9f.js} +2 -2
  33. package/dist/cli/chunk-cy5bm0j0.js +104 -0
  34. package/dist/cli/chunk-cy5bm0j0.js.map +11 -0
  35. package/dist/cli/{chunk-crgn1q09.js → chunk-e7vvk5ya.js} +4 -4
  36. package/dist/cli/{chunk-pehfxfta.js → chunk-g2z9x01v.js} +6 -98
  37. package/dist/cli/chunk-g2z9x01v.js.map +10 -0
  38. package/dist/cli/{chunk-tkacnehg.js → chunk-gp84za0h.js} +2 -2
  39. package/dist/cli/{chunk-wrr3j9w9.js → chunk-h2a48yhd.js} +186 -63
  40. package/dist/cli/chunk-h2a48yhd.js.map +36 -0
  41. package/dist/cli/{chunk-hm3vjy5s.js → chunk-jnwj5kjj.js} +14 -9
  42. package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-jnwj5kjj.js.map} +4 -4
  43. package/dist/cli/chunk-kwrg63tm.js +31 -0
  44. package/dist/cli/chunk-kwrg63tm.js.map +10 -0
  45. package/dist/cli/{chunk-2hsdwb9n.js → chunk-nd1821sk.js} +18 -16
  46. package/dist/cli/{chunk-2hsdwb9n.js.map → chunk-nd1821sk.js.map} +2 -2
  47. package/dist/cli/{chunk-6dsbexzp.js → chunk-ntv4qrt7.js} +17 -15
  48. package/dist/cli/{chunk-6dsbexzp.js.map → chunk-ntv4qrt7.js.map} +2 -2
  49. package/dist/cli/{chunk-r9rcc4w7.js → chunk-p804f3pe.js} +7 -7
  50. package/dist/cli/{chunk-ey84smr6.js → chunk-py62fewh.js} +6 -6
  51. package/dist/cli/{chunk-ey84smr6.js.map → chunk-py62fewh.js.map} +1 -1
  52. package/dist/cli/chunk-q3wxxq39.js +126 -0
  53. package/dist/cli/chunk-q3wxxq39.js.map +11 -0
  54. package/dist/cli/{chunk-9t7a85s3.js → chunk-rekqz4qg.js} +23 -13
  55. package/dist/cli/chunk-rekqz4qg.js.map +10 -0
  56. package/dist/cli/{chunk-8ktnccpt.js → chunk-ta27feev.js} +1 -1
  57. package/dist/cli/{chunk-pv29h0wf.js → chunk-xkz5xbtv.js} +3476 -822
  58. package/dist/cli/chunk-xkz5xbtv.js.map +213 -0
  59. package/dist/cli/{chunk-a58773jm.js → chunk-y4ykbark.js} +2 -2
  60. package/dist/cli/{chunk-p3v96n38.js → chunk-y5h4r2y0.js} +4 -4
  61. package/dist/cli/{chunk-acanzt5p.js → chunk-yj17vs39.js} +6 -6
  62. package/dist/cli/{chunk-p73c0m7w.js → chunk-yxmk4pec.js} +16 -14
  63. package/dist/cli/{chunk-p73c0m7w.js.map → chunk-yxmk4pec.js.map} +2 -2
  64. package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
  65. package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
  66. package/dist/cli/{chunk-c8chx29p.js → chunk-zf748avv.js} +384 -207
  67. package/dist/cli/chunk-zf748avv.js.map +37 -0
  68. package/dist/cli/{chunk-g4hq16wv.js → chunk-zhvd6adm.js} +16 -14
  69. package/dist/cli/{chunk-g4hq16wv.js.map → chunk-zhvd6adm.js.map} +2 -2
  70. package/dist/cli/index.js +26 -20
  71. package/dist/cli/index.js.map +5 -5
  72. package/dist/types/ai/agent-surface.d.ts +8 -7
  73. package/dist/types/ai/ai-catalog.d.ts +7 -0
  74. package/dist/types/ai/ask-context.d.ts +22 -0
  75. package/dist/types/ai/ask.d.ts +271 -58
  76. package/dist/types/ai/index.d.ts +2 -2
  77. package/dist/types/ai/site-skill.d.ts +26 -0
  78. package/dist/types/ai/skills.d.ts +16 -0
  79. package/dist/types/astro/integration.d.ts +8 -0
  80. package/dist/types/captcha/hcaptcha.d.ts +27 -0
  81. package/dist/types/captcha/index.d.ts +28 -0
  82. package/dist/types/captcha/schema.d.ts +29 -0
  83. package/dist/types/captcha/turnstile.d.ts +28 -0
  84. package/dist/types/components/content/api-field.d.ts +59 -0
  85. package/dist/types/components/content/api-page.d.ts +95 -0
  86. package/dist/types/components/layout/nav-utils.d.ts +26 -0
  87. package/dist/types/components/openapi/helpers.d.ts +137 -0
  88. package/dist/types/components/openapi/security.d.ts +85 -0
  89. package/dist/types/consent/ethyca.d.ts +48 -0
  90. package/dist/types/consent/index.d.ts +37 -0
  91. package/dist/types/consent/native.d.ts +28 -0
  92. package/dist/types/consent/osano.d.ts +42 -0
  93. package/dist/types/consent/schema.d.ts +110 -0
  94. package/dist/types/core/config-input.d.ts +187 -20
  95. package/dist/types/core/data.d.ts +49 -4
  96. package/dist/types/core/footer.d.ts +8 -0
  97. package/dist/types/core/i18n-ui.d.ts +86 -0
  98. package/dist/types/core/includes.d.ts +8 -2
  99. package/dist/types/core/localizable.d.ts +7 -0
  100. package/dist/types/core/page-modes.d.ts +29 -0
  101. package/dist/types/core/redirect-patterns.d.ts +144 -0
  102. package/dist/types/core/related.d.ts +40 -0
  103. package/dist/types/core/schema.d.ts +551 -56
  104. package/dist/types/core/sources/read.d.ts +5 -0
  105. package/dist/types/core/types.d.ts +1 -1
  106. package/dist/types/core/variables.d.ts +42 -0
  107. package/dist/types/deploy/node-headers.d.ts +13 -2
  108. package/dist/types/deploy/platforms/cloudflare.d.ts +5 -0
  109. package/dist/types/deploy/platforms/netlify.d.ts +7 -0
  110. package/dist/types/deploy/platforms/vercel.d.ts +6 -0
  111. package/dist/types/deploy/redirects.d.ts +39 -11
  112. package/dist/types/deploy/vercel-negotiation.d.ts +9 -0
  113. package/dist/types/markdown/code-title.d.ts +17 -0
  114. package/dist/types/markdown/features.d.ts +3 -2
  115. package/dist/types/narration/build.d.ts +70 -0
  116. package/dist/types/narration/provider.d.ts +26 -0
  117. package/dist/types/narration/script.d.ts +154 -0
  118. package/dist/types/openapi/model.d.ts +12 -6
  119. package/dist/types/openapi/overlay.d.ts +54 -0
  120. package/dist/types/openapi/parse.d.ts +13 -0
  121. package/dist/types/openapi/references.d.ts +14 -4
  122. package/dist/types/ratelimit/cloudflare.d.ts +39 -0
  123. package/dist/types/ratelimit/index.d.ts +27 -0
  124. package/dist/types/ratelimit/memory.d.ts +36 -0
  125. package/dist/types/ratelimit/schema.d.ts +111 -0
  126. package/dist/types/ratelimit/upstash.d.ts +21 -0
  127. package/dist/types/ratelimit/wrangler.d.ts +23 -0
  128. package/dist/types/reference/asyncapi.d.ts +10 -10
  129. package/dist/types/reference/graphql.d.ts +13 -10
  130. package/dist/types/reference/openapi.d.ts +33 -12
  131. package/dist/types/reference/options.d.ts +45 -5
  132. package/dist/types/reference/scalar.d.ts +13 -0
  133. package/dist/types/reference/schema.d.ts +60 -36
  134. package/dist/types/search/documents.d.ts +12 -1
  135. package/dist/types/search/orama-index.d.ts +4 -0
  136. package/dist/types/seo/metatags.d.ts +20 -0
  137. package/docs/02-deployment.mdx +41 -5
  138. package/docs/03-upgrading.mdx +4 -4
  139. package/docs/04-migrating.mdx +1 -1
  140. package/docs/advanced/changelog.mdx +2 -2
  141. package/docs/advanced/skills.mdx +14 -0
  142. package/docs/cli/audit.mdx +21 -1
  143. package/docs/cli/index.mdx +1 -0
  144. package/docs/configuration/analytics.mdx +3 -1
  145. package/docs/configuration/assistant.mdx +188 -36
  146. package/docs/configuration/consent.mdx +100 -0
  147. package/docs/configuration/customization.mdx +4 -4
  148. package/docs/configuration/index.mdx +63 -5
  149. package/docs/configuration/meta.ts +3 -0
  150. package/docs/configuration/narration.mdx +119 -0
  151. package/docs/configuration/rate-limiting.mdx +69 -0
  152. package/docs/configuration/search.mdx +29 -1
  153. package/docs/configuration/theming.mdx +3 -1
  154. package/docs/content/components.mdx +106 -0
  155. package/docs/content/frontmatter.mdx +76 -0
  156. package/docs/content/i18n.mdx +38 -3
  157. package/docs/content/includes.mdx +16 -0
  158. package/docs/content/meta.mdx +1 -0
  159. package/docs/content/meta.ts +1 -0
  160. package/docs/content/navigation.mdx +28 -6
  161. package/docs/content/sources/contentful.mdx +32 -0
  162. package/docs/content/sources/custom.mdx +39 -0
  163. package/docs/content/sources/github-releases.mdx +31 -0
  164. package/docs/content/sources/index.mdx +91 -0
  165. package/docs/content/sources/meta.ts +16 -0
  166. package/docs/content/sources/notion.mdx +32 -0
  167. package/docs/content/sources/obsidian.mdx +37 -0
  168. package/docs/content/sources/payload.mdx +30 -0
  169. package/docs/content/sources/remote-mdx.mdx +40 -0
  170. package/docs/content/sources/sanity.mdx +29 -0
  171. package/docs/content/sources/strapi.mdx +31 -0
  172. package/docs/content/syntax.mdx +67 -2
  173. package/docs/content/variables.mdx +41 -0
  174. package/docs/discoverability/agent-discovery.mdx +29 -2
  175. package/docs/discoverability/index.mdx +1 -1
  176. package/docs/discoverability/llms-txt.mdx +1 -1
  177. package/docs/discoverability/metadata.mdx +17 -0
  178. package/docs/references/api-pages.mdx +74 -0
  179. package/docs/references/asyncapi.mdx +1 -1
  180. package/docs/references/graphql.mdx +2 -2
  181. package/docs/references/meta.ts +1 -1
  182. package/docs/references/openapi.mdx +102 -3
  183. package/docs/references/scalar.mdx +3 -1
  184. package/package.json +36 -1
  185. package/skills/blume/SKILL.md +3 -0
  186. package/skills/blume-migrate/SKILL.md +5 -5
  187. package/skills/blume-migrate/references/docusaurus.md +3 -3
  188. package/skills/blume-migrate/references/mintlify.md +37 -19
  189. package/skills/blume-migrate/references/nextra.md +2 -2
  190. package/skills/blume-migrate/references/starlight.md +2 -1
  191. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
  192. package/skills/blume-write-skill/SKILL.md +82 -0
  193. package/src/ai/agent-readability.ts +2 -1
  194. package/src/ai/agent-surface.ts +9 -7
  195. package/src/ai/ai-catalog.ts +6 -3
  196. package/src/ai/ask-context.ts +73 -20
  197. package/src/ai/ask-data.ts +6 -0
  198. package/src/ai/ask-tools.ts +142 -0
  199. package/src/ai/ask.ts +354 -76
  200. package/src/ai/component-markdown.ts +75 -0
  201. package/src/ai/cors.ts +2 -0
  202. package/src/ai/index.ts +12 -0
  203. package/src/ai/llms.ts +6 -2
  204. package/src/ai/markdown.ts +2 -1
  205. package/src/ai/mcp/data.ts +6 -0
  206. package/src/ai/openapi-components.ts +9 -3
  207. package/src/ai/site-skill.ts +274 -0
  208. package/src/ai/skills.ts +35 -2
  209. package/src/ai/write-skill.ts +97 -0
  210. package/src/astro/generate.ts +132 -18
  211. package/src/astro/index.ts +1 -0
  212. package/src/astro/integration.ts +35 -0
  213. package/src/astro/module-types.ts +6 -0
  214. package/src/astro/templates.ts +283 -30
  215. package/src/astro/variables.ts +31 -0
  216. package/src/audit/catalog.ts +19 -0
  217. package/src/audit/checks/contrast.ts +183 -0
  218. package/src/audit/checks/i18n.ts +2 -3
  219. package/src/audit/checks/indexability.ts +2 -3
  220. package/src/audit/checks/links.ts +5 -12
  221. package/src/audit/checks/sitemap.ts +2 -3
  222. package/src/audit/redirects.ts +46 -15
  223. package/src/audit/run.ts +2 -0
  224. package/src/audit/types.ts +2 -1
  225. package/src/blume-modules.d.ts +7 -0
  226. package/src/captcha/client.ts +152 -0
  227. package/src/captcha/hcaptcha.ts +36 -0
  228. package/src/captcha/index.ts +28 -0
  229. package/src/captcha/schema.ts +32 -0
  230. package/src/captcha/turnstile.ts +38 -0
  231. package/src/captcha/verify.ts +71 -0
  232. package/src/cli/command-meta.ts +5 -0
  233. package/src/cli/commands/doctor.ts +22 -16
  234. package/src/cli/commands/skill.ts +96 -0
  235. package/src/cli/index.ts +5 -0
  236. package/src/cli/required-secrets.ts +71 -29
  237. package/src/components/BlumePage.astro +2 -0
  238. package/src/components/content/ApiEndpoint.astro +18 -0
  239. package/src/components/content/ApiField.astro +79 -0
  240. package/src/components/content/ApiPlayground.astro +62 -0
  241. package/src/components/content/ApiRail.astro +19 -0
  242. package/src/components/content/Color.astro +1 -0
  243. package/src/components/content/FileTree.astro +1 -0
  244. package/src/components/content/GithubInfo.astro +1 -0
  245. package/src/components/content/Panel.astro +1 -0
  246. package/src/components/content/ParamField.astro +25 -0
  247. package/src/components/content/RequestExample.astro +17 -0
  248. package/src/components/content/ResponseExample.astro +17 -0
  249. package/src/components/content/ResponseField.astro +32 -0
  250. package/src/components/content/Step.astro +1 -0
  251. package/src/components/content/Tile.astro +1 -0
  252. package/src/components/content/Tooltip.astro +1 -0
  253. package/src/components/content/Tree.astro +1 -0
  254. package/src/components/content/TypeTable.astro +4 -1
  255. package/src/components/content/View.astro +21 -0
  256. package/src/components/content/ViewSwitcher.astro +168 -0
  257. package/src/components/content/api-field.ts +100 -0
  258. package/src/components/content/api-page.ts +224 -0
  259. package/src/components/content/view-switcher.ts +71 -0
  260. package/src/components/index.ts +2 -0
  261. package/src/components/islands/Assistant.astro +10 -1
  262. package/src/components/islands/assistant.tsx +104 -14
  263. package/src/components/islands/code-question.ts +62 -0
  264. package/src/components/islands/hooks.ts +110 -21
  265. package/src/components/islands/support-link.ts +68 -0
  266. package/src/components/layout/Analytics.astro +11 -2
  267. package/src/components/layout/Banner.astro +14 -10
  268. package/src/components/layout/Breadcrumbs.astro +6 -2
  269. package/src/components/layout/ConsentBanner.astro +62 -0
  270. package/src/components/layout/ConsentHead.astro +38 -0
  271. package/src/components/layout/Directory.astro +94 -0
  272. package/src/components/layout/DrawerSwitchers.astro +51 -0
  273. package/src/components/layout/Empty.astro +2 -2
  274. package/src/components/layout/Header.astro +122 -80
  275. package/src/components/layout/LanguageSwitcher.astro +48 -15
  276. package/src/components/layout/NarrationPlayer.astro +1085 -0
  277. package/src/components/layout/NavSelector.astro +33 -7
  278. package/src/components/layout/PageFeedback.astro +54 -49
  279. package/src/components/layout/PageLayout.astro +71 -3
  280. package/src/components/layout/ReferenceLayout.astro +17 -6
  281. package/src/components/layout/RelatedPages.astro +42 -0
  282. package/src/components/layout/RootLayout.astro +308 -45
  283. package/src/components/layout/Search.astro +31 -17
  284. package/src/components/layout/SiteFooter.astro +124 -0
  285. package/src/components/layout/SiteMetatags.astro +16 -0
  286. package/src/components/layout/consent/native.ts +79 -0
  287. package/src/components/layout/consent/types.ts +37 -0
  288. package/src/components/layout/footer-links.ts +53 -0
  289. package/src/components/layout/footer-socials.ts +87 -0
  290. package/src/components/layout/locale-redirect.ts +107 -0
  291. package/src/components/layout/nav-utils.ts +83 -0
  292. package/src/components/layout/page-feedback.ts +96 -0
  293. package/src/components/layout/search/analytics.ts +98 -0
  294. package/src/components/layout/search/flexsearch.ts +17 -5
  295. package/src/components/layout/search/orama-cloud.ts +26 -14
  296. package/src/components/layout/search/types.ts +20 -0
  297. package/src/components/layout/search/typesense.ts +5 -1
  298. package/src/components/openapi/Operation.astro +161 -13
  299. package/src/components/openapi/RequestBody.astro +6 -4
  300. package/src/components/openapi/RequestPanel.astro +59 -7
  301. package/src/components/openapi/Responses.astro +6 -4
  302. package/src/components/openapi/async-snippets.ts +4 -4
  303. package/src/components/openapi/code-samples.ts +97 -0
  304. package/src/components/openapi/security.ts +6 -3
  305. package/src/components/openapi/snippets.ts +869 -8
  306. package/src/components/props.ts +6 -0
  307. package/src/consent/client.ts +95 -0
  308. package/src/consent/clients.ts +19 -0
  309. package/src/consent/ethyca.ts +71 -0
  310. package/src/consent/head.ts +24 -0
  311. package/src/consent/index.ts +37 -0
  312. package/src/consent/init.ts +29 -0
  313. package/src/consent/native.ts +36 -0
  314. package/src/consent/osano.ts +59 -0
  315. package/src/consent/schema.ts +30 -0
  316. package/src/core/builtin-tags.ts +5 -0
  317. package/src/core/client-address.ts +19 -0
  318. package/src/core/config-input.ts +194 -20
  319. package/src/core/data.ts +44 -4
  320. package/src/core/diagnostics.ts +3 -2
  321. package/src/core/footer.ts +26 -0
  322. package/src/core/graph.ts +39 -36
  323. package/src/core/i18n-ui.ts +82 -2
  324. package/src/core/includes.ts +20 -3
  325. package/src/core/links.ts +16 -2
  326. package/src/core/localizable.ts +26 -0
  327. package/src/core/navigation.ts +43 -12
  328. package/src/core/page-modes.ts +56 -0
  329. package/src/core/project-graph.ts +111 -5
  330. package/src/core/redirect-patterns.ts +491 -0
  331. package/src/core/related.ts +131 -0
  332. package/src/core/schema.ts +318 -64
  333. package/src/core/sources/normalize.ts +2 -1
  334. package/src/core/sources/read.ts +8 -3
  335. package/src/core/types.ts +1 -1
  336. package/src/core/ui-packs/ar.ts +43 -0
  337. package/src/core/ui-packs/bg.ts +45 -0
  338. package/src/core/ui-packs/bn.ts +43 -0
  339. package/src/core/ui-packs/ca.ts +46 -0
  340. package/src/core/ui-packs/cs.ts +44 -0
  341. package/src/core/ui-packs/da.ts +45 -0
  342. package/src/core/ui-packs/de.ts +46 -0
  343. package/src/core/ui-packs/el.ts +45 -0
  344. package/src/core/ui-packs/es.ts +46 -0
  345. package/src/core/ui-packs/fa.ts +45 -0
  346. package/src/core/ui-packs/fi.ts +45 -0
  347. package/src/core/ui-packs/fr.ts +46 -0
  348. package/src/core/ui-packs/he.ts +43 -0
  349. package/src/core/ui-packs/hi.ts +44 -0
  350. package/src/core/ui-packs/hr.ts +45 -0
  351. package/src/core/ui-packs/hu.ts +44 -0
  352. package/src/core/ui-packs/id.ts +45 -0
  353. package/src/core/ui-packs/it.ts +45 -0
  354. package/src/core/ui-packs/ja.ts +45 -0
  355. package/src/core/ui-packs/ko.ts +44 -0
  356. package/src/core/ui-packs/nl.ts +46 -0
  357. package/src/core/ui-packs/no.ts +44 -0
  358. package/src/core/ui-packs/pl.ts +45 -0
  359. package/src/core/ui-packs/pt-br.ts +46 -0
  360. package/src/core/ui-packs/pt.ts +45 -0
  361. package/src/core/ui-packs/ro.ts +45 -0
  362. package/src/core/ui-packs/ru.ts +45 -0
  363. package/src/core/ui-packs/sk.ts +44 -0
  364. package/src/core/ui-packs/sr.ts +45 -0
  365. package/src/core/ui-packs/sv.ts +44 -0
  366. package/src/core/ui-packs/th.ts +43 -0
  367. package/src/core/ui-packs/tr.ts +45 -0
  368. package/src/core/ui-packs/uk.ts +45 -0
  369. package/src/core/ui-packs/vi.ts +45 -0
  370. package/src/core/ui-packs/zh-tw.ts +43 -0
  371. package/src/core/ui-packs/zh.ts +43 -0
  372. package/src/core/variables.ts +103 -0
  373. package/src/deploy/artifacts.ts +77 -8
  374. package/src/deploy/cloudflare-negotiation.ts +35 -5
  375. package/src/deploy/headers.ts +2 -1
  376. package/src/deploy/node-headers.ts +63 -9
  377. package/src/deploy/platforms/cloudflare.ts +32 -0
  378. package/src/deploy/platforms/netlify.ts +33 -1
  379. package/src/deploy/platforms/vercel.ts +37 -2
  380. package/src/deploy/redirects.ts +91 -24
  381. package/src/deploy/vercel-negotiation.ts +36 -0
  382. package/src/markdown/api-rail.ts +259 -0
  383. package/src/markdown/code-title.ts +35 -9
  384. package/src/markdown/features.ts +3 -2
  385. package/src/markdown/fence-meta.ts +2 -0
  386. package/src/markdown/include.ts +11 -1
  387. package/src/markdown/index.ts +28 -5
  388. package/src/markdown/math.ts +4 -4
  389. package/src/markdown/variables.ts +56 -0
  390. package/src/markdown/views.ts +82 -0
  391. package/src/narration/build.ts +412 -0
  392. package/src/narration/player.ts +249 -0
  393. package/src/narration/provider.ts +29 -0
  394. package/src/narration/script.ts +592 -0
  395. package/src/og/card.ts +7 -6
  396. package/src/openapi/model.ts +57 -24
  397. package/src/openapi/overlay.ts +256 -0
  398. package/src/openapi/parse.ts +55 -2
  399. package/src/openapi/references.ts +21 -5
  400. package/src/openapi/render-mdx.ts +5 -1
  401. package/src/openapi/scalar.ts +40 -6
  402. package/src/openapi/source.ts +1 -1
  403. package/src/ratelimit/cloudflare.ts +54 -0
  404. package/src/ratelimit/index.ts +30 -0
  405. package/src/ratelimit/memory.ts +45 -0
  406. package/src/ratelimit/runtime.ts +229 -0
  407. package/src/ratelimit/schema.ts +28 -0
  408. package/src/ratelimit/upstash.ts +30 -0
  409. package/src/ratelimit/wrangler.ts +70 -0
  410. package/src/reference/asyncapi.ts +2 -2
  411. package/src/reference/graphql.ts +5 -2
  412. package/src/reference/openapi.ts +21 -7
  413. package/src/reference/options.ts +51 -7
  414. package/src/reference/scalar.ts +33 -8
  415. package/src/registry/eject.ts +20 -4
  416. package/src/registry/registry.ts +7 -0
  417. package/src/search/documents.ts +26 -2
  418. package/src/search/orama-index.ts +28 -3
  419. package/src/search/pagefind-ranking.ts +39 -0
  420. package/src/search/sync/algolia.ts +15 -4
  421. package/src/search/sync/orama-cloud.ts +3 -0
  422. package/src/search/sync/typesense.ts +5 -0
  423. package/src/seo/metatags.ts +67 -0
  424. package/src/theme/chrome-icons.ts +1 -0
  425. package/src/theme/color.ts +500 -0
  426. package/src/theme/entry.ts +56 -3
  427. package/src/theme/palette.ts +121 -45
  428. package/src/translate/prompts.ts +1 -0
  429. package/src/translate/validate.ts +8 -2
  430. package/src/upgrade/upgrade.ts +4 -171
  431. package/dist/cli/chunk-364znk6q.js +0 -75
  432. package/dist/cli/chunk-364znk6q.js.map +0 -11
  433. package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
  434. package/dist/cli/chunk-9t7a85s3.js.map +0 -10
  435. package/dist/cli/chunk-c8chx29p.js.map +0 -36
  436. package/dist/cli/chunk-pehfxfta.js.map +0 -10
  437. package/dist/cli/chunk-pv29h0wf.js.map +0 -190
  438. package/dist/cli/chunk-q58y5e6a.js.map +0 -10
  439. package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
  440. package/dist/cli/chunk-yfyb25rh.js.map +0 -14
  441. package/docs/content/sources.mdx +0 -334
  442. /package/dist/cli/{chunk-2eytanqx.js.map → chunk-1n228xqb.js.map} +0 -0
  443. /package/dist/cli/{chunk-35d4wj9f.js.map → chunk-2n4ps1b3.js.map} +0 -0
  444. /package/dist/cli/{chunk-e04dxsz1.js.map → chunk-4ejxbzee.js.map} +0 -0
  445. /package/dist/cli/{chunk-tzmab476.js.map → chunk-5ffywsmb.js.map} +0 -0
  446. /package/dist/cli/{chunk-2z928egk.js.map → chunk-5wj2qwn2.js.map} +0 -0
  447. /package/dist/cli/{chunk-b07cmahc.js.map → chunk-amrb6hgh.js.map} +0 -0
  448. /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-cmtcnh9f.js.map} +0 -0
  449. /package/dist/cli/{chunk-crgn1q09.js.map → chunk-e7vvk5ya.js.map} +0 -0
  450. /package/dist/cli/{chunk-tkacnehg.js.map → chunk-gp84za0h.js.map} +0 -0
  451. /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-p804f3pe.js.map} +0 -0
  452. /package/dist/cli/{chunk-8ktnccpt.js.map → chunk-ta27feev.js.map} +0 -0
  453. /package/dist/cli/{chunk-a58773jm.js.map → chunk-y4ykbark.js.map} +0 -0
  454. /package/dist/cli/{chunk-p3v96n38.js.map → chunk-y5h4r2y0.js.map} +0 -0
  455. /package/dist/cli/{chunk-acanzt5p.js.map → chunk-yj17vs39.js.map} +0 -0
@@ -17,6 +17,7 @@ import {
17
17
  referenceRoutes,
18
18
  hasScalarReferences,
19
19
  builtinProxyReferences,
20
+ apiPagesUseBuiltinProxy,
20
21
  needsPlaygroundProxy,
21
22
  buildMcpDiscovery,
22
23
  buildMcpServerCard,
@@ -28,6 +29,8 @@ import {
28
29
  hasGeneratedChangelog,
29
30
  customOgRoutes,
30
31
  resolveAskBackend,
32
+ captchaSettings,
33
+ parseApiEndpoint,
31
34
  GOOGLE_FONTS,
32
35
  isFontSlug,
33
36
  fontLocaleCodes,
@@ -46,10 +49,11 @@ import {
46
49
  renderRssFeed,
47
50
  HTTP_METHODS,
48
51
  withServerDefaults,
52
+ readOverlaidSpec,
49
53
  isOpenApiSource,
50
54
  buildRawMarkdown,
51
55
  markdownRoutePaths
52
- } from "./chunk-pv29h0wf.js";
56
+ } from "./chunk-xkz5xbtv.js";
53
57
  import {
54
58
  trimChar,
55
59
  normalizeBasePath,
@@ -57,15 +61,17 @@ import {
57
61
  mountBasePath,
58
62
  siteRoot,
59
63
  absoluteUrl2
60
- } from "./chunk-3em5wd2y.js";
64
+ } from "./chunk-zccbjcj0.js";
61
65
  import {
66
+ resolveLocalizable,
62
67
  validateSearchPopularIcons,
63
68
  validateNavTargets
64
- } from "./chunk-j85vccga.js";
69
+ } from "./chunk-43zcf4gz.js";
65
70
  import {
71
+ EXPANDABLE_VISIBLE_LINES,
66
72
  buildSearchDocuments,
67
73
  buildMcpData
68
- } from "./chunk-yfyb25rh.js";
74
+ } from "./chunk-2f3ndkpw.js";
69
75
  import {
70
76
  planComponentSlots,
71
77
  publishRuntimeModules,
@@ -77,6 +83,7 @@ import {
77
83
  askComponentTemplate,
78
84
  searchEndpointTemplate,
79
85
  featuresTemplate,
86
+ consentClientTemplate,
80
87
  searchClientTemplate,
81
88
  mixedbreadSearchEndpointTemplate,
82
89
  rawMarkdownEndpointTemplate,
@@ -105,32 +112,129 @@ import {
105
112
  examplesPageTemplate,
106
113
  runtimePackageTemplate,
107
114
  runtimeTsconfigTemplate
108
- } from "./chunk-5m5nmvyq.js";
115
+ } from "./chunk-4h8z9vv5.js";
109
116
  import {
110
117
  emptyComponentOverrides,
111
118
  analyzeComponentOverrides
112
- } from "./chunk-8ktnccpt.js";
119
+ } from "./chunk-ta27feev.js";
113
120
  import {
114
121
  writeTextAtomic
115
122
  } from "./chunk-jq5n4avg.js";
123
+ import {
124
+ resolveAccent,
125
+ resolveRadius,
126
+ buildThemeCss
127
+ } from "./chunk-cm89scdv.js";
116
128
  import {
117
129
  registry
118
- } from "./chunk-r20tn01b.js";
130
+ } from "./chunk-2f7n4qzt.js";
119
131
  import {
120
132
  readClientMode,
121
133
  discoverIslands,
122
134
  missingDependencyDiagnostic
123
- } from "./chunk-b07cmahc.js";
135
+ } from "./chunk-amrb6hgh.js";
124
136
 
125
137
  // src/astro/integration.ts
126
- import { join as join3, relative, resolve as resolve2 } from "pathe";
138
+ import { join as join4, relative, resolve as resolve2 } from "pathe";
127
139
 
128
140
  // src/deploy/artifacts.ts
129
- import { dirname as dirname2, join as join2, resolve } from "pathe";
141
+ import { dirname as dirname3, join as join3, resolve } from "pathe";
142
+
143
+ // src/narration/build.ts
144
+ import { createGateway, generateSpeech } from "ai";
145
+ import { HTMLElement, parse, TextNode } from "node-html-parser";
146
+ import { dirname, join } from "pathe";
147
+
148
+ // src/narration/script.ts
149
+ var INLINE_TAGS = new Set([
150
+ "a",
151
+ "abbr",
152
+ "audio",
153
+ "button",
154
+ "canvas",
155
+ "embed",
156
+ "iframe",
157
+ "img",
158
+ "input",
159
+ "math",
160
+ "noscript",
161
+ "object",
162
+ "picture",
163
+ "script",
164
+ "select",
165
+ "style",
166
+ "svg",
167
+ "template",
168
+ "textarea",
169
+ "video",
170
+ "b",
171
+ "bdi",
172
+ "bdo",
173
+ "cite",
174
+ "code",
175
+ "data",
176
+ "del",
177
+ "dfn",
178
+ "em",
179
+ "font",
180
+ "i",
181
+ "ins",
182
+ "kbd",
183
+ "label",
184
+ "mark",
185
+ "q",
186
+ "s",
187
+ "samp",
188
+ "small",
189
+ "span",
190
+ "strong",
191
+ "sub",
192
+ "sup",
193
+ "time",
194
+ "u",
195
+ "var",
196
+ "wbr"
197
+ ]);
198
+ var SKIPPED_TAGS = new Set([
199
+ "audio",
200
+ "blume-diff",
201
+ "blume-mermaid",
202
+ "button",
203
+ "canvas",
204
+ "dialog",
205
+ "embed",
206
+ "figure",
207
+ "iframe",
208
+ "img",
209
+ "input",
210
+ "math",
211
+ "nav",
212
+ "noscript",
213
+ "object",
214
+ "picture",
215
+ "pre",
216
+ "script",
217
+ "select",
218
+ "style",
219
+ "svg",
220
+ "table",
221
+ "template",
222
+ "textarea",
223
+ "video"
224
+ ]);
225
+ var CALLOUT_KINDS = new Set([
226
+ "danger",
227
+ "info",
228
+ "note",
229
+ "success",
230
+ "tip",
231
+ "warning"
232
+ ]);
233
+ var DENSE_SCRIPT_LANGS = new Set(["ja", "ko", "zh"]);
130
234
 
131
235
  // src/search/build.ts
132
236
  import { close, createIndex } from "pagefind";
133
- import { dirname, join } from "pathe";
237
+ import { dirname as dirname2, join as join2 } from "pathe";
134
238
 
135
239
  // src/deploy/sitemap.ts
136
240
  import { escape as escapeXml } from "html-escaper";
@@ -226,8 +330,8 @@ import {
226
330
  rm,
227
331
  writeFile
228
332
  } from "node:fs/promises";
229
- import { dirname as dirname3, join as join4 } from "pathe";
230
- var ogCacheDir = (context) => existsSync(join4(context.root, "node_modules")) ? join4(context.root, "node_modules", ".cache", "blume", "og") : join4(context.outDir, ".cache", "og");
333
+ import { dirname as dirname4, join as join5 } from "pathe";
334
+ var ogCacheDir = (context) => existsSync(join5(context.root, "node_modules")) ? join5(context.root, "node_modules", ".cache", "blume", "og") : join5(context.outDir, ".cache", "og");
231
335
  var REGISTRY_KEY2 = Symbol.for("blume.og-cache");
232
336
  var registry3 = () => {
233
337
  const host = globalThis;
@@ -245,7 +349,7 @@ var pruneCardCache = async (dir) => {
245
349
  return 0;
246
350
  }
247
351
  const stale = entries.filter((name) => name.endsWith(".tmp") || name.endsWith(".png") && !used.has(name.slice(0, -".png".length)));
248
- await Promise.all(stale.map((name) => rm(join4(dir, name), { force: true })));
352
+ await Promise.all(stale.map((name) => rm(join5(dir, name), { force: true })));
249
353
  return stale.length;
250
354
  };
251
355
  var cardCacheTally = () => {
@@ -268,7 +372,7 @@ import {
268
372
  import { createRequire as createRequire2 } from "node:module";
269
373
  import { pathToFileURL } from "node:url";
270
374
  import pMap2 from "p-map";
271
- import { dirname as dirname7, isAbsolute as isAbsolute6, join as join11, normalize as normalize2, relative as relative5, resolve as resolve6 } from "pathe";
375
+ import { dirname as dirname8, isAbsolute as isAbsolute6, join as join12, normalize as normalize2, relative as relative5, resolve as resolve6 } from "pathe";
272
376
  import { glob as glob2 } from "tinyglobby";
273
377
 
274
378
  // src/ai/api/problem.ts
@@ -813,6 +917,12 @@ var buildAskData = async (project) => {
813
917
  if (versioned) {
814
918
  document.version = doc.version;
815
919
  }
920
+ if (doc.boost !== undefined) {
921
+ document.boost = doc.boost;
922
+ }
923
+ if (doc.keywords) {
924
+ document.keywords = doc.keywords;
925
+ }
816
926
  return document;
817
927
  }),
818
928
  site: project.config.deployment.options.site ?? null
@@ -865,7 +975,11 @@ var BUILTIN_MDX_TAGS = new Set([
865
975
  "Math",
866
976
  "Operation",
867
977
  "Panel",
978
+ "ParamField",
868
979
  "Prompt",
980
+ "RequestExample",
981
+ "ResponseExample",
982
+ "ResponseField",
869
983
  "Step",
870
984
  "Steps",
871
985
  "Tab",
@@ -874,6 +988,7 @@ var BUILTIN_MDX_TAGS = new Set([
874
988
  "Tooltip",
875
989
  "Tree",
876
990
  "TypeTable",
991
+ "View",
877
992
  "Visibility",
878
993
  "YouTube"
879
994
  ]);
@@ -968,7 +1083,7 @@ var svgDimensions = (svg) => {
968
1083
 
969
1084
  // src/core/tsconfig-aliases.ts
970
1085
  import { existsSync as existsSync2 } from "node:fs";
971
- import { dirname as dirname4, join as join5, resolve as resolve3 } from "pathe";
1086
+ import { dirname as dirname5, join as join6, resolve as resolve3 } from "pathe";
972
1087
  import ts from "typescript";
973
1088
  var PARSE_HOST = {
974
1089
  fileExists: ts.sys.fileExists,
@@ -990,7 +1105,7 @@ var toAlias = (key, value, baseDir) => {
990
1105
  return { find, replacement: resolve3(baseDir, target) };
991
1106
  };
992
1107
  var resolveTsconfigAliases = (root) => {
993
- const entry = ["tsconfig.json", "jsconfig.json"].map((name) => join5(root, name)).find((file) => existsSync2(file));
1108
+ const entry = ["tsconfig.json", "jsconfig.json"].map((name) => join6(root, name)).find((file) => existsSync2(file));
994
1109
  if (!entry) {
995
1110
  return {};
996
1111
  }
@@ -998,7 +1113,7 @@ var resolveTsconfigAliases = (root) => {
998
1113
  if (error) {
999
1114
  return {};
1000
1115
  }
1001
- const configDir = dirname4(entry);
1116
+ const configDir = dirname5(entry);
1002
1117
  const { options } = ts.parseJsonConfigFileContent(config, PARSE_HOST, configDir, undefined, entry);
1003
1118
  const { paths } = options;
1004
1119
  if (!paths) {
@@ -1151,9 +1266,9 @@ var hasMermaidFence = (text) => MERMAID_FENCE.test(text);
1151
1266
 
1152
1267
  // src/og/derive.ts
1153
1268
  import { existsSync as existsSync3 } from "node:fs";
1154
- import { isAbsolute, join as join6 } from "pathe";
1269
+ import { isAbsolute, join as join7 } from "pathe";
1155
1270
  var CARD_WEIGHTS = [400, 600];
1156
- var absoluteSrc = (root, src) => isAbsolute(src) ? src : join6(root, src);
1271
+ var absoluteSrc = (root, src) => isAbsolute(src) ? src : join7(root, src);
1157
1272
  var isNumericWeight = (weight) => typeof weight === "number";
1158
1273
  var isRangeWeight = (weight) => typeof weight === "string";
1159
1274
  var isFontName = (value) => typeof value === "string";
@@ -1334,98 +1449,22 @@ var missingFontFiles = (options, root) => {
1334
1449
 
1335
1450
  // src/og/logo.ts
1336
1451
  import { existsSync as existsSync4, readFileSync } from "node:fs";
1337
- import { join as join7 } from "pathe";
1452
+ import { join as join8 } from "pathe";
1338
1453
  var resolveOgLogo = (project, source) => {
1339
1454
  if (!source?.toLowerCase().endsWith(".svg")) {
1340
1455
  return;
1341
1456
  }
1342
1457
  const relative = source.replace(/^\//u, "");
1343
1458
  const file = [
1344
- join7(project.context.root, "public", relative),
1345
- join7(project.context.root, relative)
1459
+ join8(project.context.root, "public", relative),
1460
+ join8(project.context.root, relative)
1346
1461
  ].find((path) => existsSync4(path));
1347
1462
  return file ? readFileSync(file, "utf-8") : undefined;
1348
1463
  };
1349
1464
 
1350
1465
  // src/openapi/scalar.ts
1351
1466
  import { readFile as readFile2 } from "node:fs/promises";
1352
- import { isAbsolute as isAbsolute2, join as join8 } from "pathe";
1353
-
1354
- // src/theme/palette.ts
1355
- var FALLBACK_ACCENT = "oklch(0.62 0.16 250)";
1356
- var ACCENTS = {
1357
- blue: FALLBACK_ACCENT,
1358
- green: "oklch(0.6 0.16 150)",
1359
- orange: "oklch(0.68 0.17 50)",
1360
- pink: "oklch(0.65 0.2 350)",
1361
- purple: "oklch(0.58 0.2 290)",
1362
- red: "oklch(0.58 0.22 25)",
1363
- teal: "oklch(0.6 0.12 195)"
1364
- };
1365
- var isAccentPreset = (value) => Object.hasOwn(ACCENTS, value);
1366
- var CSS_COLOR = /^[\w\s#%.,()/+-]+$/u;
1367
- var safeColor = (value, fallback) => CSS_COLOR.test(value.trim()) ? value.trim() : fallback;
1368
- var presetOrColor = (value) => isAccentPreset(value) ? ACCENTS[value] : safeColor(value, FALLBACK_ACCENT);
1369
- var safeColorOrNull = (value) => value && CSS_COLOR.test(value.trim()) ? value.trim() : null;
1370
- var RADII = {
1371
- lg: "0.75rem",
1372
- md: "0.5rem",
1373
- none: "0",
1374
- sm: "0.25rem"
1375
- };
1376
- var cssString = (value) => JSON.stringify(value);
1377
- var backgroundImageCss = (image) => `url(${cssString(image)})`;
1378
- var cssToken = (name, value) => value ? [` ${name}: ${value};`] : [];
1379
- var themeRootCss = (theme, options) => [
1380
- ` --blume-accent: ${options.accent};`,
1381
- ...cssToken("--blume-action", options.action),
1382
- ...cssToken("--blume-action-foreground", options.action ? "oklch(1 0 0)" : null),
1383
- ...cssToken("--blume-background", safeColorOrNull(theme.background?.light)),
1384
- ...cssToken("--blume-background-image", theme.backgroundImage?.light ? backgroundImageCss(theme.backgroundImage.light) : null),
1385
- ` --blume-radius: ${options.radius};`
1386
- ].filter(Boolean).join(`
1387
- `);
1388
- var themeDarkCss = (theme, options) => {
1389
- const tokens = [
1390
- ` --blume-accent: ${options.accent};`,
1391
- " --blume-accent-foreground: oklch(1 0 0);",
1392
- ...cssToken("--blume-action", options.action),
1393
- ...cssToken("--blume-action-foreground", options.action ? "oklch(1 0 0)" : null),
1394
- ...cssToken("--blume-background", safeColorOrNull(theme.background?.dark)),
1395
- ...cssToken("--blume-background-image", theme.backgroundImage?.dark ? backgroundImageCss(theme.backgroundImage.dark) : null)
1396
- ].filter(Boolean);
1397
- return `:root[data-theme="dark"] {
1398
- ${tokens.join(`
1399
- `)}
1400
- }
1401
- `;
1402
- };
1403
- var resolveAccent = (theme) => ({
1404
- dark: presetOrColor(theme.accent.dark),
1405
- light: presetOrColor(theme.accent.light)
1406
- });
1407
- var resolveRadius = (theme) => RADII[theme.radius];
1408
- var buildThemeCss = (theme) => {
1409
- const accent = resolveAccent(theme);
1410
- const action = theme.action ? presetOrColor(theme.action) : null;
1411
- const radius = RADII[theme.radius];
1412
- const root = themeRootCss(theme, {
1413
- accent: accent.light,
1414
- action,
1415
- radius
1416
- });
1417
- const dark = themeDarkCss(theme, {
1418
- accent: accent.dark,
1419
- action
1420
- });
1421
- return `/* Generated by Blume from theme config. */
1422
- :root {
1423
- ${root}
1424
- }
1425
- ${dark}`;
1426
- };
1427
-
1428
- // src/openapi/scalar.ts
1467
+ import { isAbsolute as isAbsolute2, join as join9 } from "pathe";
1429
1468
  var URL_SPEC = /^https?:\/\//u;
1430
1469
  var referencePagePath = (route) => {
1431
1470
  const segments = trimChar(route, "/");
@@ -1441,11 +1480,28 @@ var themeConfiguration = (config, override) => {
1441
1480
  customCss: `:root,.light-mode,.dark-mode{--scalar-color-accent:${accent.light};--scalar-radius:${radius};}.dark-mode{--scalar-color-accent:${accent.dark};}`
1442
1481
  };
1443
1482
  };
1444
- var specConfiguration = async (spec, root) => {
1483
+ var overlaidConfiguration = async (ref, root) => {
1484
+ try {
1485
+ const { text, warnings } = await readOverlaidSpec(ref.spec, root, {
1486
+ overlays: ref.overlays
1487
+ });
1488
+ return { config: { content: text }, warning: warnings[0] };
1489
+ } catch (error) {
1490
+ const { message } = error;
1491
+ return {
1492
+ warning: `API reference ${ref.route} was skipped: its overlays couldn't be applied to "${ref.spec}" (${message}).`
1493
+ };
1494
+ }
1495
+ };
1496
+ var specConfiguration = async (ref, root) => {
1497
+ const { spec } = ref;
1498
+ if (ref.overlays?.length) {
1499
+ return await overlaidConfiguration(ref, root);
1500
+ }
1445
1501
  if (URL_SPEC.test(spec)) {
1446
1502
  return { config: { url: spec } };
1447
1503
  }
1448
- const absolute = isAbsolute2(spec) ? spec : join8(root, spec);
1504
+ const absolute = isAbsolute2(spec) ? spec : join9(root, spec);
1449
1505
  try {
1450
1506
  return { config: { content: await readFile2(absolute, "utf-8") } };
1451
1507
  } catch {
@@ -1483,13 +1539,16 @@ var buildReferenceFiles = async (options) => {
1483
1539
  }
1484
1540
  const built = await Promise.all(accepted.map(async (ref) => ({
1485
1541
  ref,
1486
- spec: await specConfiguration(ref.spec, root)
1542
+ spec: await specConfiguration(ref, root)
1487
1543
  })));
1488
1544
  const files = [];
1489
1545
  for (const { ref, spec } of built) {
1490
1546
  if (spec.warning) {
1491
1547
  warnings.push(spec.warning);
1492
1548
  }
1549
+ if (!spec.config) {
1550
+ continue;
1551
+ }
1493
1552
  const pagePath = referencePagePath(ref.route);
1494
1553
  const { theme, ...passthrough } = ref.scalar ?? {};
1495
1554
  files.push({
@@ -2077,14 +2136,60 @@ ${options.languageIcons ?? ""}
2077
2136
  transparent;
2078
2137
  }
2079
2138
 
2080
- /* Word wrap (markdown.code.wrap): long lines wrap instead of scrolling. The
2081
- attribute is set on <body> from config; default code keeps \`white-space: pre\`. */
2139
+ /* Word wrap: long lines wrap instead of scrolling, on every block
2140
+ (markdown.code.wrap, an attribute on <body>) or on one (\`\`\`ts wrap, which
2141
+ Shiki's fence-meta reader sets as data-wrap). Default code keeps
2142
+ \`white-space: pre\`. */
2082
2143
  [data-blume-code-wrap] pre,
2083
- [data-blume-code-wrap] pre code {
2144
+ [data-blume-code-wrap] pre code,
2145
+ pre[data-wrap],
2146
+ pre[data-wrap] code {
2084
2147
  overflow-wrap: break-word;
2085
2148
  white-space: pre-wrap;
2086
2149
  }
2087
2150
 
2151
+ /* An expandable block (\`\`\`ts expandable) starts collapsed to its first lines,
2152
+ faded out toward the cut, with a toggle under it (added by the layout
2153
+ script). Opened, it shows in full: no height cap and no inner scroll. The
2154
+ collapse needs that script to undo it, so a page without scripting shows
2155
+ the block the ordinary way. */
2156
+ @media (scripting: enabled) {
2157
+ .prose pre[data-expandable]:not([data-expanded]) > code {
2158
+ max-height: calc(${EXPANDABLE_VISIBLE_LINES}lh + ${CODE_SCROLL_INSET_REM}rem);
2159
+ mask-image: linear-gradient(to bottom, #000 calc(100% - 3lh), transparent);
2160
+ overflow-y: hidden;
2161
+ }
2162
+ }
2163
+
2164
+ .prose pre[data-expandable][data-expanded] > code {
2165
+ max-height: none;
2166
+ }
2167
+
2168
+ [data-blume-code-expand] {
2169
+ align-items: center;
2170
+ color: var(--blume-muted-foreground);
2171
+ display: flex;
2172
+ font-family: var(--font-sans);
2173
+ font-size: 0.75rem;
2174
+ font-weight: 500;
2175
+ gap: 0.25rem;
2176
+ justify-content: center;
2177
+ padding-top: 0.5rem;
2178
+ width: 100%;
2179
+ }
2180
+
2181
+ [data-blume-code-expand]:hover {
2182
+ color: var(--blume-foreground);
2183
+ }
2184
+
2185
+ [data-blume-code-expand] svg {
2186
+ transition: transform 150ms;
2187
+ }
2188
+
2189
+ [data-blume-code-expand][aria-expanded="true"] svg {
2190
+ transform: rotate(180deg);
2191
+ }
2192
+
2088
2193
  .prose :where(table) {
2089
2194
  font-size: 0.8125rem;
2090
2195
  }
@@ -2196,6 +2301,12 @@ blume-tabs pre[data-language],
2196
2301
  padding-inline-end: 3.5rem;
2197
2302
  }
2198
2303
 
2304
+ /* With the assistant on, an Ask button sits beside the copy button, so the
2305
+ line's tail clears both. */
2306
+ .prose :is(blume-tabs pre, .not-prose pre, pre:not([data-language])):not(.twoslash, .twoslash pre, blume-panel-tabs *):has(> [data-blume-ask]) > code {
2307
+ padding-inline-end: 5.75rem;
2308
+ }
2309
+
2199
2310
  blume-tabs pre[data-language]::before,
2200
2311
  .not-prose pre[data-language]::before {
2201
2312
  content: none;
@@ -2446,10 +2557,10 @@ ${options.userCss}
2446
2557
  `;
2447
2558
 
2448
2559
  // src/theme/sources.ts
2449
- import { dirname as dirname5, isAbsolute as isAbsolute3, relative as relative2, resolve as resolve4 } from "pathe";
2560
+ import { dirname as dirname6, isAbsolute as isAbsolute3, relative as relative2, resolve as resolve4 } from "pathe";
2450
2561
  var SOURCE_DIRECTIVE = /@source(?<not>\s+not)?\s+(?<quote>["'])(?<path>[^"']+)\k<quote>/gu;
2451
2562
  var rebaseSourceDirectives = (css, options) => {
2452
- const base = dirname5(options.from);
2563
+ const base = dirname6(options.from);
2453
2564
  return css.replace(SOURCE_DIRECTIVE, (directive, not, quote, path) => {
2454
2565
  if (isAbsolute3(path)) {
2455
2566
  return directive;
@@ -2544,7 +2655,7 @@ ${OVERRIDES}`;
2544
2655
  // src/astro/examples.ts
2545
2656
  import { readFile as readFile3 } from "node:fs/promises";
2546
2657
  import pMap from "p-map";
2547
- import { isAbsolute as isAbsolute4, join as join9, relative as relative3 } from "pathe";
2658
+ import { isAbsolute as isAbsolute4, join as join10, relative as relative3 } from "pathe";
2548
2659
  import { glob } from "tinyglobby";
2549
2660
  var FRAMEWORK_BY_EXT = {
2550
2661
  astro: "astro",
@@ -2573,7 +2684,7 @@ var splitGlobBase = (pattern) => {
2573
2684
  };
2574
2685
  var discoverExamples = async (root, pattern = "examples") => {
2575
2686
  const { base, rest } = GLOB_MAGIC.test(pattern) ? splitGlobBase(pattern) : { base: pattern, rest: DEFAULT_EXAMPLE_GLOB };
2576
- const dir = join9(root, base);
2687
+ const dir = join10(root, base);
2577
2688
  const matches = await glob([rest], {
2578
2689
  absolute: true,
2579
2690
  cwd: dir,
@@ -2622,26 +2733,26 @@ var exampleMarkdownLookup = (examples) => Object.fromEntries(examples.map((examp
2622
2733
  import { existsSync as existsSync5, realpathSync } from "node:fs";
2623
2734
  import {
2624
2735
  basename,
2625
- dirname as dirname6,
2736
+ dirname as dirname7,
2626
2737
  isAbsolute as isAbsolute5,
2627
- join as join10,
2738
+ join as join11,
2628
2739
  normalize,
2629
2740
  relative as relative4,
2630
2741
  resolve as resolve5
2631
2742
  } from "pathe";
2632
2743
  var depsCandidates = (pkgDir) => [
2633
- join10(pkgDir, "node_modules"),
2634
- dirname6(pkgDir)
2744
+ join11(pkgDir, "node_modules"),
2745
+ dirname7(pkgDir)
2635
2746
  ];
2636
- var candidateHolding = (pkgDir, ...segments) => depsCandidates(pkgDir).find((dir) => existsSync5(join10(dir, ...segments))) ?? null;
2747
+ var candidateHolding = (pkgDir, ...segments) => depsCandidates(pkgDir).find((dir) => existsSync5(join11(dir, ...segments))) ?? null;
2637
2748
  var packageDirFrom = (name, fromDir) => {
2638
2749
  let dir = normalize(fromDir);
2639
2750
  while (true) {
2640
- const candidate = join10(dir, "node_modules", name);
2641
- if (existsSync5(join10(candidate, "package.json"))) {
2751
+ const candidate = join11(dir, "node_modules", name);
2752
+ if (existsSync5(join11(candidate, "package.json"))) {
2642
2753
  return normalize(realpathSync(candidate));
2643
2754
  }
2644
- const parent = dirname6(dir);
2755
+ const parent = dirname7(dir);
2645
2756
  if (parent === dir) {
2646
2757
  return null;
2647
2758
  }
@@ -2650,13 +2761,13 @@ var packageDirFrom = (name, fromDir) => {
2650
2761
  };
2651
2762
 
2652
2763
  // src/astro/generate.ts
2653
- var BLUME_SRC = join11(packageRoot(), "src");
2764
+ var BLUME_SRC = join12(packageRoot(), "src");
2654
2765
  var resolveReactCompiler = (config, needsReact, pkgDir = packageRoot()) => {
2655
2766
  if (!(needsReact && config.react.compiler)) {
2656
2767
  return null;
2657
2768
  }
2658
2769
  try {
2659
- return createRequire2(pathToFileURL(join11(pkgDir, "_.js")).href).resolve("babel-plugin-react-compiler");
2770
+ return createRequire2(pathToFileURL(join12(pkgDir, "_.js")).href).resolve("babel-plugin-react-compiler");
2660
2771
  } catch {
2661
2772
  return null;
2662
2773
  }
@@ -2666,7 +2777,7 @@ var reactCompilerWarnings = (config, needsReact, compilerPath) => needsReact &&
2666
2777
  ] : [];
2667
2778
  var resolveAstroPackageJson = (modulesDir) => {
2668
2779
  try {
2669
- return realpathSync2(join11(modulesDir, "astro", "package.json"));
2780
+ return realpathSync2(join12(modulesDir, "astro", "package.json"));
2670
2781
  } catch {
2671
2782
  return null;
2672
2783
  }
@@ -2674,12 +2785,12 @@ var resolveAstroPackageJson = (modulesDir) => {
2674
2785
  var resolvedAstroHit = (fromDir) => {
2675
2786
  let dir = normalize2(fromDir);
2676
2787
  while (true) {
2677
- const modulesDir = join11(dir, "node_modules");
2788
+ const modulesDir = join12(dir, "node_modules");
2678
2789
  const pkg = resolveAstroPackageJson(modulesDir);
2679
2790
  if (pkg) {
2680
2791
  return { modulesDir, pkg };
2681
2792
  }
2682
- const parent = dirname7(dir);
2793
+ const parent = dirname8(dir);
2683
2794
  if (parent === dir) {
2684
2795
  return null;
2685
2796
  }
@@ -2712,13 +2823,13 @@ var linkDepsJunction = async (link, depsDir) => {
2712
2823
  return;
2713
2824
  }
2714
2825
  try {
2715
- if (resolve6(dirname7(link), await readlink(link)) === resolve6(depsDir)) {
2826
+ if (resolve6(dirname8(link), await readlink(link)) === resolve6(depsDir)) {
2716
2827
  return;
2717
2828
  }
2718
2829
  } catch {}
2719
2830
  await rm2(link, { force: true });
2720
2831
  }
2721
- await mkdir2(dirname7(link), { recursive: true });
2832
+ await mkdir2(dirname8(link), { recursive: true });
2722
2833
  await symlinkDir(depsDir, link);
2723
2834
  };
2724
2835
  var readPkgVersion = (pkgJsonPath) => {
@@ -2751,7 +2862,7 @@ var dropStaleDepsLink = async (link, pkgDir) => {
2751
2862
  let linkedBlume;
2752
2863
  let runningBlume;
2753
2864
  try {
2754
- linkedBlume = await realpath(join11(link, "blume"));
2865
+ linkedBlume = await realpath(join12(link, "blume"));
2755
2866
  runningBlume = await realpath(pkgDir);
2756
2867
  } catch {
2757
2868
  return;
@@ -2767,7 +2878,7 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
2767
2878
  }
2768
2879
  const mdxDir = candidateHolding(pkgDir, "@astrojs", "mdx");
2769
2880
  const blumeAstro = resolveAstroPackageJson(astroDir);
2770
- await dropStaleDepsLink(join11(outDir, "node_modules"), pkgDir);
2881
+ await dropStaleDepsLink(join12(outDir, "node_modules"), pkgDir);
2771
2882
  const outDirHit = resolvedAstroHit(outDir);
2772
2883
  const astroCorrect = blumeAstro !== null && outDirHit?.pkg === blumeAstro;
2773
2884
  const walkLandsInDeps = astroCorrect && outDirHit !== null && sameRealDir(outDirHit.modulesDir, astroDir);
@@ -2775,16 +2886,16 @@ var ensureDepsLink = async (outDir, pkgDir = packageRoot()) => {
2775
2886
  return null;
2776
2887
  }
2777
2888
  if (mdxDir && (mdxDir === astroDir || astroCorrect)) {
2778
- await linkDepsJunction(join11(outDir, "node_modules"), mdxDir);
2889
+ await linkDepsJunction(join12(outDir, "node_modules"), mdxDir);
2779
2890
  return null;
2780
2891
  }
2781
2892
  return astroConflictWarning(blumeAstro, outDirHit?.pkg ?? null);
2782
2893
  };
2783
- var examplesCssFile = (root, config) => config.examples.css ? join11(root, config.examples.css) : null;
2894
+ var examplesCssFile = (root, config) => config.examples.css ? join12(root, config.examples.css) : null;
2784
2895
  var writeExamplesPreview = async (options) => {
2785
2896
  const { config, hasExamples, root, srcDir, write } = options;
2786
2897
  if (hasExamples) {
2787
- await write(join11(srcDir, "pages", ...config.basePath.split("/").filter(Boolean), "blume-examples", "[...path].astro"), examplesPageTemplate());
2898
+ await write(join12(srcDir, "pages", ...config.basePath.split("/").filter(Boolean), "blume-examples", "[...path].astro"), examplesPageTemplate());
2788
2899
  }
2789
2900
  const cssFile = examplesCssFile(root, config);
2790
2901
  return cssFile && !existsSync6(cssFile) ? [
@@ -2821,7 +2932,7 @@ var detectUsesMath = async (root, staged = []) => {
2821
2932
  ignore: ["**/node_modules/**", "**/.blume/**", "**/dist/**"],
2822
2933
  onlyFiles: true
2823
2934
  });
2824
- const contents = await pMap2(files, (file) => readOptional(join11(root, file)), {
2935
+ const contents = await pMap2(files, (file) => readOptional(join12(root, file)), {
2825
2936
  concurrency: READ_CONCURRENCY2
2826
2937
  });
2827
2938
  return [...contents, ...staged].some(containsMath);
@@ -2883,7 +2994,7 @@ var writeStagedContent = async (out, staged) => {
2883
2994
  const contentDir = stagedContentDir(out);
2884
2995
  const written = new Set;
2885
2996
  await Promise.all([...staged].map(async ([entryId, text]) => {
2886
- const path = join11(contentDir, entryId);
2997
+ const path = join12(contentDir, entryId);
2887
2998
  written.add(normalize2(path));
2888
2999
  await writeIfChanged(path, text);
2889
3000
  }));
@@ -2898,13 +3009,13 @@ var readLogoSvg = (project, source) => {
2898
3009
  }
2899
3010
  const rel = source.replace(/^\//u, "");
2900
3011
  const file = [
2901
- join11(project.context.root, "public", rel),
2902
- join11(project.context.root, rel)
3012
+ join12(project.context.root, "public", rel),
3013
+ join12(project.context.root, rel)
2903
3014
  ].find((path) => existsSync6(path));
2904
3015
  return file ? readFileSync3(file, "utf-8") : undefined;
2905
3016
  };
2906
3017
  var isStringShorthand = (value) => typeof value === "string";
2907
- var headerRepoUrl = (repo, derived) => {
3018
+ var footerRepoUrl = (repo, derived) => {
2908
3019
  if (isStringShorthand(repo)) {
2909
3020
  return repo;
2910
3021
  }
@@ -2955,10 +3066,10 @@ var faviconType = (name) => {
2955
3066
  var inlineDataUri = (file, type) => `data:${type};base64,${readFileSync3(file).toString("base64")}`;
2956
3067
  var defaultFavicon = () => ({
2957
3068
  dark: {
2958
- href: inlineDataUri(join11(BLUME_SRC, "assets", "icon-dark.png"), "image/png"),
3069
+ href: inlineDataUri(join12(BLUME_SRC, "assets", "icon-dark.png"), "image/png"),
2959
3070
  type: "image/png"
2960
3071
  },
2961
- href: inlineDataUri(join11(BLUME_SRC, "assets", "icon.png"), "image/png"),
3072
+ href: inlineDataUri(join12(BLUME_SRC, "assets", "icon.png"), "image/png"),
2962
3073
  type: "image/png"
2963
3074
  });
2964
3075
  var APPLE_ICON_CANDIDATES = [
@@ -2970,12 +3081,12 @@ var APPLE_ICON_CANDIDATES = [
2970
3081
  var resolveIconFile = (project, candidates) => {
2971
3082
  const { root } = project.context;
2972
3083
  for (const name of candidates) {
2973
- if (existsSync6(join11(root, "public", name))) {
3084
+ if (existsSync6(join12(root, "public", name))) {
2974
3085
  return { href: `/${name}`, type: faviconType(name) };
2975
3086
  }
2976
3087
  }
2977
3088
  for (const name of candidates) {
2978
- const file = join11(root, name);
3089
+ const file = join12(root, name);
2979
3090
  if (existsSync6(file)) {
2980
3091
  const type = faviconType(name);
2981
3092
  return { href: inlineDataUri(file, type ?? "image/x-icon"), type };
@@ -2986,18 +3097,18 @@ var resolveIconFile = (project, candidates) => {
2986
3097
  var resolveFavicon = (project) => {
2987
3098
  const { root } = project.context;
2988
3099
  for (const name of FAVICON_CANDIDATES) {
2989
- if (existsSync6(join11(root, "public", name))) {
3100
+ if (existsSync6(join12(root, "public", name))) {
2990
3101
  const type = faviconType(name);
2991
3102
  const sibling = darkSibling(name);
2992
- return existsSync6(join11(root, "public", sibling)) ? { dark: { href: `/${sibling}`, type }, href: `/${name}`, type } : { href: `/${name}`, type };
3103
+ return existsSync6(join12(root, "public", sibling)) ? { dark: { href: `/${sibling}`, type }, href: `/${name}`, type } : { href: `/${name}`, type };
2993
3104
  }
2994
3105
  }
2995
3106
  for (const name of FAVICON_CANDIDATES) {
2996
- const file = join11(root, name);
3107
+ const file = join12(root, name);
2997
3108
  if (existsSync6(file)) {
2998
3109
  const type = faviconType(name);
2999
3110
  const mime = type ?? "image/x-icon";
3000
- const siblingFile = join11(root, darkSibling(name));
3111
+ const siblingFile = join12(root, darkSibling(name));
3001
3112
  return existsSync6(siblingFile) ? {
3002
3113
  dark: { href: inlineDataUri(siblingFile, mime), type },
3003
3114
  href: inlineDataUri(file, mime),
@@ -3019,10 +3130,31 @@ var resolveBanner = (config) => {
3019
3130
  return {
3020
3131
  content: banner.content,
3021
3132
  dismissible: banner.dismissible,
3022
- key: banner.id ?? banner.content,
3133
+ key: banner.id ?? resolveLocalizable(banner.content, undefined, config.i18n?.defaultLocale),
3023
3134
  link: banner.link
3024
3135
  };
3025
3136
  };
3137
+ var playgroundProxyPattern = (config) => withBasePath(config.basePath, "/_api-proxy");
3138
+ var resolveApiPages = (config) => {
3139
+ const { auth, playground, server } = config.api;
3140
+ const resolved = {
3141
+ playground: {
3142
+ enabled: playground.enabled,
3143
+ proxy: playground.proxy === true ? playgroundProxyPattern(config) : playground.proxy
3144
+ }
3145
+ };
3146
+ if (auth) {
3147
+ resolved.auth = auth;
3148
+ }
3149
+ if (server) {
3150
+ resolved.server = server;
3151
+ }
3152
+ return resolved;
3153
+ };
3154
+ var resolveFooter = (config) => {
3155
+ const { footer } = config;
3156
+ return footer && (footer.links.length > 0 || Object.keys(footer.socials).length > 0) ? footer : null;
3157
+ };
3026
3158
  var resolveOgMark = (project, siteLogo) => {
3027
3159
  const configured = project.config.seo.og.logo;
3028
3160
  if (configured === false) {
@@ -3056,6 +3188,18 @@ var resolveGithubData = (github) => github ? {
3056
3188
  owner: github.owner,
3057
3189
  repo: github.repo
3058
3190
  } : null;
3191
+ var resolveAssistant = (config) => {
3192
+ const { assistant } = config.ai;
3193
+ if (!assistant?.enabled) {
3194
+ return null;
3195
+ }
3196
+ return {
3197
+ captcha: assistant.captcha ? captchaSettings(assistant.captcha) : null,
3198
+ endpoint: assistant.endpoint ?? null,
3199
+ suggestions: assistant.suggestions,
3200
+ support: assistant.support ?? null
3201
+ };
3202
+ };
3059
3203
  var buildRuntimeData = (project) => {
3060
3204
  const { config, context, graph, manifest } = project;
3061
3205
  const { github } = config;
@@ -3069,14 +3213,14 @@ var buildRuntimeData = (project) => {
3069
3213
  }
3070
3214
  const rel = relative5(context.root, sourcePath).split("\\").join("/");
3071
3215
  const editDir = trimChar(github?.dir ?? "", "/");
3072
- const editPath = normalize2(editDir ? join11(editDir, rel) : rel);
3216
+ const editPath = normalize2(editDir ? join12(editDir, rel) : rel);
3073
3217
  if (editPath.startsWith("..") || isAbsolute6(editPath)) {
3074
3218
  return null;
3075
3219
  }
3076
3220
  return `${editBase}/${editPath}`;
3077
3221
  };
3078
3222
  const { i18n } = config;
3079
- const markUrl = headerRepoUrl(config.navigation.repo, repoUrl2);
3223
+ const markUrl = footerRepoUrl(config.navigation.repo, repoUrl2);
3080
3224
  const withRepoUrl = (nav) => ({
3081
3225
  ...nav,
3082
3226
  repoUrl: markUrl
@@ -3106,15 +3250,14 @@ var buildRuntimeData = (project) => {
3106
3250
  const data = {
3107
3251
  config: {
3108
3252
  analytics: config.analytics,
3253
+ api: resolveApiPages(config),
3109
3254
  appleIcon: resolveAppleIcon(project),
3110
- assistant: config.ai.assistant?.enabled ? {
3111
- endpoint: config.ai.assistant.endpoint ?? null,
3112
- suggestions: config.ai.assistant.suggestions
3113
- } : null,
3255
+ assistant: resolveAssistant(config),
3114
3256
  banner: resolveBanner(config),
3115
3257
  basePath: config.basePath,
3116
3258
  codeThemes: config.markdown.code.theme,
3117
3259
  codeWrap: config.markdown.code.wrap,
3260
+ consent: config.consent,
3118
3261
  dateFormat: config.dateFormat,
3119
3262
  description: config.description,
3120
3263
  discovery: {
@@ -3125,7 +3268,9 @@ var buildRuntimeData = (project) => {
3125
3268
  sitemap: config.seo.sitemap && Boolean(config.deployment.options.site)
3126
3269
  },
3127
3270
  favicon: resolveFavicon(project),
3128
- feedback: config.feedback,
3271
+ feedback: config.feedback.enabled,
3272
+ feedbackComments: config.feedback.comments,
3273
+ footer: resolveFooter(config),
3129
3274
  github: resolveGithubData(github),
3130
3275
  i18n: i18n ? {
3131
3276
  defaultLocale: i18n.defaultLocale,
@@ -3135,7 +3280,8 @@ var buildRuntimeData = (project) => {
3135
3280
  code,
3136
3281
  dir,
3137
3282
  label
3138
- }))
3283
+ })),
3284
+ routeByBrowserLanguage: i18n.routeByBrowserLanguage
3139
3285
  } : null,
3140
3286
  identity: config.seo.organization || config.seo.software ? {
3141
3287
  organization: config.seo.organization,
@@ -3147,6 +3293,8 @@ var buildRuntimeData = (project) => {
3147
3293
  name: config.agents.mcp.name ?? config.title,
3148
3294
  route: config.agents.mcp.route
3149
3295
  } : null,
3296
+ metatags: config.seo.metatags ?? null,
3297
+ narration: config.narration.enabled ? { generated: config.narration.provider !== null } : null,
3150
3298
  og: {
3151
3299
  description: resolveOgDescription(config),
3152
3300
  enabled: config.seo.og.enabled ?? false,
@@ -3215,7 +3363,7 @@ var buildRuntimeData = (project) => {
3215
3363
  var planMcp = (project, srcDir, userPages) => {
3216
3364
  const { config } = project;
3217
3365
  const { route } = config.agents.mcp;
3218
- const dir = join11(srcDir, "blume-mcp");
3366
+ const dir = join12(srcDir, "blume-mcp");
3219
3367
  const base = {
3220
3368
  dir,
3221
3369
  discoveryPages: [],
@@ -3239,11 +3387,11 @@ var planMcp = (project, srcDir, userPages) => {
3239
3387
  ...base,
3240
3388
  discoveryPages: [
3241
3389
  {
3242
- entrypoint: join11(dir, "discovery.ts"),
3390
+ entrypoint: join12(dir, "discovery.ts"),
3243
3391
  pattern: "/.well-known/mcp.json"
3244
3392
  },
3245
3393
  {
3246
- entrypoint: join11(dir, "server-card.ts"),
3394
+ entrypoint: join12(dir, "server-card.ts"),
3247
3395
  pattern: "/.well-known/mcp/server-card.json"
3248
3396
  }
3249
3397
  ],
@@ -3270,9 +3418,9 @@ var writeMcpFiles = async (plan, write, data) => {
3270
3418
  version: data.version
3271
3419
  };
3272
3420
  await Promise.all([
3273
- write(join11(plan.srcDir, "pages", mcpPageFile(plan.route)), mcpEndpointTemplate()),
3274
- write(join11(plan.dir, "discovery.ts"), staticJsonEndpointTemplate(buildMcpDiscovery(discoveryInput))),
3275
- write(join11(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
3421
+ write(join12(plan.srcDir, "pages", mcpPageFile(plan.route)), mcpEndpointTemplate()),
3422
+ write(join12(plan.dir, "discovery.ts"), staticJsonEndpointTemplate(buildMcpDiscovery(discoveryInput))),
3423
+ write(join12(plan.dir, "server-card.ts"), staticJsonEndpointTemplate(buildMcpServerCard(discoveryInput)))
3276
3424
  ]);
3277
3425
  };
3278
3426
  var ownsApiRest = (page) => page.pattern.startsWith("/api/[");
@@ -3284,7 +3432,7 @@ var planApi = (project, srcDir, userPages) => {
3284
3432
  catchAll: server && !userPages.some(ownsApiRest) && !project.graph.pages.some(contentUnderApi),
3285
3433
  enabled: config.agents.api,
3286
3434
  server,
3287
- spec: !routeIsTaken(userPages, project.graph.pages, OPENAPI_PATH) && !existsSync6(join11(context.root, "public", "openapi.json")),
3435
+ spec: !routeIsTaken(userPages, project.graph.pages, OPENAPI_PATH) && !existsSync6(join12(context.root, "public", "openapi.json")),
3288
3436
  srcDir
3289
3437
  };
3290
3438
  };
@@ -3294,20 +3442,20 @@ var writeApiFiles = async (project, plan, write, data, mcp) => {
3294
3442
  }
3295
3443
  const { config } = project;
3296
3444
  const mcpRoute = mcp.enabled ? mcp.route : null;
3297
- const apiDir = join11(plan.srcDir, "pages", "api");
3445
+ const apiDir = join12(plan.srcDir, "pages", "api");
3298
3446
  const writes = [
3299
- write(join11(apiDir, "docs", "pages.json.ts"), apiPagesIndexTemplate()),
3300
- write(join11(apiDir, "docs", "pages", "[...route].json.ts"), apiPageTemplate()),
3301
- write(join11(apiDir, "docs", "navigation.json.ts"), apiNavigationTemplate())
3447
+ write(join12(apiDir, "docs", "pages.json.ts"), apiPagesIndexTemplate()),
3448
+ write(join12(apiDir, "docs", "pages", "[...route].json.ts"), apiPageTemplate()),
3449
+ write(join12(apiDir, "docs", "navigation.json.ts"), apiNavigationTemplate())
3302
3450
  ];
3303
3451
  if (plan.server) {
3304
- writes.push(write(join11(apiDir, "docs", "search.ts"), apiSearchTemplate()));
3452
+ writes.push(write(join12(apiDir, "docs", "search.ts"), apiSearchTemplate()));
3305
3453
  }
3306
3454
  if (plan.catchAll) {
3307
- writes.push(write(join11(apiDir, "[...path].ts"), apiNotFoundTemplate({ base: data.base, site: data.site })));
3455
+ writes.push(write(join12(apiDir, "[...path].ts"), apiNotFoundTemplate({ base: data.base, site: data.site })));
3308
3456
  }
3309
3457
  if (plan.spec) {
3310
- writes.push(write(join11(plan.srcDir, "pages", "openapi.json.ts"), staticJsonEndpointTemplate(buildApiSpec({
3458
+ writes.push(write(join12(plan.srcDir, "pages", "openapi.json.ts"), staticJsonEndpointTemplate(buildApiSpec({
3311
3459
  agentReadability: config.agents.agentReadability,
3312
3460
  base: data.base,
3313
3461
  description: config.description,
@@ -3321,11 +3469,10 @@ var writeApiFiles = async (project, plan, write, data, mcp) => {
3321
3469
  }
3322
3470
  await Promise.all(writes);
3323
3471
  };
3324
- var PLAYGROUND_PROXY_ENTRY = join11("blume-openapi", "api-proxy.ts");
3325
- var playgroundProxyPattern = (config) => withBasePath(config.basePath, "/_api-proxy");
3472
+ var PLAYGROUND_PROXY_ENTRY = join12("blume-openapi", "api-proxy.ts");
3326
3473
  var planPlaygroundProxy = (config, srcDir) => ({
3327
3474
  enabled: needsPlaygroundProxy(config),
3328
- entrypoint: join11(srcDir, PLAYGROUND_PROXY_ENTRY),
3475
+ entrypoint: join12(srcDir, PLAYGROUND_PROXY_ENTRY),
3329
3476
  pattern: playgroundProxyPattern(config)
3330
3477
  });
3331
3478
  var specOriginsOf = (spec) => {
@@ -3357,6 +3504,27 @@ var specOriginsOf = (spec) => {
3357
3504
  return [...origins];
3358
3505
  };
3359
3506
  var specOrigins = (data) => [...new Set(Object.values(data).flatMap(specOriginsOf))].toSorted();
3507
+ var originOf = (url) => {
3508
+ try {
3509
+ return new URL(url).origin;
3510
+ } catch {
3511
+ return null;
3512
+ }
3513
+ };
3514
+ var apiPageOrigins = (project) => {
3515
+ const { config } = project;
3516
+ if (!apiPagesUseBuiltinProxy(config)) {
3517
+ return [];
3518
+ }
3519
+ const targets = project.graph.pages.map((page) => parseApiEndpoint(page.meta.api ?? "")?.target ?? "");
3520
+ return [config.api.server ?? "", ...targets].flatMap((target) => {
3521
+ const origin = originOf(target);
3522
+ return origin ? [origin] : [];
3523
+ });
3524
+ };
3525
+ var apiPageProxyWarnings = (project) => apiPagesUseBuiltinProxy(project.config) && apiPageOrigins(project).length === 0 ? [
3526
+ "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."
3527
+ ] : [];
3360
3528
  var proxyAllowlistWarnings = (config, data) => {
3361
3529
  const proxied = new Set(builtinProxyReferences(config).map((reference) => reference.slug));
3362
3530
  const warnings = [];
@@ -3377,10 +3545,13 @@ var writeAskFiles = async (project, srcDir, write, modules) => {
3377
3545
  if (backend.grounded) {
3378
3546
  modules.set("blume:ask-data", JSON.stringify(await buildAskData(project)));
3379
3547
  }
3380
- await write(join11(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(backend, {
3548
+ await write(join12(srcDir, "pages", "api", "ask.ts"), askEndpointTemplate(backend, {
3549
+ captcha: assistant.captcha,
3381
3550
  cors: assistant.cors,
3382
3551
  instructions: assistant.instructions,
3383
- retrieval: assistant.retrieval
3552
+ rateLimit: project.config.rateLimit,
3553
+ retrieval: assistant.retrieval,
3554
+ tools: assistant.tools ?? backend.toolsByDefault
3384
3555
  }));
3385
3556
  };
3386
3557
  var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
@@ -3388,9 +3559,9 @@ var writeNotFoundPage = async (write, srcDir, pages, contentPages) => {
3388
3559
  return;
3389
3560
  }
3390
3561
  await Promise.all([
3391
- write(join11(srcDir, "pages", "404.astro"), notFoundPageTemplate()),
3392
- write(join11(srcDir, "pages", "404.md.ts"), notFoundMarkdownTemplate()),
3393
- write(join11(srcDir, "pages", "404.json.ts"), notFoundJsonTemplate())
3562
+ write(join12(srcDir, "pages", "404.astro"), notFoundPageTemplate()),
3563
+ write(join12(srcDir, "pages", "404.md.ts"), notFoundMarkdownTemplate()),
3564
+ write(join12(srcDir, "pages", "404.json.ts"), notFoundJsonTemplate())
3394
3565
  ]);
3395
3566
  };
3396
3567
  var diagnosticWarning = (diagnostic) => diagnostic.suggestion ? `${diagnostic.message} ${diagnostic.suggestion}` : diagnostic.message;
@@ -3433,20 +3604,21 @@ var languageIconCssFrom = (project, rawMarkdown) => languageIconCss(languageIcon
3433
3604
  ].join(`
3434
3605
  `)));
3435
3606
  var languageIconCssFor = async (project) => languageIconCssFrom(project, await buildRawMarkdown(project));
3436
- var writeNavFragments = (write, srcDir, navFragments) => navFragments ? write(join11(srcDir, "pages", "blume-nav", "[version]", "[locale]", "[id].astro"), navFragmentTemplate()) : Promise.resolve(false);
3607
+ var writeNavFragments = (write, srcDir, navFragments) => navFragments ? write(join12(srcDir, "pages", "blume-nav", "[version]", "[locale]", "[id].astro"), navFragmentTemplate()) : Promise.resolve(false);
3437
3608
  var clientFeaturesFor = async (project) => clientFeaturesFrom(project, await buildRawMarkdown(project));
3438
3609
  var generateRuntime = async (project) => {
3439
3610
  const { context, config } = project;
3440
3611
  assertFontFilesExist(project);
3441
3612
  const out = context.outDir;
3442
- const srcDir = join11(out, "src");
3443
- const generatedDir = join11(srcDir, "generated");
3444
- const askPath = join11(srcDir, "generated", "Ask.astro");
3445
- const themePath = join11(srcDir, "generated", "app.css");
3446
- const searchClientPath = join11(srcDir, "generated", "search-client.ts");
3447
- const featuresPath = join11(srcDir, "generated", "features.ts");
3448
- const examplesPath = join11(srcDir, "generated", "examples.ts");
3449
- const examplesThemePath = join11(srcDir, "generated", "examples.css");
3613
+ const srcDir = join12(out, "src");
3614
+ const generatedDir = join12(srcDir, "generated");
3615
+ const askPath = join12(srcDir, "generated", "Ask.astro");
3616
+ const themePath = join12(srcDir, "generated", "app.css");
3617
+ const searchClientPath = join12(srcDir, "generated", "search-client.ts");
3618
+ const consentClientPath = join12(srcDir, "generated", "consent-client.ts");
3619
+ const featuresPath = join12(srcDir, "generated", "features.ts");
3620
+ const examplesPath = join12(srcDir, "generated", "examples.ts");
3621
+ const examplesThemePath = join12(srcDir, "generated", "examples.css");
3450
3622
  const written = new Set;
3451
3623
  const write = (path, content) => {
3452
3624
  written.add(normalize2(path));
@@ -3513,16 +3685,19 @@ var generateRuntime = async (project) => {
3513
3685
  pattern: playgroundProxy.pattern
3514
3686
  });
3515
3687
  }
3516
- const proxyOrigins = specOrigins(openApiData);
3688
+ const proxyOrigins = [
3689
+ ...new Set([...specOrigins(openApiData), ...apiPageOrigins(project)])
3690
+ ].toSorted();
3517
3691
  const hasStaged = staged.size > 0;
3518
3692
  const hasFilesystemSource = project.sources.some((source) => !source.staged);
3519
3693
  const docsCollection = resolveDocsCollection(config, context.root);
3520
3694
  const [structural] = await Promise.all([
3521
3695
  Promise.all([
3522
- write(join11(out, "astro.config.mjs"), astroConfigTemplate({
3696
+ write(join12(out, "astro.config.mjs"), astroConfigTemplate({
3523
3697
  aliases: resolveTsconfigAliases(context.root),
3524
3698
  askPath,
3525
3699
  config,
3700
+ consentClientPath,
3526
3701
  contentRoot: docsCollection.base,
3527
3702
  contentRoutes,
3528
3703
  context,
@@ -3539,16 +3714,16 @@ var generateRuntime = async (project) => {
3539
3714
  searchClientPath,
3540
3715
  themePath
3541
3716
  })),
3542
- write(join11(out, "package.json"), runtimePackageTemplate(runtimeDependencies({ config, needsReact, needsSvelte, needsVue }))),
3543
- write(join11(out, "tsconfig.json"), runtimeTsconfigTemplate()),
3544
- write(join11(srcDir, "content.config.ts"), contentConfigTemplate({
3717
+ write(join12(out, "package.json"), runtimePackageTemplate(runtimeDependencies({ config, needsReact, needsSvelte, needsVue }))),
3718
+ write(join12(out, "tsconfig.json"), runtimeTsconfigTemplate()),
3719
+ write(join12(srcDir, "content.config.ts"), contentConfigTemplate({
3545
3720
  collection: docsCollection,
3546
3721
  config,
3547
3722
  context,
3548
3723
  filesystem: hasFilesystemSource,
3549
3724
  staged: hasStaged
3550
3725
  })),
3551
- write(join11(srcDir, "pages", "[...slug].astro"), catchAllPageTemplate({
3726
+ write(join12(srcDir, "pages", "[...slug].astro"), catchAllPageTemplate({
3552
3727
  exportEpub,
3553
3728
  exportPdf,
3554
3729
  mathEnabled: usesMath,
@@ -3557,8 +3732,8 @@ var generateRuntime = async (project) => {
3557
3732
  })),
3558
3733
  writeNavFragments(write, srcDir, navFragments),
3559
3734
  write(askPath, askComponentTemplate(assistantEnabled)),
3560
- write(join11(srcDir, "generated", "components.ts"), slotPlan.module),
3561
- write(join11(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples, config.basePath)),
3735
+ write(join12(srcDir, "generated", "components.ts"), slotPlan.module),
3736
+ write(join12(srcDir, "generated", "examples.ts"), exampleMapTemplate(exampleDiscovery.examples, config.basePath)),
3562
3737
  write(examplesThemePath, examplesEntryTemplate({
3563
3738
  configTokens: buildThemeCss(config.theme),
3564
3739
  sources: exampleScanRoots(context.root, exampleDiscovery.dir).map((dir) => `${dir}/${EXAMPLE_SCAN_GLOB}`),
@@ -3575,15 +3750,15 @@ var generateRuntime = async (project) => {
3575
3750
  userTheme
3576
3751
  }))
3577
3752
  ]),
3578
- Promise.all(slotPlan.wrappers.map((wrapper) => write(join11(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content))),
3579
- Promise.all(exampleDiscovery.examples.map((example) => write(join11(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example)))),
3753
+ Promise.all(slotPlan.wrappers.map((wrapper) => write(join12(srcDir, "generated", "component-slots", `${wrapper.name}.astro`), wrapper.content))),
3754
+ Promise.all(exampleDiscovery.examples.map((example) => write(join12(srcDir, "generated", "examples", `${exampleSlug(example.path)}.astro`), exampleWrapperTemplate(example)))),
3580
3755
  writeAskFiles(project, srcDir, write, modules),
3581
3756
  writeMcpFiles(mcp, write, agentData),
3582
3757
  writeApiFiles(project, api, write, agentData, mcp),
3583
3758
  playgroundProxy.enabled ? write(playgroundProxy.entrypoint, playgroundProxyTemplate(proxyOrigins)) : Promise.resolve(false)
3584
3759
  ]);
3585
3760
  if (config.seo.og.enabled) {
3586
- await write(join11(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes, {
3761
+ await write(join12(srcDir, "pages", "og", "[...slug].png.ts"), ogEndpointTemplate(ogRoutes, {
3587
3762
  ...projectOgFonts(project),
3588
3763
  cache: {
3589
3764
  dir: ogCacheDir(project.context),
@@ -3593,7 +3768,7 @@ var generateRuntime = async (project) => {
3593
3768
  }, changelogIndex));
3594
3769
  }
3595
3770
  if (changelogIndex) {
3596
- await write(join11(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
3771
+ await write(join12(srcDir, "pages", "changelog.astro"), changelogIndexTemplate({
3597
3772
  exportEpub,
3598
3773
  exportPdf,
3599
3774
  needsReact,
@@ -3610,36 +3785,38 @@ var generateRuntime = async (project) => {
3610
3785
  }),
3611
3786
  writeNotFoundPage(write, srcDir, pages, project.graph.pages),
3612
3787
  write(searchClientPath, searchClientTemplate(config)),
3788
+ write(consentClientPath, consentClientTemplate(config.consent)),
3613
3789
  write(featuresPath, featuresTemplate(clientFeatures))
3614
3790
  ]);
3615
3791
  const searchAdapter = config.search.provider;
3616
3792
  if (searchAdapter.mode === "static") {
3617
3793
  const documents = await buildSearchDocuments(project);
3618
3794
  modules.set("blume:search-index", JSON.stringify(documents));
3619
- await write(join11(srcDir, "pages", "blume-search.json.ts"), searchEndpointTemplate());
3795
+ await write(join12(srcDir, "pages", "blume-search.json.ts"), searchEndpointTemplate());
3620
3796
  }
3621
3797
  if (searchAdapter.kind === "mixedbread") {
3622
- await write(join11(srcDir, "pages", "api", "search.ts"), mixedbreadSearchEndpointTemplate(searchAdapter.options));
3798
+ await write(join12(srcDir, "pages", "api", "search.ts"), mixedbreadSearchEndpointTemplate(searchAdapter.options));
3623
3799
  }
3624
- await write(join11(srcDir, "generated", "includes.json"), `${JSON.stringify(buildIncludeGraph(project.graph.pages))}
3800
+ await write(join12(srcDir, "generated", "includes.json"), `${JSON.stringify(buildIncludeGraph(project.graph.pages))}
3625
3801
  `);
3626
3802
  modules.set("blume:raw-markdown", JSON.stringify(rawMarkdown));
3627
3803
  const contentAssets = await collectContentAssets(project);
3628
3804
  modules.set("blume:content-assets", JSON.stringify(contentAssets));
3629
3805
  await Promise.all([
3630
- write(join11(srcDir, "pages", "[...slug].md.ts"), rawMarkdownEndpointTemplate("md")),
3631
- write(join11(srcDir, "pages", "[...slug].mdx.ts"), rawMarkdownEndpointTemplate("mdx")),
3632
- write(join11(srcDir, "pages", "blume-assets", "[...asset].ts"), contentAssetsEndpointTemplate(join11(project.context.outDir, "public", "blume-assets")))
3806
+ write(join12(srcDir, "pages", "[...slug].md.ts"), rawMarkdownEndpointTemplate("md")),
3807
+ write(join12(srcDir, "pages", "[...slug].mdx.ts"), rawMarkdownEndpointTemplate("mdx")),
3808
+ write(join12(srcDir, "pages", "blume-assets", "[...asset].ts"), contentAssetsEndpointTemplate(join12(project.context.outDir, "public", "blume-assets")))
3633
3809
  ]);
3634
3810
  const feeds = buildRssFeeds(project);
3635
3811
  if (feeds.length > 0) {
3636
3812
  const feedXml = Object.fromEntries(feeds.map((feed) => [feed.type, renderRssFeed(feed)]));
3637
3813
  modules.set("blume:rss", JSON.stringify(feedXml));
3638
- await write(join11(srcDir, "pages", "[section]", "rss.xml.ts"), rssEndpointTemplate());
3814
+ await write(join12(srcDir, "pages", "[section]", "rss.xml.ts"), rssEndpointTemplate());
3639
3815
  }
3640
3816
  const warnings = [
3641
3817
  ...depsLinkWarning ? [depsLinkWarning] : [],
3642
3818
  ...proxyAllowlistWarnings(config, openApiData),
3819
+ ...apiPageProxyWarnings(project),
3643
3820
  ...reactCompilerWarnings(config, needsReact, reactCompilerPath),
3644
3821
  ...mcp.warnings,
3645
3822
  ...islandDiscovery.warnings,
@@ -3671,12 +3848,12 @@ var generateRuntime = async (project) => {
3671
3848
  root: context.root
3672
3849
  });
3673
3850
  warnings.push(...references.warnings);
3674
- await Promise.all(references.files.map((file) => write(join11(srcDir, "pages", file.pagePath), file.content)));
3851
+ await Promise.all(references.files.map((file) => write(join12(srcDir, "pages", file.pagePath), file.content)));
3675
3852
  }
3676
3853
  modules.set("blume:data", buildRuntimeData(project));
3677
3854
  modules.set("blume:openapi", JSON.stringify(openApiData));
3678
3855
  await Promise.all([
3679
- write(join11(out, "blume.manifest.json"), `${JSON.stringify(project.manifest, null, 2)}
3856
+ write(join12(out, "blume.manifest.json"), `${JSON.stringify(project.manifest, null, 2)}
3680
3857
  `),
3681
3858
  writeStagedContent(out, staged)
3682
3859
  ]);
@@ -3686,7 +3863,7 @@ var generateRuntime = async (project) => {
3686
3863
  return { structuralChange: structural.some(Boolean), warnings };
3687
3864
  };
3688
3865
 
3689
- export { publishBuildProject, refreshBlumeContent, showBlumeErrorOverlay, ogCacheDir, pruneCardCache, cardCacheTally, buildApiSpec, buildAskData, resolveOgFonts, buildThemeCss, buildReferenceFiles, tailwindEntryTemplate, examplesEntryTemplate, rebaseSourceDirectives, twoslashCss, EXAMPLE_SCAN_GLOB, exampleScanRoots, discoverExamples, exampleMarkdownLookup, packageDirFrom, detectNeedsReact, detectUsesMath, collectStaged, buildRuntimeData, PLAYGROUND_PROXY_ENTRY, playgroundProxyPattern, specOrigins, proxyAllowlistWarnings, analyzeComponentsFile, languageIconCssFor, clientFeaturesFor, generateRuntime };
3866
+ export { publishBuildProject, refreshBlumeContent, showBlumeErrorOverlay, ogCacheDir, pruneCardCache, cardCacheTally, buildApiSpec, buildAskData, resolveOgFonts, buildReferenceFiles, tailwindEntryTemplate, examplesEntryTemplate, rebaseSourceDirectives, twoslashCss, EXAMPLE_SCAN_GLOB, exampleScanRoots, discoverExamples, exampleMarkdownLookup, packageDirFrom, detectNeedsReact, detectUsesMath, collectStaged, playgroundProxyPattern, buildRuntimeData, PLAYGROUND_PROXY_ENTRY, specOrigins, proxyAllowlistWarnings, analyzeComponentsFile, languageIconCssFor, clientFeaturesFor, generateRuntime };
3690
3867
 
3691
- //# debugId=067C177A5C0052FA64756E2164756E21
3692
- //# sourceMappingURL=chunk-c8chx29p.js.map
3868
+ //# debugId=168B822A64F4126564756E2164756E21
3869
+ //# sourceMappingURL=chunk-zf748avv.js.map