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
@@ -1,7 +1,12 @@
1
1
  import type { PageRecord } from "../types.ts";
2
+ import type { ContentVariables } from "../variables.ts";
2
3
  import type { ContentSource } from "./types.ts";
3
4
  /** The subset of a scanned project the entry reader needs. */
4
5
  export interface EntryReadContext {
6
+ /** The site's content variables, substituted into what's read. */
7
+ config?: {
8
+ variables?: ContentVariables;
9
+ };
5
10
  /** The instantiated sources, keyed for `read()` lookups. */
6
11
  sources?: ContentSource[];
7
12
  }
@@ -297,7 +297,7 @@ export interface Navigation {
297
297
  cta?: HeaderAction | null;
298
298
  /** Pinned links shown above the sidebar sections, unscoped by tab. */
299
299
  featured: FeaturedLink[];
300
- /** Repo URL for the header link, or null when hidden (`navigation.repo`). */
300
+ /** Repo URL for the footer's GitHub link, or null when hidden (`navigation.repo`). */
301
301
  repoUrl?: string | null;
302
302
  /**
303
303
  * Where the header's brand link points in this locale: `logo.href` moved
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Content variables: `variables: { version: "2.1.0" }` in `blume.config.ts`
3
+ * makes `{{version}}` in a page read `2.1.0` wherever it appears in the body,
4
+ * code and links included. The syntax is Mintlify's, so migrated pages keep
5
+ * working.
6
+ *
7
+ * Substitution is textual, before any parsing, so a page's HTML, its search
8
+ * entry, its `.md` mirror, and `llms-full.txt` all agree: the MDX pipeline
9
+ * substitutes in a Vite transform ahead of the compiler (an MDX parser would
10
+ * read `{{version}}` as a JavaScript expression), the Markdown pipeline in a
11
+ * plugin over the parsed text, includes as their files are read, and the raw
12
+ * readers through {@link substituteVariables}. Only defined names are
13
+ * replaced; an undefined one in prose is a build error
14
+ * (`BLUME_UNDEFINED_VARIABLE`), and inside code it is left alone, since
15
+ * templating examples (`{{name}}` in a Handlebars snippet) are common there.
16
+ */
17
+ /** The variables a site defines, name to value. */
18
+ export type ContentVariables = Readonly<Record<string, string>>;
19
+ /** A variable name: letters, digits, `_`, and `-` (Mintlify's `api-url`). */
20
+ export declare const VARIABLE_NAME: RegExp;
21
+ /** Whether a site defines any variables, so the rest can be skipped. */
22
+ export declare const hasVariables: (variables?: ContentVariables) => variables is ContentVariables;
23
+ /** `text` with every reference to a defined variable replaced by its value. */
24
+ export declare const substituteVariables: (text: string, variables?: ContentVariables) => string;
25
+ /**
26
+ * {@link substituteVariables} over a page's raw source, leaving its front
27
+ * matter as written: the rendered page reads its title and description from
28
+ * the unsubstituted front matter, so the other surfaces must too.
29
+ */
30
+ export declare const substituteVariablesInBody: (source: string, variables?: ContentVariables) => string;
31
+ /** An undefined variable referenced in prose, with its 1-based line. */
32
+ export interface UndefinedVariable {
33
+ line: number;
34
+ name: string;
35
+ }
36
+ /**
37
+ * The undefined variables `text` references outside code: fenced blocks and
38
+ * inline code spans are skipped, so a templating example never fails a
39
+ * build. Empty when the site defines no variables at all, so a page that
40
+ * shows `{{…}}` literally keeps working until the site opts in.
41
+ */
42
+ export declare const undefinedVariables: (text: string, variables?: ContentVariables) => UndefinedVariable[];
@@ -1,4 +1,5 @@
1
1
  import type { BlumeProject } from "../core/project-graph.ts";
2
+ import type { CompiledRedirect } from "../core/redirect-patterns.ts";
2
3
  import type { ResolvedConfig } from "../core/schema.ts";
3
4
  import type { BuildLog } from "./platforms/types.ts";
4
5
  /**
@@ -34,19 +35,29 @@ export declare const nodeHeaderRules: (config: ResolvedConfig) => NodeHeaderRule
34
35
  */
35
36
  export type NodeRedirects = Record<string, [string, number]>;
36
37
  /**
37
- * The configured redirects, based the way the host matches them (see
38
+ * The configured exact redirects, based the way the host matches them (see
38
39
  * `platformRedirects`) and keyed for the wrapper's lookup, the `Location`
39
40
  * percent-encoded as Astro sends it. A redirect at a content route's own path
40
41
  * is left out: the prerendered page owns that URL, and the static handler
41
- * serves it before Astro's redirect ever could.
42
+ * serves it before Astro's redirect ever could. Patterns are compiled apart
43
+ * ({@link nodePatternRedirects}).
42
44
  */
43
45
  export declare const nodeRedirects: (project: BlumeProject) => NodeRedirects;
46
+ /**
47
+ * The configured pattern redirects (`/beta/:slug*`), based the way the host
48
+ * matches them and compiled for the wrapper, which tries them in order after
49
+ * the exact ones. None can match a page: the scan rejects a pattern that
50
+ * does (`BLUME_REDIRECT_MATCHES_PAGE`).
51
+ */
52
+ export declare const nodePatternRedirects: (project: BlumeProject) => CompiledRedirect[];
44
53
  /** What the wrapper needs beyond the header rules. */
45
54
  export interface NodeEntryOptions {
46
55
  /** `deployment.base`, normalized (`""` at the root). */
47
56
  base?: string;
48
57
  /** The configured redirects, from {@link nodeRedirects}. */
49
58
  redirects?: NodeRedirects;
59
+ /** The configured pattern redirects, from {@link nodePatternRedirects}. */
60
+ patternRedirects?: CompiledRedirect[];
50
61
  }
51
62
  /**
52
63
  * The entry that replaces Astro's: it answers a configured redirect with its
@@ -28,6 +28,11 @@ export declare const emitCloudflareDeployConfig: (context: ProjectContext) => Pr
28
28
  * built config instead, and is left alone.
29
29
  */
30
30
  export declare const nameCloudflareWorker: (project: BlumeProject, log: BuildLog) => Promise<void>;
31
+ /**
32
+ * Declare the Workers rate limiting binding `rateLimit: cloudflare()` counts
33
+ * with in the built Worker's config, which `wrangler deploy` reads.
34
+ */
35
+ export declare const bindCloudflareRateLimit: (project: BlumeProject, log: BuildLog) => Promise<void>;
31
36
  /**
32
37
  * Cloudflare Workers and Pages. A server build emits the Worker into
33
38
  * `dist/server` and serves `dist/client` through the ASSETS binding, which
@@ -26,6 +26,13 @@ export declare const NETLIFY_CONFIG_FILE: string;
26
26
  * as static files, so the prerendered endpoint's own headers never ship.
27
27
  */
28
28
  export declare const emitNetlifyHeaders: (project: BlumeProject, log: BuildLog) => Promise<void>;
29
+ /**
30
+ * Carry the pattern redirects (`/beta/:slug*`) into a server build, as
31
+ * `redirects` in the Frameworks API config: Astro's `redirects` carry only
32
+ * the exact ones, since it can't prerender a pattern's pages, so the adapter
33
+ * never writes these. Netlify appends them after any rules of the user's own.
34
+ */
35
+ export declare const emitNetlifyPatternRedirects: (project: BlumeProject) => Promise<void>;
29
36
  /**
30
37
  * Netlify. A server build runs on Netlify Functions from the Frameworks API
31
38
  * tree the adapter writes to `.netlify/v1`, relative to the Astro root —
@@ -20,6 +20,12 @@ export declare const checkVercelFunctionBundles: (outputDir: string, root: strin
20
20
  * root it was shown.
21
21
  */
22
22
  export declare const emitVercelNegotiation: (project: BlumeProject, log: BuildLog) => Promise<void>;
23
+ /**
24
+ * Route the pattern redirects (`/beta/:slug*`) in the adapter's Build Output
25
+ * config: Astro's `redirects` carry only the exact ones, since it can't
26
+ * prerender a pattern's pages, so the adapter never sees these.
27
+ */
28
+ export declare const emitVercelPatternRedirects: (project: BlumeProject, log: BuildLog) => Promise<void>;
23
29
  /**
24
30
  * Vercel. A server build's Build Output tree lands at `.vercel/output` — at
25
31
  * the project root, because the adapter is handed that root up front: its
@@ -2,12 +2,16 @@ import type { RouteSet } from "../core/locale-links.ts";
2
2
  import type { BlumeProject } from "../core/project-graph.ts";
3
3
  import type { ResolvedConfig } from "../core/schema.ts";
4
4
  import type { VercelHeader } from "./headers.ts";
5
+ import type { VercelRoute } from "./vercel-negotiation.ts";
5
6
  /**
6
7
  * Platform redirect files for a static build. Astro already emits redirect HTML
7
8
  * (meta-refresh) pages for static output, but that's a soft client redirect.
8
9
  * These give the host a real HTTP 3xx: Netlify/Cloudflare read `_redirects`,
9
10
  * Vercel reads `vercel.json`, and `blume-redirects.json` is a structured
10
- * manifest for anything else (Apache/nginx rules, an edge worker).
11
+ * manifest for anything else (Apache/nginx rules, an edge worker). A pattern
12
+ * redirect (`/beta/:slug*`) gets no redirect page, since Astro can't
13
+ * prerender one for paths it doesn't know; each host file carries it in that
14
+ * host's syntax (see `core/redirect-patterns.ts`).
11
15
  */
12
16
  type Redirect = ResolvedConfig["redirects"][number];
13
17
  /**
@@ -39,19 +43,22 @@ export declare const applyBaseToAstroRedirects: (redirects: Redirect[], basePath
39
43
  export declare const applyBaseToPlatformRedirects: (redirects: Redirect[], basePath: string, deployBase: string, routes: RouteSet) => Redirect[];
40
44
  /**
41
45
  * The configured redirects as the host platform matches them, via
42
- * {@link applyBaseToPlatformRedirects}. The one basing every consumer must
43
- * share: the emitted redirect files and the Cloudflare worker-first redirect
44
- * exemptions both compare these paths against real served URLs.
46
+ * {@link applyBaseToPlatformRedirects}, exact paths ahead of patterns: hosts
47
+ * try rules in order, and an exact redirect wins over a pattern that also
48
+ * covers its path. The one basing every consumer must share: the emitted
49
+ * redirect files and the server wrappers all compare these paths against
50
+ * real served URLs.
45
51
  */
46
52
  export declare const platformRedirects: (project: {
47
53
  config: ResolvedConfig;
48
54
  manifest: Pick<BlumeProject["manifest"], "routes">;
49
55
  }) => Redirect[];
50
56
  /**
51
- * `_redirects` text (Netlify + Cloudflare Pages): `from to status` per line.
52
- * `force` appends Netlify's `!` to each status (`301!`), so the rule wins over
53
- * the redirect page Astro writes at `from`; Cloudflare, which always applies
54
- * its rules first, rejects a line carrying it.
57
+ * `_redirects` text (Netlify + Cloudflare Pages): `from to status` per line,
58
+ * a pattern as `:placeholder`s and a `*` splat the destination reads as
59
+ * `:splat`. `force` appends Netlify's `!` to each status (`301!`), so the rule
60
+ * wins over the redirect page Astro writes at `from`; Cloudflare, which always
61
+ * applies its rules first, rejects a line carrying it.
55
62
  */
56
63
  export declare const buildNetlifyRedirects: (redirects: Redirect[], force?: boolean) => string;
57
64
  /**
@@ -60,10 +67,31 @@ export declare const buildNetlifyRedirects: (redirects: Redirect[], force?: bool
60
67
  * alternative to the boolean `permanent`) so the configured code ships exactly:
61
68
  * `permanent` would silently coerce a 301 to 308 and a 302 to 307, diverging
62
69
  * from the `_redirects` file, which preserves exact codes. A `source` is a
63
- * `path-to-regexp` pattern, so each exact `from` path is escaped: unescaped,
64
- * `/c++-guide` fails the whole config and `/faq(old)` never matches.
70
+ * `path-to-regexp` pattern, so each literal run of a `from` path is escaped:
71
+ * unescaped, `/c++-guide` fails the whole config and `/faq(old)` never
72
+ * matches. A pattern's captures are `path-to-regexp` params.
65
73
  */
66
74
  export declare const buildVercelConfig: (redirects: Redirect[], headers?: readonly VercelHeader[]) => string;
67
- /** Structured manifest for hosts that need manual wiring. */
75
+ /**
76
+ * The pattern redirects as `_redirects` entries, for the `redirects` of a
77
+ * Netlify server build's Frameworks API config (see
78
+ * {@link buildNetlifyRedirects} for the syntax).
79
+ */
80
+ export declare const netlifyPatternRedirects: (redirects: Redirect[]) => {
81
+ from: string;
82
+ status: number;
83
+ to: string;
84
+ }[];
85
+ /**
86
+ * The pattern redirects as Build Output API routes, for a Vercel server
87
+ * build: the adapter routes only the exact redirects Astro's config carries.
88
+ * Each matches the served path, a trailing slash optional, and fills its
89
+ * `Location` from numbered captures, as the adapter's own redirect routes do.
90
+ */
91
+ export declare const vercelPatternRoutes: (redirects: Redirect[]) => VercelRoute[];
92
+ /**
93
+ * Structured manifest for hosts that need manual wiring. A pattern stays as
94
+ * configured (`/beta/:slug*`), for the rule it becomes to be written by hand.
95
+ */
68
96
  export declare const buildRedirectManifest: (redirects: Redirect[]) => string;
69
97
  export {};
@@ -108,3 +108,12 @@ export declare const buildNegotiationRoutes: (routePaths: readonly string[], hom
108
108
  * `handle: "filesystem"` marker to anchor the splice.
109
109
  */
110
110
  export declare const injectNegotiationRoutes: (configText: string, routePaths: readonly string[], homeLinkHeader?: string | null, contentTypeOverrides?: Record<string, string>, homeTokens?: number, notFound?: NotFoundVariants, corsPaths?: readonly string[], svgAssets?: boolean) => string | null;
111
+ /**
112
+ * Splice routes for the pattern redirects (see `vercelPatternRoutes`) into a
113
+ * Build Output `config.json`, in the main phase just ahead of
114
+ * `handle: "filesystem"`: after the exact redirects the adapter puts first,
115
+ * so an exact path still wins. A second pass replaces its own routes. Returns
116
+ * the updated JSON text, or `null` when there is nowhere safe to splice: an
117
+ * unparsable config, no `routes` array, or no `handle: "filesystem"` marker.
118
+ */
119
+ export declare const injectRedirectRoutes: (configText: string, redirectRoutes: readonly VercelRoute[]) => string | null;
@@ -7,7 +7,20 @@
7
7
  * language label.
8
8
  * - the `lineNumbers` keyword (```ts file.ts lineNumbers) becomes
9
9
  * `data-line-numbers`; the theme renders a counter-driven line-number gutter.
10
+ * - the `wrap` keyword becomes `data-wrap`: this block's long lines wrap
11
+ * instead of scrolling, as `markdown.code.wrap` does for every block.
12
+ * - the `expandable` keyword becomes `data-expandable` on a block of
13
+ * {@link EXPANDABLE_MIN_LINES} lines or more: the theme shows its first
14
+ * {@link EXPANDABLE_VISIBLE_LINES} lines, and the page script adds a toggle
15
+ * that shows the rest in full. A shorter block renders as it is.
10
16
  */
17
+ /** The lines a collapsed `expandable` block shows. */
18
+ export declare const EXPANDABLE_VISIBLE_LINES = 10;
19
+ /**
20
+ * The lines a block needs before `expandable` collapses it: a few more than it
21
+ * shows, so the toggle never hides a line or two behind a click.
22
+ */
23
+ export declare const EXPANDABLE_MIN_LINES = 16;
11
24
  /** The slice of Shiki's transformer `this` context Blume reads. */
12
25
  interface CodeMetaContext {
13
26
  options: {
@@ -15,6 +28,8 @@ interface CodeMetaContext {
15
28
  __raw?: string;
16
29
  };
17
30
  };
31
+ /** The block's code, as highlighted. */
32
+ source?: string;
18
33
  }
19
34
  /** The `<pre>` hast node a Shiki `pre` hook receives. */
20
35
  interface PreNode {
@@ -27,6 +42,8 @@ export interface CodeTitleTransformer {
27
42
  }
28
43
  /** The title a fence's meta string promotes to `data-title`, if any. */
29
44
  export declare const parseCodeTitle: (raw: string | undefined) => string | undefined;
45
+ /** How many lines a block's code runs to, a trailing newline aside. */
46
+ export declare const lineCount: (source?: string) => number;
30
47
  /** Build the transformer. Runs after Shiki's built-in `data-language` hook. */
31
48
  export declare const codeTitleTransformer: () => CodeTitleTransformer;
32
49
  export {};
@@ -8,8 +8,9 @@ export declare const MARKDOWN_FEATURES: {
8
8
  };
9
9
  /**
10
10
  * The `.mdx` feature set: Markdown's plus `:::` directives (→ `<Callout>`) and
11
- * block-only math — `singleDollarTextMath: false` keeps a bare `$` (currency,
12
- * shell, code) as literal text and only parses `$$…$$`.
11
+ * math — `singleDollarTextMath: false` keeps a bare `$` (currency, shell,
12
+ * code) as literal text and only parses `$$…$$`, as a block on its own lines
13
+ * or inline within a sentence.
13
14
  */
14
15
  export declare const MDX_FEATURES: {
15
16
  directive: true;
@@ -0,0 +1,70 @@
1
+ import { HTMLElement } from "node-html-parser";
2
+ import type { Node } from "node-html-parser";
3
+ import type { BlumeProject } from "../core/project-graph.ts";
4
+ import type { ProjectContext } from "../core/types.ts";
5
+ import type { NarrationProvider } from "./provider.ts";
6
+ import type { NarrationCues, NarrationTree } from "./script.ts";
7
+ /**
8
+ * Generated narration: after Astro writes the HTML, read every page that
9
+ * carries the player exactly as the browser will (same walker, same blocks),
10
+ * split it into sentences, and give each sentence a clip from the configured
11
+ * speech model. Clips are cached by what decides their sound (text, language,
12
+ * model, voice, instructions, provider options), so a rebuild only pays for
13
+ * sentences that changed, and one sentence shared by many pages is generated
14
+ * once. Each page gets a manifest listing its clips; the player plays them in
15
+ * order and falls back to browser voices wherever a manifest is missing.
16
+ */
17
+ /** How the build logs: the integration's Astro logger. */
18
+ export interface NarrationLogger {
19
+ info: (message: string) => void;
20
+ warn: (message: string) => void;
21
+ }
22
+ /** Speak `text` in `lang`, returning MP3 bytes. */
23
+ export type Speak = (text: string, lang: string) => Promise<Uint8Array>;
24
+ /** What a narration build did, for the log line and tests. */
25
+ export interface NarrationBuildResult {
26
+ /** Clips that failed to generate; their pages get no manifest. */
27
+ failed: number;
28
+ /** Clips generated by the speech model on this build. */
29
+ generated: number;
30
+ /** Pages that got a manifest. */
31
+ pages: number;
32
+ /** Clips read back from the cache. */
33
+ reused: number;
34
+ }
35
+ /**
36
+ * The clip cache directory: `node_modules/.cache/blume/narration`, next to the
37
+ * OG card cache and restored by the same host build caches (see `ogCacheDir`).
38
+ */
39
+ export declare const narrationCacheDir: (context: Pick<ProjectContext, "outDir" | "root">) => string;
40
+ /** The walker's view of a node-html-parser tree. */
41
+ export declare const htmlTree: NarrationTree<Node>;
42
+ /** The player's settings on a built page, and the article it reads. */
43
+ interface PlayerPage {
44
+ article: HTMLElement;
45
+ audioBase: string;
46
+ cues: NarrationCues;
47
+ lang: string;
48
+ manifest: string;
49
+ }
50
+ /**
51
+ * The generated player on a built page, or `null` when the page has none (or
52
+ * a player without generated audio, which reads with browser voices).
53
+ */
54
+ export declare const readPlayerPage: (html: string) => PlayerPage | null;
55
+ /**
56
+ * A clip's cache key: a digest of everything that decides how it sounds. The
57
+ * Blume version is deliberately left out, unlike the OG card's: an upgrade
58
+ * shouldn't pay to regenerate audio that would sound the same.
59
+ */
60
+ export declare const clipKey: (provider: NarrationProvider, lang: string, text: string) => string;
61
+ /** Speak through the Vercel AI Gateway with the provider's model and voice. */
62
+ export declare const gatewaySpeaker: (provider: NarrationProvider) => Speak;
63
+ /**
64
+ * Generate the narration for a built site in `distDir`: a clip per sentence
65
+ * and a manifest per page. Does nothing unless `narration.provider` is set,
66
+ * and warns instead of generating when the provider's key is missing (the
67
+ * pages then read with browser voices). `speak` replaces the gateway call.
68
+ */
69
+ export declare const buildNarration: (project: BlumeProject, distDir: string, logger: NarrationLogger, speak?: Speak) => Promise<NarrationBuildResult | null>;
70
+ export {};
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ /** The speech model narration uses when `gateway()` names none. */
3
+ export declare const DEFAULT_NARRATION_MODEL = "openai/tts-1-hd";
4
+ /** The voice narration uses when `gateway()` names none. */
5
+ export declare const DEFAULT_NARRATION_VOICE = "alloy";
6
+ /**
7
+ * `narration.provider`: the `gateway()` descriptor from `blume/ai`, read with
8
+ * speech defaults. `reasoning` is an assistant option and is rejected here;
9
+ * `voice` and `instructions` are narration options and are rejected by the
10
+ * assistant.
11
+ */
12
+ export declare const narrationProviderSchema: z.ZodObject<{
13
+ kind: z.ZodLiteral<"gateway">;
14
+ options: z.ZodObject<{
15
+ instructions: z.ZodOptional<z.ZodString>;
16
+ model: z.ZodDefault<z.ZodString>;
17
+ voice: z.ZodDefault<z.ZodString>;
18
+ apiKeyEnv: z.ZodDefault<z.ZodString>;
19
+ headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
20
+ providerOptions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodJSONSchema>>>;
21
+ }, z.core.$strict>;
22
+ requiredSecrets: z.ZodArray<z.ZodString>;
23
+ runtimeDeps: z.ZodArray<z.ZodString>;
24
+ }, z.core.$strict>;
25
+ /** A validated narration provider, defaults filled in. */
26
+ export type NarrationProvider = z.output<typeof narrationProviderSchema>;
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Narration's reading script: what "Listen to this page" says, in order, and
3
+ * where each spoken sentence sits in the page's text.
4
+ *
5
+ * One walker serves both sides. `blume build` runs it over the built HTML
6
+ * (parsed with node-html-parser) to generate a clip per sentence, and the
7
+ * player runs it over the live `<article>` to highlight the sentence being
8
+ * read. Both see the same markup and apply the same rules, so they agree on
9
+ * every block's text; the sentence split is only ever computed once per
10
+ * engine (by the build for generated audio, by the browser for its own
11
+ * voices), so an ICU difference between Node and the browser can't move a
12
+ * highlight.
13
+ *
14
+ * The rules follow what reads well aloud: the title, description, headings,
15
+ * and prose are read in order; callouts, steps, tabs, and collapsible
16
+ * sections are announced with a short spoken cue; code, tables, media,
17
+ * diagrams, math, API field tables, and anything marked
18
+ * `data-blume-narration="skip"` are left out.
19
+ */
20
+ /**
21
+ * The slice of a DOM-like tree the walker reads. The browser DOM and
22
+ * node-html-parser both satisfy it through a small adapter, so the walker
23
+ * never touches either API directly.
24
+ */
25
+ export interface NarrationTree<N> {
26
+ /** An element's attribute, or `null` when it is absent. */
27
+ attr: (node: N, name: string) => string | null;
28
+ children: (node: N) => readonly N[];
29
+ /** An element's lowercase tag name; `null` for text and other nodes. */
30
+ tag: (node: N) => string | null;
31
+ /** A text node's decoded text; `null` for elements and other nodes. */
32
+ text: (node: N) => string | null;
33
+ }
34
+ /**
35
+ * The spoken cues, already localized for the page. `{n}` in `step` is the
36
+ * step's number and `{title}` in `tab` is the tab's label. An empty string
37
+ * silences that cue.
38
+ */
39
+ export interface NarrationCues {
40
+ danger: string;
41
+ info: string;
42
+ note: string;
43
+ section: string;
44
+ step: string;
45
+ success: string;
46
+ tab: string;
47
+ tip: string;
48
+ warning: string;
49
+ }
50
+ /**
51
+ * A run of text read as one unit: a paragraph, heading, list item, or any
52
+ * other block. `nodes` are the text nodes it was read from; `nodeOf[i]` and
53
+ * `offsetOf[i]` locate character `i` of `text` in them, so a sentence's
54
+ * `[start, end)` maps back to a DOM range for highlighting.
55
+ */
56
+ export interface NarrationBlock<N> {
57
+ nodeOf: number[];
58
+ nodes: N[];
59
+ offsetOf: number[];
60
+ text: string;
61
+ }
62
+ /** One step of the reading order: a spoken cue, or a block of page text. */
63
+ export type NarrationItem = {
64
+ block: number;
65
+ kind: "block";
66
+ } | {
67
+ kind: "cue";
68
+ text: string;
69
+ };
70
+ /** What {@link extractNarration} reads from a page. */
71
+ export interface NarrationExtract<N> {
72
+ blocks: NarrationBlock<N>[];
73
+ items: NarrationItem[];
74
+ }
75
+ /**
76
+ * One spoken unit. A sentence carries its block and its `[start, end)` in
77
+ * that block's text; a cue carries `block: null`. `text` is what is spoken.
78
+ */
79
+ export interface NarrationSegment {
80
+ block: number | null;
81
+ end: number;
82
+ start: number;
83
+ text: string;
84
+ }
85
+ /**
86
+ * The per-page manifest `blume build` writes for generated narration. The
87
+ * player aligns `blocks` (the build's block texts) with the live page by
88
+ * text, then plays one clip per segment. A sentence names its block and range;
89
+ * a cue carries its spoken `text` instead.
90
+ */
91
+ export interface NarrationManifest {
92
+ blocks: string[];
93
+ segments: NarrationManifestSegment[];
94
+ version: 1;
95
+ }
96
+ /** One clip of a {@link NarrationManifest}: a sentence or a cue. */
97
+ export type NarrationManifestSegment = {
98
+ audio: string;
99
+ block: number;
100
+ end: number;
101
+ start: number;
102
+ } | {
103
+ audio: string;
104
+ text: string;
105
+ };
106
+ /**
107
+ * A page needs at least this many spoken characters (title and description
108
+ * included) to offer narration: roughly 50 English words. Shorter pages, and
109
+ * pages that are mostly code, tables, or API fields, get no player.
110
+ */
111
+ export declare const NARRATION_MIN_CHARS = 280;
112
+ /**
113
+ * Sentences longer than this are split at a clause, then a word boundary.
114
+ * Browser speech engines drop an utterance that runs past about 15 seconds,
115
+ * and shorter clips also keep the highlight moving.
116
+ */
117
+ export declare const NARRATION_MAX_SEGMENT_CHARS = 220;
118
+ /** The attribute that keeps an element (and everything in it) out of narration. */
119
+ export declare const NARRATION_SKIP_ATTRIBUTE = "data-blume-narration";
120
+ /**
121
+ * Walk `root` and return its reading order: each block of text, with the
122
+ * cues that introduce callouts, steps, tabs, and collapsible sections.
123
+ * Whitespace collapses to single spaces, as it renders.
124
+ */
125
+ export declare const extractNarration: <N>(root: N, tree: NarrationTree<N>, cues: NarrationCues) => NarrationExtract<N>;
126
+ /**
127
+ * Split an extract into spoken segments: a cue as it is, and each block into
128
+ * its sentences for `lang` (long ones broken further, see
129
+ * {@link NARRATION_MAX_SEGMENT_CHARS}).
130
+ */
131
+ export declare const segmentNarration: <N>(extract: NarrationExtract<N>, lang: string, max?: number) => NarrationSegment[];
132
+ /** How many characters the page's blocks will speak, cues excluded. */
133
+ export declare const narrationLength: <N>(extract: NarrationExtract<N>) => number;
134
+ /** Whether a page has enough prose to offer narration. */
135
+ export declare const isNarratable: <N>(extract: NarrationExtract<N>) => boolean;
136
+ /**
137
+ * Characters read per second at 1x: about 170 words a minute for
138
+ * space-separated scripts, and a slower character rate where a character is a
139
+ * word or more. Estimates only; neither engine reports durations up front.
140
+ */
141
+ export declare const narrationCharsPerSecond: (lang: string) => number;
142
+ /** The page's estimated listening time at 1x, in whole minutes (at least 1). */
143
+ export declare const narrationMinutes: (chars: number, lang: string) => number;
144
+ /**
145
+ * Map each manifest block onto the live page's blocks by exact text, in
146
+ * order, skipping page blocks the build didn't see (a script may have added
147
+ * some). A manifest block with no match maps to `-1`: its sentences still
148
+ * play, without a highlight.
149
+ */
150
+ export declare const alignBlocks: (manifestBlocks: readonly string[], pageBlocks: readonly string[]) => number[];
151
+ /** Whether a value (the player's `data-cues` JSON) is a full set of cues. */
152
+ export declare const isNarrationCues: (value: unknown) => value is NarrationCues;
153
+ /** Whether a fetched manifest has the shape the player plays. */
154
+ export declare const isNarrationManifest: (value: unknown) => value is NarrationManifest;
@@ -45,6 +45,12 @@ export interface ApiOperationRef {
45
45
  deprecated: boolean;
46
46
  /** The channel the operation acts on (AsyncAPI only). */
47
47
  channelId?: string;
48
+ /**
49
+ * An OpenAPI 3.1 webhook: a request the API sends to the reader's endpoint
50
+ * rather than one it serves. `path` then holds the webhook's name, the key
51
+ * it has under the document's `webhooks`.
52
+ */
53
+ webhook?: true;
48
54
  }
49
55
  /**
50
56
  * A tag/section: the spec's declared tags in their declared order, then any
@@ -76,8 +82,8 @@ export interface ApiSpecData {
76
82
  /** Operations keyed by {@link ApiOperationRef.key}. */
77
83
  operations: Record<string, ApiOperationRef>;
78
84
  tags: ApiTagRef[];
79
- /** Code-sample languages to render per operation. */
80
- codeSamples: string[];
85
+ /** Code-sample languages to render per operation; `false` for none. */
86
+ codeSamples: string[] | false;
81
87
  /** Whether nested schema rows start expanded. */
82
88
  expandSchemas: boolean;
83
89
  /**
@@ -162,10 +168,10 @@ export interface ExtractedOperations extends CollectedOperations {
162
168
  export declare const operationCollector: (baseRoute: string, tagMeta: ReadonlyMap<string, string>) => OperationCollector;
163
169
  /**
164
170
  * Flatten a 3.1 document into a route-mapped operation list and its ordered
165
- * tags. Operations inherit the first tag they declare; keys are de-duplicated so
166
- * a repeated `operationId` still yields distinct routes. `warnings` reports
167
- * anything skipped (a `$ref` path item, webhooks), so missing operations
168
- * aren't silent.
171
+ * tags, webhooks included. Operations inherit the first tag they declare; keys
172
+ * are de-duplicated so a repeated `operationId` still yields distinct routes.
173
+ * `warnings` reports anything skipped (a `$ref` path item), so missing
174
+ * operations aren't silent.
169
175
  */
170
176
  export declare const extractOperations: (document: ApiDocument, baseRoute: string) => ExtractedOperations;
171
177
  /** Resolve the operation object for a ref out of its (OpenAPI) document. */
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+ import type { JsonValue } from "../core/adapter.ts";
3
+ /**
4
+ * OpenAPI Overlays: the OpenAPI Initiative's format for changing an API
5
+ * description without editing it — an ordered list of actions, each an RFC
6
+ * 9535 JSONPath `target` with an `update` to merge in, a `copy` of another
7
+ * node to merge in, or `remove`. A spec generated by another tool or owned by
8
+ * another team can then carry docs-only changes (better descriptions, hidden
9
+ * internal operations, a public server URL) in a file of its own.
10
+ *
11
+ * Implements Overlay Specification 1.0 and 1.1 over `jsonpath-rfc9535`, which
12
+ * passes the JSONPath compliance suite in full, as the spec requires. The
13
+ * documents here are already parsed; `parse.ts` reads the files.
14
+ */
15
+ /** An overlay document or action that doesn't follow the spec. */
16
+ export declare class OverlayError extends Error {
17
+ constructor(message: string);
18
+ }
19
+ /** An object node, the only kind that holds named properties. */
20
+ interface JsonObject {
21
+ [key: string]: JsonValue;
22
+ }
23
+ /**
24
+ * A parsed YAML or JSON mapping, as the document an overlay acts on: the
25
+ * parser's own types say nothing of JSON, but what it parses is JSON.
26
+ */
27
+ export declare const isJsonObject: <Value>(value: Value) => value is Value & JsonObject;
28
+ declare const overlaySchema: z.ZodObject<{
29
+ actions: z.ZodArray<z.ZodObject<{
30
+ copy: z.ZodOptional<z.ZodString>;
31
+ description: z.ZodOptional<z.ZodString>;
32
+ remove: z.ZodDefault<z.ZodBoolean>;
33
+ target: z.ZodString;
34
+ update: z.ZodOptional<z.ZodJSONSchema>;
35
+ }, z.core.$loose>>;
36
+ extends: z.ZodOptional<z.ZodString>;
37
+ info: z.ZodObject<{
38
+ title: z.ZodString;
39
+ version: z.ZodString;
40
+ }, z.core.$loose>;
41
+ overlay: z.ZodString;
42
+ }, z.core.$loose>;
43
+ /** A validated overlay document. */
44
+ export type OverlayDocument = z.output<typeof overlaySchema>;
45
+ /** Validate a parsed overlay document, naming the file in any error. */
46
+ export declare const overlayDocument: <Value>(value: Value, name: string) => OverlayDocument;
47
+ /**
48
+ * Apply an overlay to a parsed document, in place and in action order: each
49
+ * action sees the result of the one before. A target that matches nothing
50
+ * changes nothing. Throws an {@link OverlayError} naming the overlay file and
51
+ * the action that failed.
52
+ */
53
+ export declare const applyOverlay: (document: JsonValue, overlay: OverlayDocument, name: string) => void;
54
+ export {};