blume 2.0.3 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (607) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +142 -0
  3. package/README.md +1 -1
  4. package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
  5. package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
  6. package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
  7. package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
  8. package/dist/cli/chunk-150jk7km.js +52 -0
  9. package/dist/cli/chunk-150jk7km.js.map +10 -0
  10. package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
  11. package/dist/cli/chunk-313vnn40.js.map +10 -0
  12. package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
  13. package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
  14. package/dist/cli/chunk-3x6x3pph.js.map +10 -0
  15. package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
  16. package/dist/cli/chunk-42t4jxdx.js.map +12 -0
  17. package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
  18. package/dist/cli/chunk-54ztw1nj.js.map +10 -0
  19. package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
  20. package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
  21. package/dist/cli/chunk-66w9j7p6.js +322 -0
  22. package/dist/cli/chunk-66w9j7p6.js.map +14 -0
  23. package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
  24. package/dist/cli/chunk-7ppf1rva.js.map +10 -0
  25. package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
  26. package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
  27. package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
  28. package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
  29. package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
  30. package/dist/cli/chunk-cfyg47zg.js.map +10 -0
  31. package/dist/cli/chunk-cm89scdv.js +443 -0
  32. package/dist/cli/chunk-cm89scdv.js.map +11 -0
  33. package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
  34. package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
  35. package/dist/cli/chunk-e6atmn4h.js.map +36 -0
  36. package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
  37. package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
  38. package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
  39. package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
  40. package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
  41. package/dist/cli/chunk-ehweg4fr.js.map +218 -0
  42. package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
  43. package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
  44. package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
  45. package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
  46. package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
  47. package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
  48. package/dist/cli/chunk-gb420vvz.js.map +17 -0
  49. package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
  50. package/dist/cli/chunk-hebn0tpx.js.map +14 -0
  51. package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
  52. package/dist/cli/chunk-htrwgabr.js.map +15 -0
  53. package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
  54. package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
  55. package/dist/cli/chunk-j134vrp2.js +65 -0
  56. package/dist/cli/chunk-j134vrp2.js.map +10 -0
  57. package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
  58. package/dist/cli/chunk-kwrg63tm.js +31 -0
  59. package/dist/cli/chunk-kwrg63tm.js.map +10 -0
  60. package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
  61. package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
  62. package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
  63. package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
  64. package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
  65. package/dist/cli/chunk-ncj7w596.js.map +35 -0
  66. package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
  67. package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
  68. package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
  69. package/dist/cli/chunk-nrns10mj.js.map +10 -0
  70. package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
  71. package/dist/cli/chunk-t2m5j4pr.js +104 -0
  72. package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
  73. package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
  74. package/dist/cli/chunk-tphac74f.js +126 -0
  75. package/dist/cli/chunk-tphac74f.js.map +11 -0
  76. package/dist/cli/chunk-w1r4vase.js +18 -0
  77. package/dist/cli/chunk-w1r4vase.js.map +10 -0
  78. package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
  79. package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
  80. package/dist/cli/index.js +31 -20
  81. package/dist/cli/index.js.map +5 -5
  82. package/dist/types/ai/agent-surface.d.ts +8 -7
  83. package/dist/types/ai/ai-catalog.d.ts +7 -0
  84. package/dist/types/ai/ask-context.d.ts +26 -0
  85. package/dist/types/ai/ask.d.ts +271 -58
  86. package/dist/types/ai/component-markdown.d.ts +2 -0
  87. package/dist/types/ai/index.d.ts +2 -2
  88. package/dist/types/ai/openapi-components.d.ts +4 -1
  89. package/dist/types/ai/site-skill.d.ts +26 -0
  90. package/dist/types/ai/skills.d.ts +16 -0
  91. package/dist/types/astro/integration.d.ts +9 -0
  92. package/dist/types/astro/markdown-negotiation.d.ts +3 -0
  93. package/dist/types/astro/pages.d.ts +10 -0
  94. package/dist/types/captcha/hcaptcha.d.ts +27 -0
  95. package/dist/types/captcha/index.d.ts +28 -0
  96. package/dist/types/captcha/schema.d.ts +29 -0
  97. package/dist/types/captcha/turnstile.d.ts +28 -0
  98. package/dist/types/cli/init/scaffold.d.ts +1 -1
  99. package/dist/types/components/content/api-field.d.ts +62 -0
  100. package/dist/types/components/content/api-page.d.ts +100 -0
  101. package/dist/types/components/layout/nav-utils.d.ts +26 -0
  102. package/dist/types/components/openapi/code-samples.d.ts +29 -0
  103. package/dist/types/components/openapi/helpers.d.ts +158 -0
  104. package/dist/types/components/openapi/security.d.ts +95 -0
  105. package/dist/types/components/openapi/snippets.d.ts +60 -0
  106. package/dist/types/consent/ethyca.d.ts +48 -0
  107. package/dist/types/consent/index.d.ts +37 -0
  108. package/dist/types/consent/native.d.ts +28 -0
  109. package/dist/types/consent/osano.d.ts +42 -0
  110. package/dist/types/consent/schema.d.ts +110 -0
  111. package/dist/types/core/changelog-index.d.ts +8 -0
  112. package/dist/types/core/config-input.d.ts +217 -23
  113. package/dist/types/core/data.d.ts +53 -4
  114. package/dist/types/core/footer.d.ts +8 -0
  115. package/dist/types/core/i18n-ui.d.ts +88 -0
  116. package/dist/types/core/includes.d.ts +8 -2
  117. package/dist/types/core/links.d.ts +8 -0
  118. package/dist/types/core/localizable.d.ts +7 -0
  119. package/dist/types/core/page-modes.d.ts +29 -0
  120. package/dist/types/core/probe.d.ts +2 -0
  121. package/dist/types/core/project-graph.d.ts +6 -0
  122. package/dist/types/core/redirect-patterns.d.ts +152 -0
  123. package/dist/types/core/related.d.ts +40 -0
  124. package/dist/types/core/schema.d.ts +670 -56
  125. package/dist/types/core/sources/cache.d.ts +3 -0
  126. package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
  127. package/dist/types/core/sources/contentful.d.ts +17 -1
  128. package/dist/types/core/sources/lexical.d.ts +5 -0
  129. package/dist/types/core/sources/normalize.d.ts +20 -1
  130. package/dist/types/core/sources/read.d.ts +5 -0
  131. package/dist/types/core/sources/remote.d.ts +37 -10
  132. package/dist/types/core/sources/sanity.d.ts +1 -1
  133. package/dist/types/core/types.d.ts +18 -1
  134. package/dist/types/core/variables.d.ts +42 -0
  135. package/dist/types/deploy/adapter-output.d.ts +2 -1
  136. package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
  137. package/dist/types/deploy/adapters/node.d.ts +58 -23
  138. package/dist/types/deploy/adapters/registry.d.ts +10 -0
  139. package/dist/types/deploy/adapters/types.d.ts +3 -2
  140. package/dist/types/deploy/node-headers.d.ts +13 -2
  141. package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
  142. package/dist/types/deploy/platforms/netlify.d.ts +7 -0
  143. package/dist/types/deploy/platforms/node.d.ts +3 -1
  144. package/dist/types/deploy/platforms/types.d.ts +18 -7
  145. package/dist/types/deploy/platforms/vercel.d.ts +26 -1
  146. package/dist/types/deploy/redirects.d.ts +55 -11
  147. package/dist/types/deploy/sitemap.d.ts +2 -1
  148. package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
  149. package/dist/types/markdown/code-title.d.ts +17 -0
  150. package/dist/types/markdown/features.d.ts +3 -2
  151. package/dist/types/narration/build.d.ts +70 -0
  152. package/dist/types/narration/provider.d.ts +26 -0
  153. package/dist/types/narration/script.d.ts +154 -0
  154. package/dist/types/openapi/checks.d.ts +27 -0
  155. package/dist/types/openapi/graphql.d.ts +6 -0
  156. package/dist/types/openapi/model.d.ts +27 -10
  157. package/dist/types/openapi/overlay.d.ts +54 -0
  158. package/dist/types/openapi/parse.d.ts +16 -0
  159. package/dist/types/openapi/references.d.ts +30 -4
  160. package/dist/types/ratelimit/cloudflare.d.ts +39 -0
  161. package/dist/types/ratelimit/index.d.ts +27 -0
  162. package/dist/types/ratelimit/memory.d.ts +36 -0
  163. package/dist/types/ratelimit/schema.d.ts +119 -0
  164. package/dist/types/ratelimit/upstash.d.ts +46 -0
  165. package/dist/types/ratelimit/wrangler.d.ts +23 -0
  166. package/dist/types/reference/asyncapi.d.ts +10 -10
  167. package/dist/types/reference/graphql.d.ts +89 -11
  168. package/dist/types/reference/index.d.ts +1 -1
  169. package/dist/types/reference/openapi.d.ts +33 -12
  170. package/dist/types/reference/options.d.ts +82 -6
  171. package/dist/types/reference/scalar.d.ts +13 -0
  172. package/dist/types/reference/schema.d.ts +144 -36
  173. package/dist/types/search/adapters/registry.d.ts +3 -0
  174. package/dist/types/search/adapters/typesense.d.ts +14 -4
  175. package/dist/types/search/build.d.ts +3 -1
  176. package/dist/types/search/documents.d.ts +12 -1
  177. package/dist/types/search/orama-index.d.ts +13 -9
  178. package/dist/types/search/sync/algolia.d.ts +5 -2
  179. package/dist/types/search/sync/index.d.ts +3 -1
  180. package/dist/types/search/sync/typesense.d.ts +11 -7
  181. package/dist/types/seo/metatags.d.ts +20 -0
  182. package/dist/types/sources/contentful.d.ts +16 -0
  183. package/dist/types/sources/github-releases.d.ts +8 -1
  184. package/dist/types/sources/payload.d.ts +2 -0
  185. package/dist/types/sources/registry.d.ts +54 -0
  186. package/dist/types/sources/shared.d.ts +3 -0
  187. package/dist/types/sources/strapi.d.ts +2 -0
  188. package/docs/01-quickstart.mdx +4 -2
  189. package/docs/02-deployment.mdx +71 -17
  190. package/docs/03-upgrading.mdx +4 -4
  191. package/docs/04-migrating.mdx +1 -1
  192. package/docs/advanced/changelog.mdx +13 -2
  193. package/docs/advanced/skills.mdx +15 -1
  194. package/docs/cli/audit.mdx +51 -8
  195. package/docs/cli/doctor.mdx +5 -1
  196. package/docs/cli/evals.mdx +4 -4
  197. package/docs/cli/index.mdx +1 -0
  198. package/docs/cli/translate.mdx +1 -0
  199. package/docs/cli/validate.mdx +4 -3
  200. package/docs/configuration/analytics.mdx +3 -1
  201. package/docs/configuration/assistant.mdx +194 -38
  202. package/docs/configuration/consent.mdx +100 -0
  203. package/docs/configuration/customization.mdx +8 -6
  204. package/docs/configuration/export.mdx +5 -3
  205. package/docs/configuration/index.mdx +64 -5
  206. package/docs/configuration/meta.ts +3 -0
  207. package/docs/configuration/narration.mdx +119 -0
  208. package/docs/configuration/rate-limiting.mdx +90 -0
  209. package/docs/configuration/search.mdx +63 -12
  210. package/docs/configuration/theming.mdx +3 -1
  211. package/docs/content/components.mdx +108 -2
  212. package/docs/content/frontmatter.mdx +80 -2
  213. package/docs/content/i18n.mdx +39 -4
  214. package/docs/content/includes.mdx +16 -0
  215. package/docs/content/meta.mdx +1 -0
  216. package/docs/content/meta.ts +1 -0
  217. package/docs/content/navigation.mdx +32 -10
  218. package/docs/content/sources/contentful.mdx +35 -0
  219. package/docs/content/sources/custom.mdx +43 -0
  220. package/docs/content/sources/github-releases.mdx +39 -0
  221. package/docs/content/sources/index.mdx +91 -0
  222. package/docs/content/sources/meta.ts +16 -0
  223. package/docs/content/sources/notion.mdx +32 -0
  224. package/docs/content/sources/obsidian.mdx +37 -0
  225. package/docs/content/sources/payload.mdx +31 -0
  226. package/docs/content/sources/remote-mdx.mdx +44 -0
  227. package/docs/content/sources/sanity.mdx +29 -0
  228. package/docs/content/sources/strapi.mdx +32 -0
  229. package/docs/content/syntax.mdx +69 -4
  230. package/docs/content/variables.mdx +41 -0
  231. package/docs/discoverability/agent-discovery.mdx +29 -2
  232. package/docs/discoverability/index.mdx +2 -2
  233. package/docs/discoverability/json-api.mdx +2 -0
  234. package/docs/discoverability/llms-txt.mdx +2 -2
  235. package/docs/discoverability/markdown.mdx +3 -1
  236. package/docs/discoverability/mcp.mdx +4 -0
  237. package/docs/discoverability/metadata.mdx +17 -0
  238. package/docs/discoverability/sitemap-and-robots.mdx +1 -1
  239. package/docs/references/api-pages.mdx +74 -0
  240. package/docs/references/asyncapi.mdx +4 -2
  241. package/docs/references/graphql.mdx +14 -2
  242. package/docs/references/meta.ts +1 -1
  243. package/docs/references/openapi.mdx +148 -7
  244. package/docs/references/scalar.mdx +3 -1
  245. package/package.json +43 -8
  246. package/skills/blume/SKILL.md +3 -0
  247. package/skills/blume-migrate/SKILL.md +6 -6
  248. package/skills/blume-migrate/references/docusaurus.md +7 -7
  249. package/skills/blume-migrate/references/fumadocs.md +17 -13
  250. package/skills/blume-migrate/references/mintlify.md +37 -19
  251. package/skills/blume-migrate/references/nextra.md +10 -7
  252. package/skills/blume-migrate/references/starlight.md +11 -8
  253. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
  254. package/skills/blume-write-skill/SKILL.md +82 -0
  255. package/src/ai/agent-readability.ts +2 -1
  256. package/src/ai/agent-surface.ts +9 -7
  257. package/src/ai/ai-catalog.ts +6 -3
  258. package/src/ai/ask-context.ts +103 -20
  259. package/src/ai/ask-data.ts +6 -0
  260. package/src/ai/ask-limits.ts +13 -0
  261. package/src/ai/ask-tools.ts +142 -0
  262. package/src/ai/ask.ts +354 -76
  263. package/src/ai/changelog-markdown.ts +11 -6
  264. package/src/ai/component-markdown.ts +76 -1
  265. package/src/ai/cors.ts +14 -3
  266. package/src/ai/index.ts +12 -0
  267. package/src/ai/llms.ts +6 -2
  268. package/src/ai/markdown.ts +2 -1
  269. package/src/ai/mcp/data.ts +6 -0
  270. package/src/ai/mcp/query.ts +14 -6
  271. package/src/ai/openapi-components.ts +36 -6
  272. package/src/ai/relative-links.ts +4 -38
  273. package/src/ai/site-skill.ts +274 -0
  274. package/src/ai/skills.ts +35 -2
  275. package/src/ai/write-skill.ts +97 -0
  276. package/src/astro/generate.ts +210 -66
  277. package/src/astro/index.ts +1 -0
  278. package/src/astro/integration.ts +42 -4
  279. package/src/astro/markdown-negotiation.ts +3 -0
  280. package/src/astro/module-types.ts +9 -1
  281. package/src/astro/pages.ts +23 -0
  282. package/src/astro/templates.ts +406 -108
  283. package/src/astro/variables.ts +31 -0
  284. package/src/audit/catalog.ts +38 -3
  285. package/src/audit/checks/contrast.ts +183 -0
  286. package/src/audit/checks/i18n.ts +2 -3
  287. package/src/audit/checks/indexability.ts +2 -3
  288. package/src/audit/checks/links.ts +19 -13
  289. package/src/audit/checks/network.ts +110 -6
  290. package/src/audit/checks/redirects.ts +6 -4
  291. package/src/audit/checks/robots.ts +58 -2
  292. package/src/audit/checks/sitemap.ts +2 -3
  293. package/src/audit/redirects.ts +46 -15
  294. package/src/audit/run.ts +5 -0
  295. package/src/audit/types.ts +4 -1
  296. package/src/audit/url.ts +14 -5
  297. package/src/blume-modules.d.ts +12 -1
  298. package/src/captcha/client.ts +152 -0
  299. package/src/captcha/hcaptcha.ts +36 -0
  300. package/src/captcha/index.ts +28 -0
  301. package/src/captcha/schema.ts +32 -0
  302. package/src/captcha/turnstile.ts +38 -0
  303. package/src/captcha/verify.ts +71 -0
  304. package/src/cli/args.ts +51 -0
  305. package/src/cli/build-failure.ts +23 -0
  306. package/src/cli/command-meta.ts +5 -0
  307. package/src/cli/commands/audit.ts +10 -1
  308. package/src/cli/commands/dev.ts +18 -2
  309. package/src/cli/commands/doctor.ts +67 -28
  310. package/src/cli/commands/eval.ts +36 -4
  311. package/src/cli/commands/init.ts +6 -4
  312. package/src/cli/commands/skill.ts +96 -0
  313. package/src/cli/commands/validate.ts +10 -1
  314. package/src/cli/index.ts +5 -0
  315. package/src/cli/init/scaffold.ts +3 -3
  316. package/src/cli/prepare.ts +6 -3
  317. package/src/cli/required-secrets.ts +72 -30
  318. package/src/components/BlumePage.astro +2 -0
  319. package/src/components/content/ApiEndpoint.astro +18 -0
  320. package/src/components/content/ApiField.astro +79 -0
  321. package/src/components/content/ApiPlayground.astro +66 -0
  322. package/src/components/content/ApiRail.astro +19 -0
  323. package/src/components/content/Color.astro +1 -0
  324. package/src/components/content/FileTree.astro +1 -0
  325. package/src/components/content/GithubInfo.astro +1 -0
  326. package/src/components/content/Panel.astro +1 -0
  327. package/src/components/content/ParamField.astro +25 -0
  328. package/src/components/content/RequestExample.astro +17 -0
  329. package/src/components/content/ResponseExample.astro +17 -0
  330. package/src/components/content/ResponseField.astro +32 -0
  331. package/src/components/content/Step.astro +1 -0
  332. package/src/components/content/Tile.astro +1 -0
  333. package/src/components/content/Tooltip.astro +1 -0
  334. package/src/components/content/Tree.astro +1 -0
  335. package/src/components/content/TypeTable.astro +4 -1
  336. package/src/components/content/View.astro +21 -0
  337. package/src/components/content/ViewSwitcher.astro +168 -0
  338. package/src/components/content/api-field.ts +103 -0
  339. package/src/components/content/api-page.ts +248 -0
  340. package/src/components/content/mermaid-element.ts +15 -1
  341. package/src/components/content/view-switcher.ts +71 -0
  342. package/src/components/index.ts +2 -0
  343. package/src/components/islands/Assistant.astro +10 -1
  344. package/src/components/islands/assistant.tsx +104 -14
  345. package/src/components/islands/code-question.ts +62 -0
  346. package/src/components/islands/hooks.ts +136 -21
  347. package/src/components/islands/support-link.ts +68 -0
  348. package/src/components/layout/Analytics.astro +11 -2
  349. package/src/components/layout/Banner.astro +14 -10
  350. package/src/components/layout/Breadcrumbs.astro +6 -2
  351. package/src/components/layout/ConsentBanner.astro +62 -0
  352. package/src/components/layout/ConsentHead.astro +38 -0
  353. package/src/components/layout/Directory.astro +94 -0
  354. package/src/components/layout/DrawerSwitchers.astro +51 -0
  355. package/src/components/layout/Empty.astro +2 -2
  356. package/src/components/layout/Header.astro +122 -80
  357. package/src/components/layout/LanguageSwitcher.astro +48 -15
  358. package/src/components/layout/NarrationPlayer.astro +1085 -0
  359. package/src/components/layout/NavSelector.astro +33 -7
  360. package/src/components/layout/PageActions.astro +139 -24
  361. package/src/components/layout/PageFeedback.astro +54 -49
  362. package/src/components/layout/PageLayout.astro +71 -3
  363. package/src/components/layout/ReferenceLayout.astro +17 -6
  364. package/src/components/layout/RelatedPages.astro +42 -0
  365. package/src/components/layout/RootLayout.astro +318 -47
  366. package/src/components/layout/Search.astro +47 -19
  367. package/src/components/layout/SiteFooter.astro +124 -0
  368. package/src/components/layout/SiteMetatags.astro +16 -0
  369. package/src/components/layout/TableOfContents.astro +24 -17
  370. package/src/components/layout/consent/native.ts +79 -0
  371. package/src/components/layout/consent/types.ts +37 -0
  372. package/src/components/layout/footer-links.ts +53 -0
  373. package/src/components/layout/footer-socials.ts +87 -0
  374. package/src/components/layout/head-scripts.ts +6 -1
  375. package/src/components/layout/locale-redirect.ts +107 -0
  376. package/src/components/layout/nav-utils.ts +83 -0
  377. package/src/components/layout/page-feedback.ts +96 -0
  378. package/src/components/layout/search/algolia.ts +10 -1
  379. package/src/components/layout/search/analytics.ts +126 -0
  380. package/src/components/layout/search/endpoint.ts +48 -5
  381. package/src/components/layout/search/flexsearch.ts +17 -5
  382. package/src/components/layout/search/orama-cloud.ts +26 -14
  383. package/src/components/layout/search/pagefind.ts +114 -5
  384. package/src/components/layout/search/types.ts +32 -0
  385. package/src/components/layout/search/typesense.ts +19 -3
  386. package/src/components/openapi/AsyncApiOperation.astro +14 -7
  387. package/src/components/openapi/Authorization.astro +10 -0
  388. package/src/components/openapi/GraphqlOperation.astro +5 -0
  389. package/src/components/openapi/Operation.astro +184 -13
  390. package/src/components/openapi/ParametersTable.astro +8 -4
  391. package/src/components/openapi/Playground.astro +7 -1
  392. package/src/components/openapi/RequestBody.astro +24 -5
  393. package/src/components/openapi/RequestPanel.astro +59 -7
  394. package/src/components/openapi/Responses.astro +7 -4
  395. package/src/components/openapi/SchemaTable.astro +15 -3
  396. package/src/components/openapi/async-snippets.ts +65 -9
  397. package/src/components/openapi/async.ts +123 -29
  398. package/src/components/openapi/code-samples.ts +97 -0
  399. package/src/components/openapi/graphql-helpers.ts +35 -12
  400. package/src/components/openapi/helpers.ts +36 -2
  401. package/src/components/openapi/message-model.ts +54 -11
  402. package/src/components/openapi/message.ts +14 -4
  403. package/src/components/openapi/operation-model.ts +16 -7
  404. package/src/components/openapi/playground-client.ts +24 -5
  405. package/src/components/openapi/playground-schema.ts +1 -1
  406. package/src/components/openapi/schema-tree.ts +44 -14
  407. package/src/components/openapi/security.ts +16 -3
  408. package/src/components/openapi/snippets.ts +873 -10
  409. package/src/components/openapi/validate-json.ts +4 -3
  410. package/src/components/props.ts +6 -0
  411. package/src/consent/client.ts +95 -0
  412. package/src/consent/clients.ts +19 -0
  413. package/src/consent/ethyca.ts +71 -0
  414. package/src/consent/head.ts +24 -0
  415. package/src/consent/index.ts +37 -0
  416. package/src/consent/init.ts +29 -0
  417. package/src/consent/native.ts +36 -0
  418. package/src/consent/osano.ts +59 -0
  419. package/src/consent/schema.ts +30 -0
  420. package/src/core/builtin-tags.ts +5 -0
  421. package/src/core/changelog-index.ts +31 -1
  422. package/src/core/client-address.ts +19 -0
  423. package/src/core/component-diagnostics.ts +53 -0
  424. package/src/core/component-overrides.ts +32 -0
  425. package/src/core/config-input.ts +225 -23
  426. package/src/core/data.ts +46 -4
  427. package/src/core/diagnostics.ts +8 -2
  428. package/src/core/footer.ts +26 -0
  429. package/src/core/graph.ts +39 -36
  430. package/src/core/i18n-ui.ts +84 -2
  431. package/src/core/includes.ts +21 -4
  432. package/src/core/links.ts +63 -19
  433. package/src/core/localizable.ts +26 -0
  434. package/src/core/navigation.ts +43 -12
  435. package/src/core/page-modes.ts +56 -0
  436. package/src/core/probe.ts +26 -6
  437. package/src/core/project-graph.ts +163 -16
  438. package/src/core/redirect-patterns.ts +520 -0
  439. package/src/core/related.ts +131 -0
  440. package/src/core/schema.ts +339 -66
  441. package/src/core/sources/cache.ts +6 -0
  442. package/src/core/sources/contentful-rich-text.ts +29 -6
  443. package/src/core/sources/contentful.ts +135 -25
  444. package/src/core/sources/filesystem.ts +26 -4
  445. package/src/core/sources/github-releases.ts +12 -1
  446. package/src/core/sources/lexical.ts +15 -10
  447. package/src/core/sources/mdx-remote.ts +62 -10
  448. package/src/core/sources/normalize.ts +228 -41
  449. package/src/core/sources/notion.ts +7 -1
  450. package/src/core/sources/obsidian.ts +16 -3
  451. package/src/core/sources/payload.ts +38 -15
  452. package/src/core/sources/read.ts +8 -3
  453. package/src/core/sources/remote.ts +72 -15
  454. package/src/core/sources/resolve.ts +11 -1
  455. package/src/core/sources/sanity.ts +43 -25
  456. package/src/core/sources/strapi.ts +2 -2
  457. package/src/core/types.ts +19 -1
  458. package/src/core/ui-packs/ar.ts +44 -0
  459. package/src/core/ui-packs/bg.ts +46 -0
  460. package/src/core/ui-packs/bn.ts +44 -0
  461. package/src/core/ui-packs/ca.ts +47 -0
  462. package/src/core/ui-packs/cs.ts +45 -0
  463. package/src/core/ui-packs/da.ts +46 -0
  464. package/src/core/ui-packs/de.ts +47 -0
  465. package/src/core/ui-packs/el.ts +46 -0
  466. package/src/core/ui-packs/es.ts +47 -0
  467. package/src/core/ui-packs/fa.ts +46 -0
  468. package/src/core/ui-packs/fi.ts +46 -0
  469. package/src/core/ui-packs/fr.ts +47 -0
  470. package/src/core/ui-packs/he.ts +44 -0
  471. package/src/core/ui-packs/hi.ts +45 -0
  472. package/src/core/ui-packs/hr.ts +46 -0
  473. package/src/core/ui-packs/hu.ts +45 -0
  474. package/src/core/ui-packs/id.ts +46 -0
  475. package/src/core/ui-packs/it.ts +46 -0
  476. package/src/core/ui-packs/ja.ts +46 -0
  477. package/src/core/ui-packs/ko.ts +45 -0
  478. package/src/core/ui-packs/nl.ts +47 -0
  479. package/src/core/ui-packs/no.ts +45 -0
  480. package/src/core/ui-packs/pl.ts +46 -0
  481. package/src/core/ui-packs/pt-br.ts +47 -0
  482. package/src/core/ui-packs/pt.ts +46 -0
  483. package/src/core/ui-packs/ro.ts +46 -0
  484. package/src/core/ui-packs/ru.ts +46 -0
  485. package/src/core/ui-packs/sk.ts +45 -0
  486. package/src/core/ui-packs/sr.ts +46 -0
  487. package/src/core/ui-packs/sv.ts +45 -0
  488. package/src/core/ui-packs/th.ts +44 -0
  489. package/src/core/ui-packs/tr.ts +46 -0
  490. package/src/core/ui-packs/uk.ts +46 -0
  491. package/src/core/ui-packs/vi.ts +46 -0
  492. package/src/core/ui-packs/zh-tw.ts +44 -0
  493. package/src/core/ui-packs/zh.ts +44 -0
  494. package/src/core/variables.ts +103 -0
  495. package/src/deploy/adapter-output.ts +7 -2
  496. package/src/deploy/adapters/cloudflare.ts +7 -5
  497. package/src/deploy/adapters/node.ts +47 -9
  498. package/src/deploy/adapters/types.ts +7 -3
  499. package/src/deploy/artifacts.ts +79 -9
  500. package/src/deploy/cloudflare-negotiation.ts +35 -5
  501. package/src/deploy/headers.ts +2 -1
  502. package/src/deploy/node-headers.ts +63 -9
  503. package/src/deploy/platforms/cloudflare.ts +45 -9
  504. package/src/deploy/platforms/netlify.ts +35 -2
  505. package/src/deploy/platforms/node.ts +12 -2
  506. package/src/deploy/platforms/types.ts +21 -7
  507. package/src/deploy/platforms/vercel.ts +149 -17
  508. package/src/deploy/redirects.ts +151 -24
  509. package/src/deploy/rss.ts +3 -1
  510. package/src/deploy/sitemap.ts +39 -5
  511. package/src/deploy/vercel-negotiation.ts +326 -102
  512. package/src/eval/agents.ts +18 -1
  513. package/src/eval/prompts.ts +6 -3
  514. package/src/eval/report.ts +34 -13
  515. package/src/eval/run.ts +5 -0
  516. package/src/markdown/api-rail.ts +259 -0
  517. package/src/markdown/code-title.ts +35 -9
  518. package/src/markdown/features.ts +3 -2
  519. package/src/markdown/fence-meta.ts +2 -0
  520. package/src/markdown/include.ts +11 -1
  521. package/src/markdown/index.ts +28 -5
  522. package/src/markdown/math.ts +4 -4
  523. package/src/markdown/relative-links.ts +3 -2
  524. package/src/markdown/variables.ts +56 -0
  525. package/src/markdown/views.ts +82 -0
  526. package/src/narration/build.ts +412 -0
  527. package/src/narration/player.ts +249 -0
  528. package/src/narration/provider.ts +29 -0
  529. package/src/narration/script.ts +592 -0
  530. package/src/og/card.ts +7 -6
  531. package/src/openapi/checks.ts +273 -0
  532. package/src/openapi/graphql-build.ts +21 -0
  533. package/src/openapi/graphql.ts +11 -0
  534. package/src/openapi/model.ts +72 -27
  535. package/src/openapi/overlay.ts +256 -0
  536. package/src/openapi/parse.ts +182 -4
  537. package/src/openapi/references.ts +64 -8
  538. package/src/openapi/render-mdx.ts +5 -1
  539. package/src/openapi/scalar.ts +40 -6
  540. package/src/openapi/source.ts +40 -15
  541. package/src/ratelimit/cloudflare.ts +54 -0
  542. package/src/ratelimit/index.ts +30 -0
  543. package/src/ratelimit/memory.ts +45 -0
  544. package/src/ratelimit/runtime.ts +247 -0
  545. package/src/ratelimit/schema.ts +28 -0
  546. package/src/ratelimit/upstash.ts +60 -0
  547. package/src/ratelimit/wrangler.ts +70 -0
  548. package/src/reference/asyncapi.ts +2 -2
  549. package/src/reference/graphql.ts +20 -3
  550. package/src/reference/index.ts +1 -0
  551. package/src/reference/openapi.ts +21 -7
  552. package/src/reference/options.ts +80 -8
  553. package/src/reference/scalar.ts +33 -8
  554. package/src/registry/eject.ts +23 -5
  555. package/src/registry/registry.ts +7 -0
  556. package/src/search/adapters/locale-scope.ts +30 -0
  557. package/src/search/adapters/typesense.ts +14 -4
  558. package/src/search/build.ts +21 -3
  559. package/src/search/documents.ts +26 -2
  560. package/src/search/orama-index.ts +191 -34
  561. package/src/search/pagefind-ranking.ts +39 -0
  562. package/src/search/source-pages.ts +29 -0
  563. package/src/search/sync/algolia.ts +111 -10
  564. package/src/search/sync/index.ts +52 -13
  565. package/src/search/sync/orama-cloud.ts +3 -0
  566. package/src/search/sync/typesense.ts +76 -26
  567. package/src/seo/metatags.ts +67 -0
  568. package/src/sources/contentful.ts +12 -0
  569. package/src/sources/github-releases.ts +7 -1
  570. package/src/sources/shared.ts +3 -0
  571. package/src/theme/chrome-icons.ts +1 -0
  572. package/src/theme/color.ts +500 -0
  573. package/src/theme/entry.ts +85 -6
  574. package/src/theme/palette.ts +121 -45
  575. package/src/translate/prompts.ts +1 -0
  576. package/src/translate/validate.ts +31 -3
  577. package/src/upgrade/upgrade.ts +4 -171
  578. package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
  579. package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
  580. package/dist/cli/chunk-35d4wj9f.js.map +0 -15
  581. package/dist/cli/chunk-364znk6q.js +0 -75
  582. package/dist/cli/chunk-364znk6q.js.map +0 -11
  583. package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
  584. package/dist/cli/chunk-8ktnccpt.js.map +0 -10
  585. package/dist/cli/chunk-9t7a85s3.js.map +0 -10
  586. package/dist/cli/chunk-b07cmahc.js +0 -145
  587. package/dist/cli/chunk-b07cmahc.js.map +0 -11
  588. package/dist/cli/chunk-c8chx29p.js.map +0 -36
  589. package/dist/cli/chunk-e04dxsz1.js +0 -39
  590. package/dist/cli/chunk-e04dxsz1.js.map +0 -10
  591. package/dist/cli/chunk-j85vccga.js.map +0 -36
  592. package/dist/cli/chunk-p3v96n38.js.map +0 -10
  593. package/dist/cli/chunk-pehfxfta.js.map +0 -10
  594. package/dist/cli/chunk-pv29h0wf.js.map +0 -190
  595. package/dist/cli/chunk-q58y5e6a.js.map +0 -10
  596. package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
  597. package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
  598. package/dist/cli/chunk-yfyb25rh.js.map +0 -14
  599. package/docs/content/sources.mdx +0 -334
  600. /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
  601. /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
  602. /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
  603. /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
  604. /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
  605. /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
  606. /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
  607. /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.js.map} +0 -0
