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
@@ -0,0 +1,70 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ import type { JsonValue } from "../core/adapter.ts";
4
+ import { isJsonObject } from "../core/sources/json.ts";
5
+ import { RATE_LIMIT_BINDING } from "./cloudflare.ts";
6
+ import type { CloudflareRateLimitAdapter } from "./cloudflare.ts";
7
+
8
+ /** The Workers rate limiting binding, as the Worker's config declares it. */
9
+ export interface RateLimitBindingConfig {
10
+ name: string;
11
+ namespace_id: string;
12
+ simple: { limit: number; period: 10 | 60 };
13
+ }
14
+
15
+ /**
16
+ * A namespace id for a Worker that sets none: a positive integer derived from
17
+ * its name, so two Blume sites on one account don't share one.
18
+ */
19
+ export const rateLimitNamespace = (workerName: string): string => {
20
+ const digest = createHash("sha256").update(workerName).digest("hex");
21
+ return String((Number.parseInt(digest.slice(0, 8), 16) % 2_000_000_000) + 1);
22
+ };
23
+
24
+ const isText = <Value>(value: Value): value is Value & string =>
25
+ typeof value === "string";
26
+
27
+ /** The binding `cloudflare()` asks for, on the Worker named `workerName`. */
28
+ export const rateLimitBinding = (
29
+ adapter: CloudflareRateLimitAdapter,
30
+ workerName: string
31
+ ): RateLimitBindingConfig => ({
32
+ name: RATE_LIMIT_BINDING,
33
+ namespace_id: adapter.options.namespaceId ?? rateLimitNamespace(workerName),
34
+ simple: {
35
+ limit: adapter.options.requests ?? 10,
36
+ period: adapter.options.window ?? 60,
37
+ },
38
+ });
39
+
40
+ /**
41
+ * The built Worker's config (`dist/server/wrangler.json`) with Blume's rate
42
+ * limiting binding in `ratelimits`, replacing an earlier one of the same name
43
+ * and keeping any others. `null` when the config isn't a JSON object.
44
+ */
45
+ export const withRateLimitBinding = (
46
+ wranglerText: string,
47
+ adapter: CloudflareRateLimitAdapter
48
+ ): string | null => {
49
+ let config: JsonValue;
50
+ try {
51
+ config = JSON.parse(wranglerText);
52
+ } catch {
53
+ return null;
54
+ }
55
+ if (!isJsonObject(config) || Array.isArray(config)) {
56
+ return null;
57
+ }
58
+ const { name, ratelimits } = config;
59
+ const others = Array.isArray(ratelimits)
60
+ ? ratelimits.filter(
61
+ (entry) => !(isJsonObject(entry) && entry.name === RATE_LIMIT_BINDING)
62
+ )
63
+ : [];
64
+ const binding = rateLimitBinding(adapter, isText(name) ? name : "");
65
+ config.ratelimits = [
66
+ ...others,
67
+ { ...binding, simple: { ...binding.simple } },
68
+ ];
69
+ return JSON.stringify(config);
70
+ };
@@ -16,9 +16,9 @@ import type { PlaygroundOptions, ReferenceSourceOptions } from "./options.ts";
16
16
  export interface AsyncApiOptions {
17
17
  /**
18
18
  * Code-sample tools shown per operation (Blume renderer). Defaults to every
19
- * tool appropriate to the operation's protocol binding.
19
+ * tool appropriate to the operation's protocol binding; `false` shows none.
20
20
  */
21
- codeSamples?: string[];
21
+ codeSamples?: string[] | false;
22
22
  /** Start nested schema rows expanded rather than collapsed (Blume renderer). Defaults to `false`. */
23
23
  expandSchemas?: boolean;
24
24
  /**
@@ -3,18 +3,33 @@ import { z } from "zod";
3
3
  import type { AdapterDescriptor } from "../core/adapter.ts";
4
4
  import { adapterDescriptorSchema } from "../core/adapter.ts";
5
5
  import {
6
+ graphqlAuthSchema,
6
7
  graphqlSourceSchema,
7
8
  liftSpec,
8
9
  hasSources,
9
10
  missingSourcesIssue,
10
11
  sharedOptions,
11
12
  } from "./options.ts";
12
- import type { GraphqlSourceOptions, PlaygroundOptions } from "./options.ts";
13
+ import type {
14
+ GraphqlAuthOptions,
15
+ GraphqlSourceOptions,
16
+ PlaygroundOptions,
17
+ } from "./options.ts";
13
18
 
14
19
  /** Options for {@link graphql}. */
15
20
  export interface GraphqlOptions {
16
- /** Code-sample languages shown per operation. Defaults to `["curl", "js", "python"]`. */
17
- codeSamples?: string[];
21
+ /**
22
+ * How the endpoint authenticates, like the site's `api.auth`: `bearer`,
23
+ * `basic`, or `key` (sent in the `name` header, `x-api-key` by default).
24
+ * The Try it panel gets a field for the credential and the code samples
25
+ * send a placeholder. Applies to every source; a per-source `auth` wins.
26
+ */
27
+ auth?: GraphqlAuthOptions;
28
+ /**
29
+ * Code-sample languages shown per operation, in order. Defaults to
30
+ * `["curl", "js", "python"]`; `false` shows none.
31
+ */
32
+ codeSamples?: string[] | false;
18
33
  /**
19
34
  * URL of the live GraphQL endpoint the playground and code samples target —
20
35
  * a schema, unlike an OpenAPI document, names no server. Applies to every
@@ -49,6 +64,8 @@ export const graphqlOptionsSchema = z
49
64
  codeSamples: ["curl", "js", "python"],
50
65
  route: "/graphql",
51
66
  }),
67
+ /** Default endpoint auth for every source (per-source `auth` wins). */
68
+ auth: graphqlAuthSchema.optional(),
52
69
  /** Default live endpoint URL for every source (per-source `endpoint` wins). */
53
70
  endpoint: z.string().optional(),
54
71
  /** One or more schemas; each renders on its own route by default. */
@@ -27,6 +27,7 @@ export type { GraphqlAdapter, GraphqlOptions } from "./graphql.ts";
27
27
  export { openapi } from "./openapi.ts";
28
28
  export type { OpenApiAdapter, OpenApiOptions } from "./openapi.ts";
29
29
  export type {
30
+ GraphqlAuthOptions,
30
31
  GraphqlSourceOptions,
31
32
  PlaygroundOptions,
32
33
  ReferenceSourceOptions,
@@ -4,18 +4,24 @@ import type { AdapterDescriptor } from "../core/adapter.ts";
4
4
  import { adapterDescriptorSchema } from "../core/adapter.ts";
5
5
  import {
6
6
  liftSpec,
7
- referenceSourceSchema,
7
+ openapiSourceSchema,
8
+ overlaysHaveSpec,
9
+ overlaysNeedSpecIssue,
8
10
  hasSources,
9
11
  missingSourcesIssue,
10
12
  rendererRemovedHint,
11
13
  sharedOptions,
12
14
  } from "./options.ts";
13
- import type { PlaygroundOptions, ReferenceSourceOptions } from "./options.ts";
15
+ import type { OpenApiSourceOptions, PlaygroundOptions } from "./options.ts";
14
16
 
15
17
  /** Options for {@link openapi}. */
16
18
  export interface OpenApiOptions {
17
- /** Code-sample languages shown per operation (Blume renderer). Defaults to `["curl", "js", "python"]`. */
18
- codeSamples?: string[];
19
+ /**
20
+ * Code-sample languages generated per operation (Blume renderer), in
21
+ * order. Defaults to `["curl", "js", "python"]`; `false` (or an empty list)
22
+ * generates none, so only the spec's own `x-codeSamples` show.
23
+ */
24
+ codeSamples?: string[] | false;
19
25
  /** Start nested schema rows expanded rather than collapsed (Blume renderer). Defaults to `false`. */
20
26
  expandSchemas?: boolean;
21
27
  /**
@@ -26,10 +32,15 @@ export interface OpenApiOptions {
26
32
  * `vercel()` in `deployment`).
27
33
  */
28
34
  playground?: PlaygroundOptions;
35
+ /**
36
+ * OpenAPI Overlay documents for `spec`, applied in order before it renders.
37
+ * With `sources`, each source takes its own `overlays`.
38
+ */
39
+ overlays?: string[];
29
40
  /** Where the reference mounts. Defaults to `/reference`. */
30
41
  route?: string;
31
42
  /** One or more specs; each renders on its own route by default. */
32
- sources?: ReferenceSourceOptions[];
43
+ sources?: OpenApiSourceOptions[];
33
44
  /** Shorthand for a single source: `sources: [{ spec }]`. */
34
45
  spec?: string;
35
46
  }
@@ -43,12 +54,15 @@ export const openapiOptionsSchema = z
43
54
  }),
44
55
  /** Start nested schema rows expanded rather than collapsed (Blume renderer). */
45
56
  expandSchemas: z.boolean().default(false),
57
+ /** Overlays for the `spec` shorthand. */
58
+ overlays: z.array(z.string()).optional(),
46
59
  /** One or more specs; each renders on its own route by default. */
47
- sources: z.array(referenceSourceSchema).default([]),
60
+ sources: z.array(openapiSourceSchema).default([]),
48
61
  },