@@ -4,19 +4,26 @@ import {
4
4
  resolveDocsCollection,
5
5
  TOC_HIDDEN_KEY,
6
6
  deployPassthrough,
7
+ RATE_LIMIT_BINDING,
7
8
  fontLocaleCodes,
8
9
  buildFontEntries,
10
+ isPatternPath,
11
+ compileEveryRedirect,
12
+ hasVariables,
9
13
  SVG_ASSET_HEADERS,
10
14
  applyBaseToAstroRedirects,
15
+ withMirrorRedirects,
11
16
  distDir,
12
17
  adapterRoot,
13
- deployPlatform,
14
- BLUME_IGNORE_DIRS
15
- } from "./chunk-pv29h0wf.js";
18
+ deployPlatform
19
+ } from "./chunk-ehweg4fr.js";
16
20
  import {
17
21
  trimChar,
18
22
  normalizeBasePath
19
- } from "./chunk-3em5wd2y.js";
23
+ } from "./chunk-zccbjcj0.js";
24
+ import {
25
+ BLUME_IGNORE_DIRS
26
+ } from "./chunk-kwrg63tm.js";
20
27
 
21
28
  // src/deploy/adapter-output.ts
22
29
  import { existsSync } from "node:fs";
@@ -28,7 +35,7 @@ var deployOutputDir = (config, context) => {
28
35
  };
29
36
  var deployStaticDir = (config, context) => {
30
37
  const { deployment } = config;
31
- return deployment.options.output === "server" ? deployPlatform(deployment).serverStaticDir(context) : distDir(context);
38
+ return deployment.options.output === "server" ? deployPlatform(deployment).serverStaticDir(context, normalizeBasePath(deployment.options.base)) : distDir(context);
32
39
  };
33
40
  var surfaceAdapterOutput = async (config, context) => {
34
41
  const { deployment } = config;
@@ -212,6 +219,23 @@ var publishRuntimeModules = (modules) => {
212
219
  import { existsSync as existsSync2, readFileSync } from "node:fs";
213
220
  import { pathToFileURL } from "node:url";
214
221
  import { dirname as dirname2, isAbsolute as isAbsolute2, join as join3, relative as relative2 } from "pathe";
222
+
223
+ // src/ai/ask-limits.ts
224
+ var ASK_MAX_MESSAGES = 40;
225
+ var ASK_MAX_MESSAGES_CHARS = 24000;
226
+
227
+ // src/consent/clients.ts
228
+ var CONSENT_CLIENT_MODULES = new Map([
229
+ ["native", "blume/components/layout/consent/native.ts"]
230
+ ]);
231
+
232
+ // src/markdown/api-rail.ts
233
+ var API_RAIL_KEY = "blumeApiRail";
234
+
235
+ // src/markdown/views.ts
236
+ var VIEWS_KEY = "blumeViews";
237
+
238
+ // src/astro/templates.ts
215
239
  var WORKSPACE_MARKERS = [
216
240
  ".git",
217
241
  "bun.lock",
@@ -254,13 +278,13 @@ var renderAstroAdapter = (deployment, context, ejected) => {
254
278
  const { astro } = platform;
255
279
  const args = {
256
280
  ...astro.options(context),
257
- ...deployPassthrough(deployment.options)
281
+ ...deployPassthrough(deployment.options, astro.configOptions)
258
282
  };
259
283
  const argsLiteral = Object.keys(args).length > 0 ? JSON.stringify(args) : "";
260
284
  const construct = `adapter(${argsLiteral})`;
261
285
  const expression = platform.hiddenRuntime.showProjectRoot && !ejected ? `withAdapterRoot(${construct}, ${JSON.stringify(adapterRoot(context))})` : construct;
262
286
  return {
263
- configEntries: Object.entries(astro.config).map(([key, value]) => `
287
+ configEntries: Object.entries(astro.config(deployment.options)).map(([key, value]) => `
264
288
  ${key}: ${JSON.stringify(value)},`).join(""),
265
289
  importLine: `import adapter from "${astro.package}";
266
290
  `,
@@ -288,7 +312,7 @@ var runtimeDependencies = (options) => {
288
312
  if (needsSvelte) {
289
313
  deps.push("@astrojs/svelte");
290
314
  }
291
- deps.push(...new Set(config.reference.flatMap((adapter) => adapter.runtimeDeps)), ...config.search.provider.runtimeDeps, ...config.analytics.flatMap((adapter) => adapter.runtimeDeps));
315
+ deps.push(...new Set(config.reference.flatMap((adapter) => adapter.runtimeDeps)), ...config.search.provider.runtimeDeps, ...config.analytics.flatMap((adapter) => adapter.runtimeDeps), ...config.consent?.runtimeDeps ?? []);
292
316
  for (const source of config.content.sources) {
293
317
  for (const dep of source.runtimeDeps) {
294
318
  if (!deps.includes(dep)) {
@@ -319,7 +343,7 @@ var RENDER_EXTERNAL_DEPS = [
319
343
  ];
320
344
  var renderUserAliases = (aliases) => Object.entries(aliases ?? {}).toSorted(([a], [b]) => b.length - a.length).map(([find, replacement]) => `
321
345
  ${JSON.stringify(find)}: ${JSON.stringify(replacement)},`).join("");
322
- var REACT_EXCLUDE = String.raw`exclude: [/\/node_modules\/\.vite\//, /\/\.cache\/vite\//]`;
346
+ var REACT_EXCLUDE = String.raw`exclude: [/\/\.cache\/vite\//]`;
323
347
  var runtimeCacheOptions = (context, generatedModulesDir) => {
324
348
  if (generatedModulesDir !== undefined) {
325
349
  return { astro: "", vite: "" };
@@ -331,7 +355,7 @@ var runtimeCacheOptions = (context, generatedModulesDir) => {
331
355
  cacheDir: ${JSON.stringify(`${context.outDir}/.cache/vite`)},`
332
356
  };
333
357
  };
334
- var reactIntegration = (compilerPath) => compilerPath ? `react({ babel: { plugins: [[${JSON.stringify(compilerPath)}, { target: "19" }]] }, ${REACT_EXCLUDE} })` : `react({ ${REACT_EXCLUDE} })`;
358
+ var reactIntegration = (compiler) => compiler ? `react({ compiler: true, ${REACT_EXCLUDE} })` : `react({ ${REACT_EXCLUDE} })`;
335
359
  var renderIntegrationBridge = (bridge) => {
336
360
  if (!bridge) {
337
361
  return {
@@ -377,7 +401,7 @@ var resolveOptimizeDeps = (options) => {
377
401
  ...features.mermaid ? ["blume > mermaid"] : [],
378
402
  ...features.epub ? ["blume > epub-gen-memory/bundle"] : [],
379
403
  ...searchDep ? [`blume > ${searchDep}`] : [],
380
- ...options.needsReact && options.reactCompilerPath ? ["react/compiler-runtime"] : []
404
+ ...options.needsReact && options.reactCompiler ? ["react/compiler-runtime"] : []
381
405
  ];
382
406
  return { optimizeDepsEntries, optimizeDepsInclude };
383
407
  };
@@ -404,17 +428,24 @@ var renderRuntimeModuleWiring = (generatedModulesDir) => {
404
428
  ${JSON.stringify(id)}: ${configPath(`${generatedModulesDir}/${file}`, true)},`).join("");
405
429
  return { aliasLines, imports: [], pluginEntry: "" };
406
430
  };
407
- var blumeIntegrationOptions = (options) => options.ejected ? {
408
- buildArtifactsRoot: ".",
409
- contentRoutes: options.contentRoutes,
410
- homeLinkHeader: buildHomeLinkHeader(options.config, options.contentRoutes, "dev") ?? undefined,
411
- pages: options.pages
412
- } : { pages: options.pages };
431
+ var blumeIntegrationOptions = (options) => {
432
+ const shared = { pages: options.pages };
433
+ if (options.redirects.length > 0) {
434
+ shared.redirects = options.redirects;
435
+ }
436
+ return options.ejected ? {
437
+ ...shared,
438
+ buildArtifactsRoot: ".",
439
+ contentRoutes: options.contentRoutes,
440
+ homeLinkHeader: buildHomeLinkHeader(options.config, options.contentRoutes, "dev") ?? undefined
441
+ } : shared;
442
+ };
413
443
  var astroConfigTemplate = (options) => {
414
444
  const { context, config, needsReact, pages, themePath } = options;
415
445
  const { astro: cacheOptions, vite: viteCacheOption } = runtimeCacheOptions(context, options.generatedModulesDir);
416
446
  const {
417
447
  askPath,
448
+ consentClientPath,
418
449
  contentRoutes,
419
450
  examplesPath,
420
451
  examplesThemePath,
@@ -439,7 +470,7 @@ var astroConfigTemplate = (options) => {
439
470
  context,
440
471
  features,
441
472
  needsReact,
442
- reactCompilerPath: options.reactCompilerPath,
473
+ reactCompiler: options.reactCompiler,
443
474
  searchKind: config.search.provider.kind
444
475
  });
445
476
  const {
@@ -460,9 +491,11 @@ var astroConfigTemplate = (options) => {
460
491
  prefixDefaultLocale: !config.i18n.hideDefaultLocalePrefix
461
492
  }
462
493
  })},` : "";
463
- const basedRedirects = applyBaseToAstroRedirects(config.redirects, config.basePath, deployment.options.base ?? "", new Set(contentRoutes));
464
- const redirectsOption = basedRedirects.length > 0 ? `
465
- redirects: ${JSON.stringify(Object.fromEntries(basedRedirects.map((redirect) => [
494
+ const redirectPages = new Set(contentRoutes);
495
+ const basedRedirects = withMirrorRedirects(applyBaseToAstroRedirects(config.redirects, config.basePath, deployment.options.base ?? "", redirectPages), redirectPages, { from: "", to: normalizeBasePath(deployment.options.base) });
496
+ const exactRedirects = basedRedirects.filter((redirect) => !isPatternPath(redirect.from));
497
+ const redirectsOption = exactRedirects.length > 0 ? `
498
+ redirects: ${JSON.stringify(Object.fromEntries(exactRedirects.map((redirect) => [
466
499
  redirect.from,
467
500
  { destination: redirect.to, status: redirect.status }
468
501
  ])))},` : "";
@@ -492,12 +525,15 @@ var astroConfigTemplate = (options) => {
492
525
  ` : "";
493
526
  const svelteImport = needsSvelte ? `import svelte from "@astrojs/svelte";
494
527
  ` : "";
528
+ const substitutesVariables = hasVariables(config.variables);
529
+ const variablesPluginEntry = substitutesVariables ? `variablesVitePlugin(${JSON.stringify(config.variables)}), ` : "";
495
530
  const blumeImports = [
496
531
  "blumeIntegration",
497
532
  "includeHmrPlugin",
498
533
  "prerenderDepsPlugin",
499
534
  ...runtimeModuleImports,
500
- ...adapterOption.includes("withAdapterRoot") ? ["withAdapterRoot"] : []
535
+ ...adapterOption.includes("withAdapterRoot") ? ["withAdapterRoot"] : [],
536
+ ...substitutesVariables ? ["variablesVitePlugin"] : []
501
537
  ];
502
538
  const blumeImport = `import { ${blumeImports.join(", ")} } from "blume/astro";
503
539
  `;
@@ -509,14 +545,15 @@ var astroConfigTemplate = (options) => {
509
545
  contentRoot: options.contentRoot,
510
546
  deployBase,
511
547
  externalLinks: config.markdown.externalLinks,
512
- headingAnchors: config.markdown.headingAnchors
548
+ headingAnchors: config.markdown.headingAnchors,
549
+ variables: config.variables
513
550
  });
514
551
  const processorOptions = options.generatedModulesDir === undefined ? processorLiteral : `{ ...${processorLiteral}, dataFile: ${configPath(`${options.generatedModulesDir}/data.json`, true)} }`;
515
552
  const integrations = [
516
553
  `mdx({ processor: blumeMdxProcessor(${processorOptions}) })`
517
554
  ];
518
555
  if (needsReact) {
519
- integrations.push(reactIntegration(options.reactCompilerPath));
556
+ integrations.push(reactIntegration(options.reactCompiler));
520
557
  }
521
558
  if (needsVue) {
522
559
  integrations.push("vue()");
@@ -528,7 +565,8 @@ var astroConfigTemplate = (options) => {
528
565
  config,
529
566
  contentRoutes,
530
567
  ejected,
531
- pages
568
+ pages,
569
+ redirects: compileEveryRedirect(basedRedirects)
532
570
  }))})`);
533
571
  const {
534
572
  configSourceMarker,
@@ -584,7 +622,7 @@ ${userConfigSetup}export default defineConfig({
584
622
  // the overlap only adds memory.
585
623
  build: { concurrency: Math.min(8, availableParallelism()) },
586
624
  vite: {${viteCacheOption}
587
- plugins: [${runtimeModulesPluginEntry}tailwindcss(), includeHmrPlugin(${configPath(`${context.outDir}/src/generated/includes.json`, ejected)}), prerenderDepsPlugin()],
625
+ plugins: [${runtimeModulesPluginEntry}${variablesPluginEntry}tailwindcss(), includeHmrPlugin(${configPath(`${context.outDir}/src/generated/includes.json`, ejected)}), prerenderDepsPlugin()],
588
626
  build: {${features.mermaid ? MERMAID_CHUNK_LIMIT : ""}
589
627
  rolldownOptions: {
590
628
  ${ROLLDOWN_ON_LOG},
@@ -593,8 +631,8 @@ ${userConfigSetup}export default defineConfig({
593
631
  // Everything hydration can reach must be part of the dev dep optimizer's
594
632
  // FIRST run. The Vite root is the generated runtime, so user pages,
595
633
  // islands, and aliased components live outside it and are only crawled
596
- // when first requested — and \`react/compiler-runtime\` is Babel-injected,
597
- // so no source scan can ever see it. A dependency discovered after
634
+ // when first requested — and \`react/compiler-runtime\` is injected by the
635
+ // React Compiler, so no source scan can ever see it. A dependency discovered after
598
636
  // hydration begins triggers a mid-session re-optimization whose new
599
637
  // generation imports React through new \`?v=\` URLs; the browser then
600
638
  // evaluates a second React copy and every island tears down with
@@ -640,6 +678,7 @@ ${userConfigSetup}export default defineConfig({
640
678
  resolve: {
641
679
  alias: {
642
680
  "blume:ask": ${configPath(askPath, ejected)},
681
+ "blume:consent-client": ${configPath(consentClientPath, ejected)},
643
682
  "blume:examples": ${configPath(examplesPath, ejected)},
644
683
  "blume:examples-theme": ${configPath(examplesThemePath, ejected)},
645
684
  "blume:features": ${configPath(featuresPath, ejected)},
@@ -719,18 +758,73 @@ var askCorsTemplate = (cors = []) => cors.length > 0 ? {
719
758
  imports: [
720
759
  'import { preflightResponse, withCors } from "blume/ai/cors.ts";'
721
760
  ],
722
- open: "withCors(ALLOWED_ORIGINS, async ({ request }) => {",
761
+ open: "withCors(ALLOWED_ORIGINS, async (context) => {",
723
762
  setup: `
724
763
  const ALLOWED_ORIGINS = ${JSON.stringify(cors)};
725
764
 
726
765
  export const OPTIONS: APIRoute = ({ request }) =>
727
766
  preflightResponse(request, ALLOWED_ORIGINS);
728
767
  `
729
- } : { close: "};", imports: [], open: "async ({ request }) => {", setup: "" };
768
+ } : { close: "};", imports: [], open: "async (context) => {", setup: "" };
769
+ var rateLimitTemplate = (adapter, scope) => {
770
+ if (!adapter) {
771
+ return { check: "", imports: [], setup: "" };
772
+ }
773
+ const imports = [
774
+ 'import { createLimiter, rateLimited } from "blume/ratelimit/runtime.ts";'
775
+ ];
776
+ let runtime = "";
777
+ if (adapter.kind === "upstash") {
778
+ imports.push('import { getSecret } from "astro:env/server";');
779
+ runtime = ", { secret: getSecret }";
780
+ } else if (adapter.kind === "cloudflare") {
781
+ imports.push("// @ts-ignore `cloudflare:workers` is typed once `wrangler types` has run.", 'import { env } from "cloudflare:workers";');
782
+ runtime = `, { binding: Reflect.get(env, ${JSON.stringify(RATE_LIMIT_BINDING)}) }`;
783
+ }
784
+ return {
785
+ check: ` const limited = await rateLimited(limiter, context, ${JSON.stringify(scope)});
786
+ if (limited) {
787
+ return limited;
788
+ }
789
+ `,
790
+ imports,
791
+ setup: `
792
+ const limiter = createLimiter(${JSON.stringify(adapter)}${runtime});
793
+ `
794
+ };
795
+ };
796
+ var askCaptchaTemplate = (adapter) => {
797
+ if (!adapter) {
798
+ return { check: "", imports: [], setup: "" };
799
+ }
800
+ const [secret = ""] = adapter.requiredSecrets;
801
+ return {
802
+ check: ` const captchaSecret = getSecret(${JSON.stringify(secret)});
803
+ if (!captchaSecret) {
804
+ return new Response(
805
+ ${JSON.stringify(`The assistant is not configured: set ${secret}.`)},
806
+ { status: 503 }
807
+ );
808
+ }
809
+ const captchaToken =
810
+ typeof body.captcha === "string" ? body.captcha : undefined;
811
+ if (!(await verifyCaptcha(CAPTCHA, captchaToken, context, { secret: captchaSecret }))) {
812
+ return new Response("Verification failed: the bot check didn't pass.", {
813
+ status: 403,
814
+ });
815
+ }
816
+ `,
817
+ imports: ['import { verifyCaptcha } from "blume/captcha/verify.ts";'],
818
+ setup: `
819
+ const CAPTCHA = ${JSON.stringify(adapter)};
820
+ `
821
+ };
822
+ };
730
823
  var ASK_BODY_LIMIT_BYTES = 65536;
731
824
  var askEndpointTemplate = (backend, options) => {
732
825
  const { instructions, retrieval } = options ?? {};
733
826
  const { grounded } = backend;
827
+ const tools = grounded && Boolean(options?.tools);
734
828
  const fallbackPrompt = instructions ? `${ASK_FALLBACK_PROMPT}
735
829
 
736
830
  ${instructions}` : ASK_FALLBACK_PROMPT;
@@ -750,14 +844,33 @@ ${instructions}` : ASK_FALLBACK_PROMPT;
750
844
  if (retrieval) {
751
845
  groundFields.push(`retrieval: ${JSON.stringify(retrieval)}`);
752
846
  }
847
+ if (tools) {
848
+ groundFields.push("tools: true");
849
+ }
753
850
  const groundOptions = groundFields.length > 0 ? `, { ${groundFields.join(", ")} }` : "";
754
851
  setup += `
755
852
  const ground = createAskContext(askData${groundOptions});
756
853
  `;
854
+ if (tools) {
855
+ imports.push('import { stepCountIs } from "ai";', 'import { ASK_MAX_STEPS, createAskTools } from "blume/ai/ask-tools.ts";');
856
+ setup += `const askTools = createAskTools(askData);
857
+ `;
858
+ }
757
859
  }
758
860
  const cors = askCorsTemplate(options?.cors);
759
861
  imports.push(...cors.imports);
760
- const validate = ` const text = await readCappedText(request, ${ASK_BODY_LIMIT_BYTES});
862
+ const limit = rateLimitTemplate(options?.rateLimit, "ask");
863
+ for (const line of limit.imports) {
864
+ if (!imports.includes(line)) {
865
+ imports.push(line);
866
+ }
867
+ }
868
+ setup += limit.setup;
869
+ const captcha = askCaptchaTemplate(options?.captcha);
870
+ imports.push(...captcha.imports);
871
+ setup += captcha.setup;
872
+ const validate = ` const { request } = context;
873
+ ${limit.check} const text = await readCappedText(request, ${ASK_BODY_LIMIT_BYTES});
761
874
  if (text === undefined) {
762
875
  return new Response("Request too large: the body must be at most 64 KB.", {
763
876
  status: 413,
@@ -773,7 +886,7 @@ const ground = createAskContext(askData${groundOptions});
773
886
  const valid =
774
887
  Array.isArray(raw) &&
775
888
  raw.length > 0 &&
776
- raw.length <= 40 &&
889
+ raw.length <= ${ASK_MAX_MESSAGES} &&
777
890
  raw.every(
778
891
  (m: unknown) =>
779
892
  typeof m === "object" &&
@@ -781,10 +894,10 @@ const ground = createAskContext(askData${groundOptions});
781
894
  ("role" in m && (m.role === "user" || m.role === "assistant")) &&
782
895
  ("content" in m && typeof m.content === "string")
783
896
  ) &&
784
- JSON.stringify(raw).length <= 24_000;
897
+ JSON.stringify(raw).length <= ${ASK_MAX_MESSAGES_CHARS};
785
898
  if (!valid) {
786
899
  return new Response(
787
- "Invalid request: send 1-40 user/assistant messages with string content.",
900
+ "Invalid request: send 1-${ASK_MAX_MESSAGES} user/assistant messages with string content.",
788
901
  { status: 400 }
789
902
  );
790
903
  }
@@ -802,6 +915,7 @@ const ground = createAskContext(askData${groundOptions});
802
915
  grounded ? "instructions" : `instructions:
803
916
  ${JSON.stringify(fallbackPrompt)}`,
804
917
  "messages",
918
+ ...tools ? ["tools: askTools(body.page)", "stopWhen: stepCountIs(ASK_MAX_STEPS)"] : [],
805
919
  ...backend.template.fields
806
920
  ];
807
921
  const call = ` const result = streamText({
@@ -817,7 +931,7 @@ ${call}` : call;
817
931
  const handler = `export const POST: APIRoute = ${cors.open}
818
932
  ${validate}
819
933
  ${keyCheck}
820
- try {
934
+ ${captcha.check} try {
821
935
  ${stream}
822
936
  return createTextStreamResponse({
823
937
  stream: toTextStream({ stream: result.stream }),
@@ -844,9 +958,11 @@ const { strings } = Astro.props;
844
958
  ---
845
959
 
846
960
  <Assistant
961
+ captcha={data.config.assistant?.captcha ?? undefined}
847
962
  endpoint={data.config.assistant?.endpoint ?? undefined}
848
963
  strings={strings ?? data.ui.assistant}
849
964
  suggestions={data.config.assistant?.suggestions ?? []}
965
+ support={data.config.assistant?.support ?? undefined}
850
966
  />
851
967
  ` : `---
852
968
  // Generated by Blume. Do not edit.
@@ -894,6 +1010,25 @@ ${features.epub ? `export const loadEpub:
894
1010
  | (() => Promise<typeof import("epub-gen-memory/bundle")>)
895
1011
  | null = () => import("epub-gen-memory/bundle");` : "export const loadEpub: (() => Promise<unknown>) | null = null;"}
896
1012
  `;
1013
+ var consentClientTemplate = (consent) => {
1014
+ const module = consent ? CONSENT_CLIENT_MODULES.get(consent.kind) : undefined;
1015
+ if (!(consent && module)) {
1016
+ return `// Generated by Blume. Do not edit.
1017
+ // The consent adapter has no browser module, or consent is off.
1018
+ export const startConsentClient = (): void => {};
1019
+ `;
1020
+ }
1021
+ return `// Generated by Blume. Do not edit.
1022
+ // The \`${consent.kind}\` consent adapter's browser module, with its options.
1023
+ import { start } from ${JSON.stringify(module)};
1024
+
1025
+ export const startConsentClient = (
1026
+ consent: Parameters<typeof start>[0]
1027
+ ): void => {
1028
+ start(consent, ${JSON.stringify(consent.options)});
1029
+ };
1030
+ `;
1031
+ };
897
1032
  var searchClientTemplate = (config) => {
898
1033
  const { provider } = config.search;
899
1034
  switch (provider.mode) {
@@ -905,10 +1040,11 @@ var searchClientTemplate = (config) => {
905
1040
  return hostedSearchClient(provider);
906
1041
  }
907
1042
  case "server": {
908
- return `${SEARCH_CLIENT_HEADER}${searchClientImport("endpoint")}${SEARCH_BASE_IMPORT}
1043
+ return `${SEARCH_CLIENT_HEADER}${searchClientImport("endpoint")}${SEARCH_BASE_IMPORT}import type { SearchClientOptions } from "blume/components/layout/search/types.ts";
909
1044
  const api = joinBase(import.meta.env.BASE_URL, "api/search");
910
1045
 
911
- export const createSearch = () => create({ api });
1046
+ export const createSearch = (options: SearchClientOptions = {}) =>
1047
+ create({ ...options, api });
912
1048
  `;
913
1049
  }
914
1050
  case "pagefind": {
@@ -925,21 +1061,47 @@ export const createSearch = () => create({ url });
925
1061
  }
926
1062
  }
927
1063
  };
928
- var mixedbreadSearchEndpointTemplate = (options) => `// Generated by Blume. Do not edit.
929
- import type { APIRoute } from "astro";
930
- import { getSecret } from "astro:env/server";
931
- import Mixedbread from "@mixedbread/sdk";
932
- import { readCappedText } from "blume/core/request-body.ts";
1064
+ var mixedbreadSearchEndpointTemplate = (options, pages, rateLimit) => {
1065
+ const { search_options: tuning, storeId, ...searchOptions } = options;
1066
+ const limit = rateLimitTemplate(rateLimit, "search");
1067
+ const imports = [
1068
+ 'import type { APIRoute } from "astro";',
1069
+ 'import { getSecret } from "astro:env/server";',
1070
+ 'import Mixedbread from "@mixedbread/sdk";',
1071
+ 'import { readCappedText } from "blume/core/request-body.ts";',
1072
+ ...limit.imports.filter((line) => !line.includes('"astro:env/server"'))
1073
+ ];
1074
+ return `// Generated by Blume. Do not edit.
1075
+ ${imports.join(`
1076
+ `)}
933
1077
 
934
1078
  export const prerender = false;
935
1079
 
936
1080
  const client = new Mixedbread({ apiKey: getSecret("MIXEDBREAD_API_KEY") ?? "" });
937
- const OPTIONS = ${JSON.stringify(options)};
938
- // Every option besides the store reaches the search call verbatim.
939
- const { storeId: STORE_ID, ...SEARCH_OPTIONS } = OPTIONS;
940
-
941
- export const POST: APIRoute = async ({ request }) => {
942
- // A search body is one short query: read it under a 16 KB cap, so a
1081
+ const STORE_ID = ${JSON.stringify(storeId)};
1082
+ // Every other option reaches the search call verbatim.
1083
+ const SEARCH_OPTIONS = ${JSON.stringify(searchOptions)};
1084
+ const SEARCH_TUNING = ${JSON.stringify(tuning ?? {})};
1085
+ // Each page's source file, relative to the project root, and the page it renders.
1086
+ const PAGES = new Map<string, { title: string; url: string }>(${JSON.stringify(pages)});
1087
+
1088
+ // The page a synced file renders. \`mxbai store sync\` records the path
1089
+ // relative to where it ran (the project root, or a monorepo root above it), so
1090
+ // the longest trailing run of that path that names a page's file wins.
1091
+ const pageFor = (path: string) => {
1092
+ const segments = path.replaceAll("\\\\", "/").split("/");
1093
+ for (let start = 0; start < segments.length; start += 1) {
1094
+ const page = PAGES.get(segments.slice(start).join("/"));
1095
+ if (page) {
1096
+ return page;
1097
+ }
1098
+ }
1099
+ return undefined;
1100
+ };
1101
+ ${limit.setup}
1102
+ export const POST: APIRoute = async (context) => {
1103
+ const { request } = context;
1104
+ ${limit.check} // A search body is one short query: read it under a 16 KB cap, so a
943
1105
  // self-hosted server never buffers an arbitrarily large POST first.
944
1106
  const text = await readCappedText(request, 16_384);
945
1107
  if (text === undefined) {
@@ -961,29 +1123,39 @@ export const POST: APIRoute = async ({ request }) => {
961
1123
  });
962
1124
  }
963
1125
  // \`top_k\` defaults to 8 unless an option sets it; the query and store
964
- // always come from the request and \`storeId\`.
1126
+ // always come from the request and \`storeId\`. File metadata is always
1127
+ // returned: it holds the path \`mxbai store sync\` recorded for the file.
965
1128
  const response = await client.stores.search({
966
1129
  top_k: 8,
967
1130
  ...SEARCH_OPTIONS,
968
1131
  query,
1132
+ search_options: { ...SEARCH_TUNING, return_metadata: true },
969
1133
  store_identifiers: [STORE_ID],
970
1134
  });
971
- const hits = (response.data ?? []).map((chunk) => {
1135
+ const seen = new Set<string>();
1136
+ const hits = (response.data ?? []).flatMap((chunk) => {
1137
+ const { file_path: path } = (chunk.metadata ?? {}) as { file_path?: unknown };
1138
+ const page = typeof path === "string" ? pageFor(path) : undefined;
1139
+ // A file no page renders has nowhere to link, and a page's later chunks
1140
+ // would repeat it: one hit per page, at its best chunk.
1141
+ if (!page || seen.has(page.url)) {
1142
+ return [];
1143
+ }
1144
+ seen.add(page.url);
972
1145
  const meta = chunk.generated_metadata ?? {};
973
1146
  // Only a text chunk carries \`text\`; image, audio, and video chunks fall
974
1147
  // back to the excerpt the store generated for them.
975
1148
  const text = "text" in chunk ? chunk.text : undefined;
976
- return {
977
- excerpt: text ?? meta.excerpt ?? "",
978
- title: meta.title ?? chunk.filename ?? "",
979
- url: meta.url ?? "",
980
- };
1149
+ return [
1150
+ { excerpt: text ?? meta.excerpt ?? "", title: page.title, url: page.url },
1151
+ ];
981
1152
  });
982
1153
  return new Response(JSON.stringify(hits), {
983
1154
  headers: { "Content-Type": "application/json" },
984
1155
  });
985
1156
  };
986
1157
  `;
1158
+ };
987
1159
  var rawMarkdownEndpointTemplate = (kind) => `// Generated by Blume. Do not edit.
988
1160
  import raw from "blume:raw-markdown";
989
1161
 
@@ -1128,16 +1300,22 @@ const handler = createMcpFetchHandler(data);
1128
1300
 
1129
1301
  export const ALL: APIRoute = ({ request }) => handler(request);
1130
1302
  `;
1131
- var playgroundProxyTemplate = (origins) => `// Generated by Blume. Do not edit.
1132
- import type { APIRoute } from "astro";
1133
- import { createPlaygroundProxyHandler } from "blume/openapi/proxy.ts";
1303
+ var playgroundProxyTemplate = (origins, rateLimit) => {
1304
+ const limit = rateLimitTemplate(rateLimit, "api-proxy");
1305
+ const route = limit.check ? `export const ALL: APIRoute = async (context) => {
1306
+ ${limit.check} return handler(context.request);
1307
+ };` : "export const ALL: APIRoute = ({ request }) => handler(request);";
1308
+ return `// Generated by Blume. Do not edit.
1309
+ ${['import type { APIRoute } from "astro";', 'import { createPlaygroundProxyHandler } from "blume/openapi/proxy.ts";', ...limit.imports].join(`
1310
+ `)}
1134
1311
 
1135
1312
  export const prerender = false;
1136
1313
 
1137
1314
  const handler = createPlaygroundProxyHandler(${JSON.stringify(origins)});
1138
-
1139
- export const ALL: APIRoute = ({ request }) => handler(request);
1315
+ ${limit.setup}
1316
+ ${route}
1140
1317
  `;
1318
+ };
1141
1319
  var staticJsonEndpointTemplate = (payload) => `// Generated by Blume. Do not edit.
1142
1320
  export const prerender = true;
1143
1321
 
@@ -1378,6 +1556,9 @@ var contentComponentsSource = (mathEnabled) => {
1378
1556
  return {
1379
1557
  imports: `import Accordion from "blume/components/content/Accordion.astro";
1380
1558
  import AccordionItem from "blume/components/content/AccordionItem.astro";
1559
+ import ApiEndpoint from "blume/components/content/ApiEndpoint.astro";
1560
+ import ApiPlayground from "blume/components/content/ApiPlayground.astro";
1561
+ import ApiRail from "blume/components/content/ApiRail.astro";
1381
1562
  import AutoTypeTable from "blume/components/content/AutoTypeTable.astro";
1382
1563
  import Badge from "blume/components/content/Badge.astro";
1383
1564
  import Callout from "blume/components/content/Callout.astro";
@@ -1397,7 +1578,11 @@ import FileTree from "blume/components/content/FileTree.astro";
1397
1578
  import Frame from "blume/components/content/Frame.astro";
1398
1579
  import GithubInfo from "blume/components/content/GithubInfo.astro";
1399
1580
  import Panel from "blume/components/content/Panel.astro";
1581
+ import ParamField from "blume/components/content/ParamField.astro";
1400
1582
  import Prompt from "blume/components/content/Prompt.astro";
1583
+ import RequestExample from "blume/components/content/RequestExample.astro";
1584
+ import ResponseExample from "blume/components/content/ResponseExample.astro";
1585
+ import ResponseField from "blume/components/content/ResponseField.astro";
1401
1586
  import Step from "blume/components/content/Step.astro";
1402
1587
  import Steps from "blume/components/content/Steps.astro";
1403
1588
  import Tab from "blume/components/content/Tab.astro";
@@ -1408,10 +1593,13 @@ import TreeRoot from "blume/components/content/Tree.astro";
1408
1593
  import TreeFile from "blume/components/content/TreeFile.astro";
1409
1594
  import TreeFolder from "blume/components/content/TreeFolder.astro";
1410
1595
  import TypeTable from "blume/components/content/TypeTable.astro";
1596
+ import View from "blume/components/content/View.astro";
1411
1597
  import Visibility from "blume/components/content/Visibility.astro";
1412
1598
  import YouTube from "blume/components/content/YouTube.astro";
1413
1599
  import Icon from "blume/components/Icon.astro";
1414
1600
  import LocaleLinks from "blume/components/layout/LocaleLinks.astro";
1601
+ import NarrationPlayer from "blume/components/layout/NarrationPlayer.astro";
1602
+ import ViewSwitcher from "blume/components/content/ViewSwitcher.astro";
1415
1603
  import ApiOverview from "blume/components/openapi/ApiOverview.astro";
1416
1604
  import ApiTagOperations from "blume/components/openapi/ApiTagOperations.astro";
1417
1605
  import Operation from "blume/components/openapi/Operation.astro";
@@ -1419,7 +1607,10 @@ ${mathImport}import { mdxComponents as userMdx, layoutOverrides } from "../gener
1419
1607
  map: `{
1420
1608
  Accordion,
1421
1609
  AccordionItem,
1610
+ ApiEndpoint,
1422
1611
  ApiOverview,
1612
+ ApiPlayground,
1613
+ ApiRail,
1423
1614
  ApiTagOperations,
1424
1615
  AutoTypeTable,
1425
1616
  Badge,
@@ -1440,7 +1631,11 @@ ${mathImport}import { mdxComponents as userMdx, layoutOverrides } from "../gener
1440
1631
  Icon,
1441
1632
  Operation,
1442
1633
  Panel,
1634
+ ParamField,
1443
1635
  Prompt,
1636
+ RequestExample,
1637
+ ResponseExample,
1638
+ ResponseField,
1444
1639
  Step,
1445
1640
  Steps,
1446
1641
  Tab,
@@ -1449,6 +1644,7 @@ ${mathImport}import { mdxComponents as userMdx, layoutOverrides } from "../gener
1449
1644
  Tooltip,
1450
1645
  Tree,
1451
1646
  TypeTable,
1647
+ View,
1452
1648
  Visibility,
1453
1649
  YouTube,
1454
1650
  ${mathEntry}...userMdx,
@@ -1462,10 +1658,12 @@ var catchAllPageTemplate = (options) => {
1462
1658
  return `---
1463
1659
  // Generated by Blume. Do not edit.
1464
1660
  import { getEntry, render } from "astro:content";
1661
+ import { pageModeLayout } from "blume/core/page-modes.ts";
1465
1662
  import type { CollectionKey } from "astro:content";
1466
1663
  import RootLayout from "blume/components/layout/RootLayout.astro";
1467
1664
  import { withBase, withMountedBase } from "blume/components/islands/base-path.ts";
1468
1665
  import { mountBasePath, stripBasePath } from "blume/core/base-path.ts";
1666
+ import { routeSetFor, servesRoute } from "blume/core/locale-links.ts";
1469
1667
  import { resolveSlot } from "blume/components/layout/overrides.ts";
1470
1668
  ${componentImports}
1471
1669
  import data from "blume:data";
@@ -1513,6 +1711,13 @@ const { Content, headings: allHeadings, remarkPluginFrontmatter } = await render
1513
1711
  // frontmatter (see markdown/heading-anchors.ts). Only the plugin's array
1514
1712
  // counts: \`frontmatter.extend\` can declare the same key, and on a page with
1515
1713
  // no headings that user-supplied value would pass straight through.
1714
+ // A page written in \`<View>\` blocks gets their picker above the content;
1715
+ // the views plugin lists them through the render's frontmatter (see
1716
+ // markdown/views.ts), and only a list of titled entries counts.
1717
+ const viewsRaw = remarkPluginFrontmatter?.${VIEWS_KEY};
1718
+ const views = Array.isArray(viewsRaw)
1719
+ ? viewsRaw.filter((view) => typeof view?.title === "string")
1720
+ : [];
1516
1721
  const tocHiddenRaw = remarkPluginFrontmatter?.${TOC_HIDDEN_KEY};
1517
1722
  const tocHidden = new Set(Array.isArray(tocHiddenRaw) ? tocHiddenRaw : []);
1518
1723
  const headings =
@@ -1591,6 +1796,14 @@ const htmlLang = i18n ? locale : "en";
1591
1796
  // follows that language — not the (mirrored) page locale.
1592
1797
  const contentLocale =
1593
1798
  fallback && i18n?.fallbackLocale ? i18n.fallbackLocale : locale;
1799
+ // "Listen to this page", unless the page opts out. The spoken cues are read
1800
+ // between the content's own sentences, so they come from the content's
1801
+ // language (a fallback page's), while the player's labels follow the page.
1802
+ // A \`custom\` or \`frame\` page brings its own heading: no title, description,
1803
+ // or narration player above its content.
1804
+ const pageChrome = pageModeLayout(frontmatter.mode).chrome;
1805
+ const narration = pageChrome && frontmatter.narration ? data.config.narration : null;
1806
+ const narrationCues = (i18n ? (data.uiByLocale[contentLocale] ?? data.ui) : data.ui).narration;
1594
1807
  const contentDir = i18n
1595
1808
  ? (i18n.locales.find((l) => l.code === contentLocale)?.dir ?? "ltr")
1596
1809
  : "ltr";
@@ -1654,18 +1867,24 @@ const logicalRoute = i18n
1654
1867
  ? stripLocale(stripBasePath(data.config.basePath, route), locale)
1655
1868
  : route;
1656
1869
  // A page from a one-language source (GitHub Releases) gets no switcher: every
1657
- // other locale would only repeat the same text.
1870
+ // other locale would only repeat the same text. A locale with no real
1871
+ // translation links the page's fallback copy, which exists only while
1872
+ // fallbacks are on; where nothing is served at that URL (\`fallbackLocale:
1873
+ // null\`), the locale is left out rather than linked to a 404.
1658
1874
  const localeSwitch = i18n && !monolingual
1659
- ? i18n.locales.map((l) => {
1875
+ ? i18n.locales.flatMap((l) => {
1660
1876
  const alt = (alternates ?? []).find((x) => x.locale === l.code);
1661
- return {
1662
- code: l.code,
1663
- current: l.code === locale,
1664
- dir: l.dir,
1665
- href: alt ? alt.path : mountLocalized(logicalRoute, l.code),
1666
- label: l.label,
1667
- untranslated: !alt,
1668
- };
1877
+ const href = alt ? alt.path : mountLocalized(logicalRoute, l.code);
1878
+ return alt || servesRoute(routeSetFor(data.routes), href)
1879
+ ? [{
1880
+ code: l.code,
1881
+ current: l.code === locale,
1882
+ dir: l.dir,
1883
+ href,
1884
+ label: l.label,
1885
+ untranslated: !alt,
1886
+ }]
1887
+ : [];
1669
1888
  })
1670
1889
  : [];
1671
1890
 
@@ -1774,6 +1993,10 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
1774
1993
  canonical={canonical}
1775
1994
  editUrl={editUrl}
1776
1995
  feedback={data.config.feedback}
1996
+ feedbackComments={data.config.feedbackComments}
1997
+ pagination={frontmatter.pagination}
1998
+ related={frontmatter.related}
1999
+ search={frontmatter.search}
1777
2000
  exportPdf={${options.exportPdf}}
1778
2001
  exportEpub={${options.exportEpub}}${options.navFragments ? `
1779
2002
  navFragmentBase={withMountedBase(\`/blume-nav/\${version || "current"}/\${i18n && localePrefix(locale) ? locale : "default"}\`)}` : ""}
@@ -1782,13 +2005,25 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
1782
2005
  discovery={data.config.discovery}
1783
2006
  siteUrl={data.config.site}
1784
2007
  pageType={frontmatter.type}
2008
+ apiRail={remarkPluginFrontmatter?.${API_RAIL_KEY} === true}
2009
+ pageMode={frontmatter.mode}
1785
2010
  published={frontmatter.date ?? frontmatter.changelog?.date ?? null}
1786
2011
  lastModified={lastModified}
1787
2012
  noindex={effectiveNoindex}
1788
2013
  structuredDataEnabled={data.config.structuredData}
1789
2014
  >
1790
- <h1>{title}</h1>
1791
- {frontmatter.description && <p class="text-lg text-muted-foreground">{frontmatter.description}</p>}
2015
+ {pageChrome && <h1>{title}</h1>}
2016
+ {pageChrome && frontmatter.description && <p class="text-lg text-muted-foreground">{frontmatter.description}</p>}
2017
+ {narration && (
2018
+ <NarrationPlayer
2019
+ audioBase={narration.generated ? withMountedBase("/blume-narration/audio/") : undefined}
2020
+ cues={narrationCues}
2021
+ lang={i18n ? contentLocale : htmlLang}
2022
+ manifest={narration.generated ? withMountedBase(encodeURI(\`/blume-narration/\${route === "/" ? "index" : route.slice(1)}.json\`)) : undefined}
2023
+ strings={ui.narration}
2024
+ />
2025
+ )}
2026
+ {views.length > 1 && <ViewSwitcher label={ui.content.selectView} views={views} />}
1792
2027
  <LocaleLinks locale={locale}>
1793
2028
  <Content components={components} />
1794
2029
  </LocaleLinks>
@@ -1949,13 +2184,15 @@ const canonical = base ? base + basedRoute : null;
1949
2184
  const ogPath = data.config.og.enabled ? withMountedBase("/og/changelog.png") : null;
1950
2185
  const ogImage = ogPath && base ? base + ogPath : ogPath;
1951
2186
 
1952
- // The page chrome (h1, title, description) comes from the translatable
1953
- // \`changelog\` group; optional chaining tolerates a not-yet-regenerated data
1954
- // snapshot from before these keys existed.
2187
+ // The page chrome (h1, title, description, empty state) comes from the
2188
+ // translatable \`changelog\` group, which carries the \`changelog\` config's title and
2189
+ // description when it sets them; optional chaining tolerates a
2190
+ // not-yet-regenerated data snapshot from before these keys existed.
1955
2191
  const changelogTitle = data.ui.changelog?.title ?? "Changelog";
1956
2192
  const changelogDescription =
1957
2193
  data.ui.changelog?.description ??
1958
2194
  "Product updates, new features, and fixes from every release.";
2195
+ const changelogEmpty = data.ui.changelog?.empty ?? "No changelog entries yet.";
1959
2196
  // The layout suffixes "- {site title}" itself, so the page title is just the
1960
2197
  // changelog's own name — prefixing the site title too would double it
1961
2198
  // ("Acme Changelog - Acme").
@@ -2008,7 +2245,7 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
2008
2245
  <p class="text-lg text-muted-foreground">{changelogDescription}</p>
2009
2246
  {
2010
2247
  items.length === 0 ? (
2011
- <p>No changelog entries yet.</p>
2248
+ <p>{changelogEmpty}</p>
2012
2249
  ) : (
2013
2250
  <div class="not-prose mt-10 divide-y divide-border border-border border-y">
2014
2251
  {groups.map((group) => (
@@ -2559,7 +2796,7 @@ var runtimeTsconfigTemplate = () => `${JSON.stringify({
2559
2796
  }, null, 2)}
2560
2797
  `;
2561
2798
 
2562
- export { deployOutputDir, deployStaticDir, surfaceAdapterOutput, planComponentSlots, publishRuntimeModules, runtimeDependencies, EJECTED_CONFIG_HEADER, astroConfigTemplate, stagedContentDir, contentConfigTemplate, askEndpointTemplate, askComponentTemplate, searchEndpointTemplate, featuresTemplate, searchClientTemplate, mixedbreadSearchEndpointTemplate, rawMarkdownEndpointTemplate, contentAssetsEndpointTemplate, mcpPageFile, mcpEndpointTemplate, playgroundProxyTemplate, staticJsonEndpointTemplate, rssEndpointTemplate, navFragmentTemplate, ogEndpointTemplate, scalarReferenceTemplate, catchAllPageTemplate, changelogIndexTemplate, notFoundPageTemplate, notFoundMarkdownTemplate, notFoundJsonTemplate, apiPagesIndexTemplate, apiPageTemplate, apiNavigationTemplate, apiSearchTemplate, apiNotFoundTemplate, exampleSlug, exampleWrapperTemplate, examplesRouteBase, exampleMapTemplate, examplesPageTemplate, runtimePackageTemplate, runtimeTsconfigTemplate };
2799
+ export { deployOutputDir, deployStaticDir, surfaceAdapterOutput, planComponentSlots, publishRuntimeModules, runtimeDependencies, EJECTED_CONFIG_HEADER, astroConfigTemplate, stagedContentDir, contentConfigTemplate, askEndpointTemplate, askComponentTemplate, searchEndpointTemplate, featuresTemplate, consentClientTemplate, searchClientTemplate, mixedbreadSearchEndpointTemplate, rawMarkdownEndpointTemplate, contentAssetsEndpointTemplate, mcpPageFile, mcpEndpointTemplate, playgroundProxyTemplate, staticJsonEndpointTemplate, rssEndpointTemplate, navFragmentTemplate, ogEndpointTemplate, scalarReferenceTemplate, catchAllPageTemplate, changelogIndexTemplate, notFoundPageTemplate, notFoundMarkdownTemplate, notFoundJsonTemplate, apiPagesIndexTemplate, apiPageTemplate, apiNavigationTemplate, apiSearchTemplate, apiNotFoundTemplate, exampleSlug, exampleWrapperTemplate, examplesRouteBase, exampleMapTemplate, examplesPageTemplate, runtimePackageTemplate, runtimeTsconfigTemplate };
2563
2800
 
2564
- //# debugId=D53DB1B1EA2E6A3764756E2164756E21
2565
- //# sourceMappingURL=chunk-5m5nmvyq.js.map
2801
+ //# debugId=5E4553A34E0C7B9D64756E2164756E21
2802
+ //# sourceMappingURL=chunk-gb420vvz.js.map