49
62
  rendererRemovedHint
50
63
  )
51
- .transform(liftSpec(referenceSourceSchema))
64
+ .refine(overlaysHaveSpec, overlaysNeedSpecIssue)
65
+ .transform(liftSpec(openapiSourceSchema))
52
66
  .refine(hasSources, missingSourcesIssue("openapi"));
53
67
 
54
68
  /** `openapi()` options with every default applied and `spec` folded into `sources`. */
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
2
 
3
+ import { AUTH_METHODS } from "../components/content/api-page.ts";
4
+ import type { AuthMethod } from "../components/content/api-page.ts";
3
5
  import { unrecognizedKeysMessage } from "../core/unrecognized-keys.ts";
4
6
 
5
7
  /**
@@ -65,18 +67,78 @@ export interface ReferenceSourceOptions {
65
67
  /** A spec source with every default applied. */
66
68
  export type ResolvedReferenceSource = z.output<typeof referenceSourceSchema>;
67
69
 
70
+ /**
71
+ * [OpenAPI Overlay](https://spec.openapis.org/overlay/latest.html) documents
72
+ * (local paths or `http(s)` URLs) applied in order to an OpenAPI spec before
73
+ * it renders: changes to a spec you don't edit by hand.
74
+ */
75
+ export const overlaysSchema = z.array(z.string()).default([]);
76
+
77
+ /** Whether adapter-level `overlays` has the `spec` it belongs to. */
78
+ export const overlaysHaveSpec = (options: {
79
+ overlays?: string[];
80
+ spec?: string;
81
+ }): boolean => !options.overlays || options.spec !== undefined;
82
+
83
+ /** The refinement issue for `overlays` set beside `sources` instead of `spec`. */
84
+ export const overlaysNeedSpecIssue = {
85
+ message:
86
+ "`overlays` belongs to the `spec` shorthand; with `sources`, give each source its own `overlays`.",
87
+ path: ["overlays"],
88
+ };
89
+
90
+ /** An OpenAPI spec source: the shared shape plus its `overlays`. */
91
+ export const openapiSourceSchema = referenceSourceSchema.extend({
92
+ overlays: overlaysSchema,
93
+ });
94
+
95
+ /** One OpenAPI spec source, as `openapi()` accepts it. */
96
+ export interface OpenApiSourceOptions extends ReferenceSourceOptions {
97
+ /**
98
+ * OpenAPI Overlay documents (local paths or `http(s)` URLs) applied in
99
+ * order to the spec before it renders.
100
+ */
101
+ overlays?: string[];
102
+ }
103
+
104
+ /**
105
+ * How a GraphQL endpoint authenticates, in the shape the site's `api.auth`
106
+ * takes for hand-written endpoints: `bearer`, `basic`, or `key` (sent in the
107
+ * `name` header, `x-api-key` by default). A schema, unlike an OpenAPI
108
+ * document, declares no security schemes, so this is what gives the Try it
109
+ * panel its credential field.
110
+ */
111
+ export const graphqlAuthSchema = z.strictObject({
112
+ method: z.enum(AUTH_METHODS),
113
+ /** The header an API key goes in. Defaults to `x-api-key`. */
114
+ name: z.string().optional(),
115
+ });
116
+
117
+ /** The `auth` option of `graphql()` and its sources. */
118
+ export interface GraphqlAuthOptions {
119
+ /** `bearer`, `basic`, `key`, or `none`. */
120
+ method: AuthMethod;
121
+ /** The header an API key goes in. Defaults to `x-api-key`. */
122
+ name?: string;
123
+ }
124
+
68
125
  /**
69
126
  * A single GraphQL schema: the shared source shape plus `endpoint`, the live
70
127
  * GraphQL API URL the playground and code samples target (a schema, unlike an
71
- * OpenAPI document, names no server).
128
+ * OpenAPI document, names no server), and `auth`, how that endpoint
129
+ * authenticates.
72
130
  */
73
131
  export const graphqlSourceSchema = referenceSourceSchema.extend({
132
+ /** How the endpoint authenticates (playground + code samples). */
133
+ auth: graphqlAuthSchema.optional(),
74
134
  /** URL of the live GraphQL endpoint (playground + code samples). */
75
135
  endpoint: z.string().optional(),
76
136
  });
77
137
 
78
138
  /** One schema source, as `graphql()` accepts it. */
79
139
  export interface GraphqlSourceOptions extends ReferenceSourceOptions {
140
+ /** How the endpoint authenticates; wins over the adapter's `auth`. */
141
+ auth?: GraphqlAuthOptions;
80
142
  /** URL of the live GraphQL endpoint (playground + code samples); wins over the adapter's `endpoint`. */
81
143
  endpoint?: string;
82
144
  }
@@ -157,8 +219,13 @@ export const sharedOptions = (defaults: {
157
219
  codeSamples: string[];
158
220
  route: string;
159
221
  }) => ({
160
- /** Code-sample languages/tools shown per operation (Blume renderer). */
161
- codeSamples: z.array(z.string()).default(defaults.codeSamples),
222
+ /**
223
+ * Code-sample languages/tools shown per operation (Blume renderer), or
224
+ * `false` for none: only the spec's own `x-codeSamples` then.
225
+ */
226
+ codeSamples: z
227
+ .union([z.literal(false), z.array(z.string())])
228
+ .default(defaults.codeSamples),
162
229
  /** The "Try it" panel; see {@link playgroundSchema}. */
163
230
  playground: playgroundSchema,
164
231
  /** Where the reference mounts. */
@@ -168,8 +235,9 @@ export const sharedOptions = (defaults: {
168
235
  });
169
236
 
170
237
  /**
171
- * Resolve the `spec` shorthand into `sources` so downstream code reads one
172
- * field: the shorthand becomes the first source (with the source defaults
238
+ * Resolve the `spec` shorthand (and, on OpenAPI kinds, the `overlays` beside
239
+ * it) into `sources` so downstream code reads one field: the shorthand becomes
240
+ * the first source (with the source defaults
173
241
  * applied through the source schema itself, so the two can never drift) and
174
242
  * the `spec` key is dropped. An adapter with neither renders nothing, which
175
243
  * is a config mistake rather than a choice — `refine` it away with
@@ -179,15 +247,19 @@ export const liftSpec =
179
247
  <Source extends { spec: string }>(
180
248
  sourceSchema: z.ZodType<Source, { spec: string }>
181
249
  ) =>
182
- <Options extends { sources: Source[]; spec?: string }>({
250
+ <Options extends { sources: Source[]; spec?: string; overlays?: string[] }>({
251
+ overlays,
183
252
  spec,
184
253
  ...options
185
- }: Options): Omit<Options, "spec"> => ({
254
+ }: Options): Omit<Options, "spec" | "overlays"> => ({
186
255
  ...options,
187
256
  sources:
188
257
  spec === undefined
189
258
  ? options.sources
190
- : [sourceSchema.parse({ spec }), ...options.sources],
259
+ : [
260
+ sourceSchema.parse(overlays ? { overlays, spec } : { spec }),
261
+ ...options.sources,
262
+ ],
191
263
  });
192
264
 
193
265
  /** Whether an adapter has anything to render; pairs with {@link missingSourcesIssue}. */
@@ -2,7 +2,13 @@ import { z } from "zod";
2
2
 
3
3
  import type { AdapterDescriptor, JsonValue } from "../core/adapter.ts";
4
4
  import { adapterDescriptorSchema } from "../core/adapter.ts";
5
- import { hasSources, missingSourcesIssue } from "./options.ts";
5
+ import {
6
+ hasSources,
7
+ missingSourcesIssue,
8
+ overlaysHaveSpec,
9
+ overlaysNeedSpecIssue,
10
+ overlaysSchema,
11
+ } from "./options.ts";
6
12
 
7
13
  /**
8
14
  * What the generated Scalar page imports. Declared on every `scalar()`
@@ -22,6 +28,11 @@ export const scalarSourceSchema = z.strictObject({
22
28
  label: z.string().optional(),
23
29
  /** Emit noindex metadata and omit the page from the sitemap. */
24
30
  noindex: z.boolean().default(false),
31
+ /**
32
+ * OpenAPI Overlay documents applied in order to the document before it's
33
+ * embedded (inlined, so a remote spec with overlays is fetched at build).
34
+ */
35
+ overlays: overlaysSchema,
25
36
  /** Per-source route; defaults to the adapter's `route` (or a derived path). */
26
37
  route: z.string().optional(),
27
38
  /** Local path or `http(s)` URL to the OpenAPI or AsyncAPI document. */
@@ -34,6 +45,8 @@ export interface ScalarSourceOptions {
34
45
  label?: string;
35
46
  /** Emit noindex metadata and omit the page from the sitemap. Defaults to `false`. */
36
47
  noindex?: boolean;
48
+ /** OpenAPI Overlay documents applied in order to the document before it's embedded. */
49
+ overlays?: string[];
37
50
  /** Per-source route; defaults to the adapter's `route` (or a derived path). */
38
51
  route?: string;
39
52
  /** Local path or `http(s)` URL to the OpenAPI or AsyncAPI document. */
@@ -55,6 +68,8 @@ export type ResolvedScalarOptions = {
55
68
 
56
69
  /** The options {@link scalar} maps itself. */
57
70
  export interface ScalarNamedOptions {
71
+ /** OpenAPI Overlay documents for `spec`; with `sources`, each takes its own. */
72
+ overlays?: string[];
58
73
  /** Where the reference mounts. Defaults to `/reference`. */
59
74
  route?: string;
60
75
  /** One or more documents; each renders on its own route by default. */
@@ -87,6 +102,8 @@ export type ScalarOptions = ScalarNamedOptions & {
87
102
  */
88
103
  export const scalarOptionsSchema = z
89
104
  .object({
105
+ /** Overlays for the `spec` shorthand. */
106
+ overlays: z.array(z.string()).optional(),
90
107
  /** Where the reference mounts. */
91
108
  route: z.string().default("/reference"),
92
109
  /** One or more documents; each renders on its own route by default. */
@@ -97,13 +114,21 @@ export const scalarOptionsSchema = z
97
114
  theme: z.string().optional(),
98
115
  })
99
116
  .catchall(z.json())
100
- .transform(({ spec, sources, ...options }): ResolvedScalarOptions => ({
101
- ...options,
102
- sources:
103
- spec === undefined
104
- ? sources
105
- : [scalarSourceSchema.parse({ spec }), ...sources],
106
- }))
117
+ .refine(overlaysHaveSpec, overlaysNeedSpecIssue)
118
+ .transform(
119
+ ({ overlays, spec, sources, ...options }): ResolvedScalarOptions => ({
120
+ ...options,
121
+ sources:
122
+ spec === undefined
123
+ ? sources
124
+ : [
125
+ scalarSourceSchema.parse(
126
+ overlays ? { overlays, spec } : { spec }
127
+ ),
128
+ ...sources,
129
+ ],
130
+ })
131
+ )
107
132
  .refine(hasSources, missingSourcesIssue("scalar"));
108
133
 
109
134
  export type ScalarAdapter = AdapterDescriptor<"scalar", ScalarOptions>;
@@ -63,6 +63,7 @@ import {
63
63
  rssEndpointTemplate,
64
64
  runtimeDependencies,
65
65
  runtimeTsconfigTemplate,
66
+ consentClientTemplate,
66
67
  searchClientTemplate,
67
68
  searchEndpointTemplate,
68
69
  staticJsonEndpointTemplate,
@@ -87,6 +88,7 @@ import {
87
88
  import { buildReferenceFiles } from "../openapi/scalar.ts";
88
89
  import { isOpenApiSource } from "../openapi/source.ts";
89
90
  import { buildSearchDocuments } from "../search/documents.ts";
91
+ import { sourcePages } from "../search/source-pages.ts";
90
92
  import {
91
93
  examplesEntryTemplate,
92
94
  tailwindEntryTemplate,
@@ -162,9 +164,12 @@ const askFiles = async (
162
164
  const files = [
163
165
  {
164
166
  content: askEndpointTemplate(backend, {
167
+ captcha: assistant.captcha,
165
168
  cors: assistant.cors,
166
169
  instructions: assistant.instructions,
170
+ rateLimit: project.config.rateLimit,
167
171
  retrieval: assistant.retrieval,
172
+ tools: assistant.tools ?? backend.toolsByDefault,
168
173
  }),
169
174
  path: join(srcDir, "pages", "api", "ask.ts"),
170
175
  },
@@ -243,7 +248,10 @@ const playgroundProxyFiles = (
243
248
  needsPlaygroundProxy(config)
244
249
  ? [
245
250
  {
246
- content: playgroundProxyTemplate(specOrigins(openApiData)),
251
+ content: playgroundProxyTemplate(
252
+ specOrigins(openApiData),
253
+ config.rateLimit
254
+ ),
247
255
  path: join(srcDir, PLAYGROUND_PROXY_ENTRY),
248
256
  },
249
257
  ]
@@ -667,6 +675,7 @@ export const eject = async (
667
675
  content: astroConfigTemplate({
668
676
  askPath: "./src/generated/Ask.astro",
669
677
  config,
678
+ consentClientPath: "./src/generated/consent-client.ts",
670
679
  contentRoot: relContext.contentRoot,
671
680
  contentRoutes: project.manifest.routes.map((route) => route.path),
672
681
  context: relContext,
@@ -747,7 +756,7 @@ export const eject = async (
747
756
  // the package is hoisted out of the project's own node_modules.
748
757
  sources: [
749
758
  blumeSourceGlob(root, genDir),
750
- "../../**/*.{astro,mdx,ts,tsx}",
759
+ "../../**/*.{astro,jsx,mdx,ts,tsx}",
751
760
  ],
752
761
  twoslashCss: twoslashCss(),
753
762
  userTheme,
@@ -869,8 +878,9 @@ export const eject = async (
869
878
  );
870
879
  }
871
880
 
872
- // The client-feature loaders behind the `blume:features` alias, and the
873
- // provider-specific client loader behind `blume:search-client`.
881
+ // The client-feature loaders behind the `blume:features` alias, the
882
+ // provider-specific client loader behind `blume:search-client`, and the
883
+ // consent adapter's browser module behind `blume:consent-client`.
874
884
  files.push(
875
885
  {
876
886
  content: featuresTemplate(features),
@@ -879,6 +889,10 @@ export const eject = async (
879
889
  {
880
890
  content: searchClientTemplate(config),
881
891
  path: join(genDir, "search-client.ts"),
892
+ },
893
+ {
894
+ content: consentClientTemplate(config.consent),
895
+ path: join(genDir, "consent-client.ts"),
882
896
  }
883
897
  );
884
898
 
@@ -899,7 +913,11 @@ export const eject = async (
899
913
 
900
914
  if (searchAdapter.kind === "mixedbread") {
901
915
  files.push({
902
- content: mixedbreadSearchEndpointTemplate(searchAdapter.options),
916
+ content: mixedbreadSearchEndpointTemplate(
917
+ searchAdapter.options,
918
+ sourcePages(project),
919
+ config.rateLimit
920
+ ),
903
921
  path: join(srcDir, "pages", "api", "search.ts"),
904
922
  });
905
923
  }
@@ -262,6 +262,13 @@ export const registry: RegistryItem[] = [
262
262
  name: "feedback",
263
263
  slot: "Feedback",
264
264
  }),
265
+ layoutComponent({
266
+ description:
267
+ "The site footer: a row of links, social icons, the theme toggle, and the Cookie settings link.",
268
+ file: "SiteFooter.astro",
269
+ name: "footer",
270
+ slot: "Footer",
271
+ }),
265
272
  ...CONTENT_COMPONENTS.map(contentComponent),
266
273
  ];
267
274
 
@@ -0,0 +1,30 @@
1
+ import type { SearchAdapterKind } from "./registry.ts";
2
+
3
+ /**
4
+ * Whether each adapter's client can limit results to one language. The
5
+ * source-built indexes (Orama, FlexSearch) store every document's `locale`,
6
+ * the Algolia, Orama Cloud, and Typesense syncs upload it for their clients
7
+ * to filter on, and Pagefind keeps an index per language, merging the others
8
+ * in to search them all. The Mixedbread endpoint takes no filter, so it
9
+ * always searches every language. Keyed by every kind so a new adapter has
10
+ * to decide.
11
+ */
12
+ const SCOPES_LOCALES = {
13
+ algolia: true,
14
+ flexsearch: true,
15
+ mixedbread: false,
16
+ none: false,
17
+ orama: true,
18
+ "orama-cloud": true,
19
+ pagefind: true,
20
+ typesense: true,
21
+ } satisfies Record<SearchAdapterKind, boolean>;
22
+
23
+ /**
24
+ * Whether the configured search adapter scopes results to the page's
25
+ * language. The search dialog offers its "All languages" toggle only when it
26
+ * does: on the others the toggle would change nothing, and every query
27
+ * already spans all languages.
28
+ */
29
+ export const scopesLocales = (kind: SearchAdapterKind): boolean =>
30
+ SCOPES_LOCALES[kind];
@@ -6,14 +6,22 @@ import type { SearchAdapter } from "./types.ts";
6
6
  /**
7
7
  * Connection details for a self-hosted or cloud Typesense node. The browser
8
8
  * queries the collection with the search-only `apiKey`; the build-time sync
9
- * recreates the collection with `TYPESENSE_ADMIN_API_KEY`, which never enters
10
- * the config.
9
+ * rebuilds it with `TYPESENSE_ADMIN_API_KEY`, which never enters the config.
11
10
  */
12
11
  export interface TypesenseNamedOptions {
13
12
  /** The search-only API key (public — it ships to the browser). */
14
13
  apiKey: string;
14
+ /** The alias the sync points at each new collection, and searches read. */
15
15
  collection: string;
16
16
  host: string;
17
+ /**
18
+ * The language Typesense tokenizes the text fields for, as a two-letter
19
+ * code (`ja`, `zh`, `ko`, `th`, …). Typesense's default tokenizer splits on
20
+ * spaces, so text in a script written without them — Chinese, Japanese,
21
+ * Thai — only matches from the start of a run. Omitted, the fields keep
22
+ * that default.
23
+ */
24
+ locale?: string;
17
25
  /** Defaults to 443. */
18
26
  port?: number;
19
27
  /** Defaults to `https`. */
@@ -39,14 +47,16 @@ export const typesenseOptionsSchema = z
39
47
  apiKey: z.string(),
40
48
  collection: z.string(),
41
49
  host: z.string(),
50
+ locale: z.string().optional(),
42
51
  port: z.number().int().positive().optional(),
43
52
  protocol: z.enum(["http", "https"]).optional(),
44
53
  })
45
54
  .catchall(z.json());
46
55
 
47
56
  /**
48
- * Hosted search on Typesense. Each `blume build` drops and recreates the
49
- * collection so deleted or renamed pages don't linger as stale hits.
57
+ * Hosted search on Typesense. Each `blume build` imports into a new
58
+ * collection and swaps the `collection` alias onto it, so deleted or renamed
59
+ * pages don't linger as stale hits and searches never read a partial index.
50
60
  */
51
61
  export const typesense = (options: TypesenseOptions): TypesenseAdapter => ({
52
62
  kind: "typesense",
@@ -3,6 +3,11 @@ import { mkdir, writeFile } from "node:fs/promises";
3
3
  import { close, createIndex } from "pagefind";
4
4
  import { dirname, join } from "pathe";
5
5
 
6
+ /** The part of `pagefind-entry.json` that counts the index's pages. */
7
+ interface PagefindEntry {
8
+ languages: Record<string, { page_count: number }>;
9
+ }
10
+
6
11
  /**
7
12
  * Build a local Pagefind search index over the built site. Pagefind indexes
8
13
  * every rendered page except those whose `<html>` carries
@@ -23,7 +28,9 @@ import { dirname, join } from "pathe";
23
28
  * Pagefind/pagefind#1272; switch back to `writeFiles()` once a release ships
24
29
  * that fix.
25
30
  *
26
- * Returns the number of pages indexed.
31
+ * Returns the number of pages indexed: the index's own count, summed over its
32
+ * languages from `pagefind-entry.json`. `addDirectory`'s `page_count` counts
33
+ * every HTML file it read, including the ones kept out of the index.
27
34
  */
28
35
  export const buildSearchIndex = async (outDir: string): Promise<number> => {
29
36
  const { index } = await createIndex({});
@@ -34,7 +41,7 @@ export const buildSearchIndex = async (outDir: string): Promise<number> => {
34
41
  // These awaits are strictly ordered, not independent: the directory must be
35
42
  // indexed before its files are read, and the index closed only after.
36
43
  // oxlint-disable-next-line react-doctor/async-parallel
37
- const result = await index.addDirectory({ path: outDir });
44
+ await index.addDirectory({ path: outDir });
38
45
  const { files } = await index.getFiles();
39
46
  await close();
40
47
 
@@ -49,5 +56,16 @@ export const buildSearchIndex = async (outDir: string): Promise<number> => {
49
56
  files.map((file) => writeFile(join(searchDir, file.path), file.content))
50
57
  );
51
58
 
52
- return result.page_count;
59
+ // Pagefind always writes the entry file, listing no languages when nothing
60
+ // was indexed.
61
+ const entry = files.find((file) => file.path === "pagefind-entry.json");
62
+ // SAFETY: the entry file is Pagefind's JSON, which counts each language's
63
+ // pages in `page_count`.
64
+ const { languages } = JSON.parse(
65
+ new TextDecoder().decode(entry?.content)
66
+ ) as PagefindEntry;
67
+ return Object.values(languages).reduce(
68
+ (sum, language) => sum + language.page_count,
69
+ 0
70
+ );
53
71
  };