blume 2.1.0 → 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 (397) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/dist/cli/{chunk-5cg2rzgf.js → chunk-073rdvgb.js} +19 -48
  3. package/dist/cli/{chunk-5cg2rzgf.js.map → chunk-073rdvgb.js.map} +4 -5
  4. package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
  5. package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
  6. package/dist/cli/chunk-150jk7km.js +52 -0
  7. package/dist/cli/chunk-150jk7km.js.map +10 -0
  8. package/dist/cli/{chunk-rekqz4qg.js → chunk-313vnn40.js} +16 -15
  9. package/dist/cli/chunk-313vnn40.js.map +10 -0
  10. package/dist/cli/{chunk-gp84za0h.js → chunk-3v3ffbrj.js} +2 -2
  11. package/dist/cli/{chunk-9xr4dgee.js → chunk-3x6x3pph.js} +29 -16
  12. package/dist/cli/chunk-3x6x3pph.js.map +10 -0
  13. package/dist/cli/{chunk-0gz36akr.js → chunk-42t4jxdx.js} +21 -5
  14. package/dist/cli/chunk-42t4jxdx.js.map +12 -0
  15. package/dist/cli/{chunk-ta27feev.js → chunk-54ztw1nj.js} +21 -2
  16. package/dist/cli/chunk-54ztw1nj.js.map +10 -0
  17. package/dist/cli/{chunk-jnwj5kjj.js → chunk-5vjtgs6e.js} +20 -7
  18. package/dist/cli/{chunk-jnwj5kjj.js.map → chunk-5vjtgs6e.js.map} +3 -3
  19. package/dist/cli/chunk-66w9j7p6.js +322 -0
  20. package/dist/cli/chunk-66w9j7p6.js.map +14 -0
  21. package/dist/cli/{chunk-nd1821sk.js → chunk-7ppf1rva.js} +32 -18
  22. package/dist/cli/chunk-7ppf1rva.js.map +10 -0
  23. package/dist/cli/{chunk-p804f3pe.js → chunk-8y2kmjv8.js} +6 -6
  24. package/dist/cli/{chunk-2f7n4qzt.js → chunk-c1y538kd.js} +1 -1
  25. package/dist/cli/{chunk-1n228xqb.js → chunk-c887fj0s.js} +2 -2
  26. package/dist/cli/{chunk-y5h4r2y0.js → chunk-cfyg47zg.js} +15 -5
  27. package/dist/cli/chunk-cfyg47zg.js.map +10 -0
  28. package/dist/cli/{chunk-cmtcnh9f.js → chunk-dzwehpy7.js} +2 -2
  29. package/dist/cli/{chunk-h2a48yhd.js → chunk-e6atmn4h.js} +119 -15
  30. package/dist/cli/{chunk-h2a48yhd.js.map → chunk-e6atmn4h.js.map} +10 -10
  31. package/dist/cli/{chunk-5ffywsmb.js → chunk-e8xw9qkh.js} +8 -6
  32. package/dist/cli/{chunk-5ffywsmb.js.map → chunk-e8xw9qkh.js.map} +3 -3
  33. package/dist/cli/{chunk-ntv4qrt7.js → chunk-e9q7a2ak.js} +14 -14
  34. package/dist/cli/{chunk-xkz5xbtv.js → chunk-ehweg4fr.js} +2366 -1114
  35. package/dist/cli/chunk-ehweg4fr.js.map +218 -0
  36. package/dist/cli/{chunk-zf748avv.js → chunk-ep6nd0rn.js} +176 -281
  37. package/dist/cli/{chunk-zf748avv.js.map → chunk-ep6nd0rn.js.map} +11 -12
  38. package/dist/cli/{chunk-yxmk4pec.js → chunk-fdrkhpjy.js} +16 -15
  39. package/dist/cli/{chunk-yxmk4pec.js.map → chunk-fdrkhpjy.js.map} +3 -3
  40. package/dist/cli/{chunk-5wj2qwn2.js → chunk-ft9vfys6.js} +4 -4
  41. package/dist/cli/{chunk-4h8z9vv5.js → chunk-gb420vvz.js} +89 -46
  42. package/dist/cli/chunk-gb420vvz.js.map +17 -0
  43. package/dist/cli/{chunk-713mngdq.js → chunk-hebn0tpx.js} +76 -10
  44. package/dist/cli/chunk-hebn0tpx.js.map +14 -0
  45. package/dist/cli/{chunk-2n4ps1b3.js → chunk-htrwgabr.js} +40 -22
  46. package/dist/cli/chunk-htrwgabr.js.map +15 -0
  47. package/dist/cli/{chunk-zhvd6adm.js → chunk-hx3xqnk9.js} +13 -13
  48. package/dist/cli/chunk-j134vrp2.js +65 -0
  49. package/dist/cli/chunk-j134vrp2.js.map +10 -0
  50. package/dist/cli/{chunk-y4ykbark.js → chunk-kma9f6sf.js} +2 -2
  51. package/dist/cli/{chunk-py62fewh.js → chunk-mrcccgnh.js} +3 -3
  52. package/dist/cli/{chunk-2f3ndkpw.js → chunk-n0v7m8ry.js} +3 -3
  53. package/dist/cli/{chunk-43zcf4gz.js → chunk-ncj7w596.js} +522 -353
  54. package/dist/cli/chunk-ncj7w596.js.map +35 -0
  55. package/dist/cli/{chunk-9geymqns.js → chunk-nq1d20w2.js} +14 -14
  56. package/dist/cli/{chunk-g2z9x01v.js → chunk-nrns10mj.js} +3 -3
  57. package/dist/cli/{chunk-e7vvk5ya.js → chunk-sds923fa.js} +3 -3
  58. package/dist/cli/{chunk-cy5bm0j0.js → chunk-t2m5j4pr.js} +2 -2
  59. package/dist/cli/{chunk-cy5bm0j0.js.map → chunk-t2m5j4pr.js.map} +1 -1
  60. package/dist/cli/{chunk-yj17vs39.js → chunk-tdqhyxfz.js} +5 -5
  61. package/dist/cli/{chunk-q3wxxq39.js → chunk-tphac74f.js} +5 -5
  62. package/dist/cli/{chunk-6bm0xpgd.js → chunk-w1r4vase.js} +2 -2
  63. package/dist/cli/index.js +24 -19
  64. package/dist/cli/index.js.map +3 -3
  65. package/dist/types/ai/ask-context.d.ts +6 -2
  66. package/dist/types/ai/component-markdown.d.ts +2 -0
  67. package/dist/types/ai/openapi-components.d.ts +4 -1
  68. package/dist/types/astro/integration.d.ts +5 -4
  69. package/dist/types/astro/markdown-negotiation.d.ts +3 -0
  70. package/dist/types/astro/pages.d.ts +10 -0
  71. package/dist/types/cli/init/scaffold.d.ts +1 -1
  72. package/dist/types/components/content/api-field.d.ts +4 -1
  73. package/dist/types/components/content/api-page.d.ts +6 -1
  74. package/dist/types/components/openapi/code-samples.d.ts +29 -0
  75. package/dist/types/components/openapi/helpers.d.ts +22 -1
  76. package/dist/types/components/openapi/security.d.ts +10 -0
  77. package/dist/types/components/openapi/snippets.d.ts +60 -0
  78. package/dist/types/core/changelog-index.d.ts +8 -0
  79. package/dist/types/core/config-input.d.ts +30 -3
  80. package/dist/types/core/data.d.ts +4 -0
  81. package/dist/types/core/i18n-ui.d.ts +2 -0
  82. package/dist/types/core/links.d.ts +8 -0
  83. package/dist/types/core/probe.d.ts +2 -0
  84. package/dist/types/core/project-graph.d.ts +6 -0
  85. package/dist/types/core/redirect-patterns.d.ts +11 -3
  86. package/dist/types/core/schema.d.ts +119 -0
  87. package/dist/types/core/sources/cache.d.ts +3 -0
  88. package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
  89. package/dist/types/core/sources/contentful.d.ts +17 -1
  90. package/dist/types/core/sources/lexical.d.ts +5 -0
  91. package/dist/types/core/sources/normalize.d.ts +20 -1
  92. package/dist/types/core/sources/remote.d.ts +37 -10
  93. package/dist/types/core/sources/sanity.d.ts +1 -1
  94. package/dist/types/core/types.d.ts +17 -0
  95. package/dist/types/deploy/adapter-output.d.ts +2 -1
  96. package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
  97. package/dist/types/deploy/adapters/node.d.ts +58 -23
  98. package/dist/types/deploy/adapters/registry.d.ts +10 -0
  99. package/dist/types/deploy/adapters/types.d.ts +3 -2
  100. package/dist/types/deploy/platforms/cloudflare.d.ts +10 -7
  101. package/dist/types/deploy/platforms/node.d.ts +3 -1
  102. package/dist/types/deploy/platforms/types.d.ts +18 -7
  103. package/dist/types/deploy/platforms/vercel.d.ts +20 -1
  104. package/dist/types/deploy/redirects.d.ts +17 -1
  105. package/dist/types/deploy/sitemap.d.ts +2 -1
  106. package/dist/types/deploy/vercel-negotiation.d.ts +42 -21
  107. package/dist/types/openapi/checks.d.ts +27 -0
  108. package/dist/types/openapi/graphql.d.ts +6 -0
  109. package/dist/types/openapi/model.d.ts +15 -4
  110. package/dist/types/openapi/parse.d.ts +3 -0
  111. package/dist/types/openapi/references.d.ts +16 -0
  112. package/dist/types/ratelimit/index.d.ts +1 -1
  113. package/dist/types/ratelimit/schema.d.ts +8 -0
  114. package/dist/types/ratelimit/upstash.d.ts +39 -14
  115. package/dist/types/reference/graphql.d.ts +76 -1
  116. package/dist/types/reference/index.d.ts +1 -1
  117. package/dist/types/reference/openapi.d.ts +2 -2
  118. package/dist/types/reference/options.d.ts +37 -1
  119. package/dist/types/reference/schema.d.ts +84 -0
  120. package/dist/types/search/adapters/registry.d.ts +3 -0
  121. package/dist/types/search/adapters/typesense.d.ts +14 -4
  122. package/dist/types/search/build.d.ts +3 -1
  123. package/dist/types/search/orama-index.d.ts +9 -9
  124. package/dist/types/search/sync/algolia.d.ts +5 -2
  125. package/dist/types/search/sync/index.d.ts +3 -1
  126. package/dist/types/search/sync/typesense.d.ts +11 -7
  127. package/dist/types/sources/contentful.d.ts +16 -0
  128. package/dist/types/sources/github-releases.d.ts +8 -1
  129. package/dist/types/sources/payload.d.ts +2 -0
  130. package/dist/types/sources/registry.d.ts +54 -0
  131. package/dist/types/sources/shared.d.ts +3 -0
  132. package/dist/types/sources/strapi.d.ts +2 -0
  133. package/docs/01-quickstart.mdx +4 -2
  134. package/docs/02-deployment.mdx +31 -13
  135. package/docs/advanced/changelog.mdx +11 -0
  136. package/docs/advanced/skills.mdx +1 -1
  137. package/docs/cli/audit.mdx +30 -7
  138. package/docs/cli/doctor.mdx +5 -1
  139. package/docs/cli/evals.mdx +4 -4
  140. package/docs/cli/translate.mdx +1 -0
  141. package/docs/cli/validate.mdx +4 -3
  142. package/docs/configuration/analytics.mdx +1 -1
  143. package/docs/configuration/assistant.mdx +6 -2
  144. package/docs/configuration/customization.mdx +4 -2
  145. package/docs/configuration/export.mdx +5 -3
  146. package/docs/configuration/index.mdx +3 -2
  147. package/docs/configuration/rate-limiting.mdx +23 -2
  148. package/docs/configuration/search.mdx +37 -14
  149. package/docs/content/components.mdx +2 -2
  150. package/docs/content/frontmatter.mdx +5 -3
  151. package/docs/content/i18n.mdx +2 -2
  152. package/docs/content/includes.mdx +1 -1
  153. package/docs/content/navigation.mdx +4 -4
  154. package/docs/content/sources/contentful.mdx +7 -4
  155. package/docs/content/sources/custom.mdx +7 -3
  156. package/docs/content/sources/github-releases.mdx +10 -2
  157. package/docs/content/sources/index.mdx +3 -3
  158. package/docs/content/sources/notion.mdx +1 -1
  159. package/docs/content/sources/obsidian.mdx +1 -1
  160. package/docs/content/sources/payload.mdx +3 -2
  161. package/docs/content/sources/remote-mdx.mdx +4 -0
  162. package/docs/content/sources/sanity.mdx +2 -2
  163. package/docs/content/sources/strapi.mdx +3 -2
  164. package/docs/content/syntax.mdx +2 -2
  165. package/docs/discoverability/agent-discovery.mdx +1 -1
  166. package/docs/discoverability/index.mdx +1 -1
  167. package/docs/discoverability/json-api.mdx +2 -0
  168. package/docs/discoverability/llms-txt.mdx +1 -1
  169. package/docs/discoverability/markdown.mdx +3 -1
  170. package/docs/discoverability/mcp.mdx +4 -0
  171. package/docs/discoverability/sitemap-and-robots.mdx +1 -1
  172. package/docs/references/api-pages.mdx +1 -1
  173. package/docs/references/asyncapi.mdx +3 -1
  174. package/docs/references/graphql.mdx +13 -1
  175. package/docs/references/openapi.mdx +50 -8
  176. package/package.json +9 -9
  177. package/skills/blume-migrate/SKILL.md +1 -1
  178. package/skills/blume-migrate/references/docusaurus.md +4 -4
  179. package/skills/blume-migrate/references/fumadocs.md +17 -13
  180. package/skills/blume-migrate/references/nextra.md +8 -5
  181. package/skills/blume-migrate/references/starlight.md +9 -7
  182. package/src/ai/ask-context.ts +33 -3
  183. package/src/ai/ask-limits.ts +13 -0
  184. package/src/ai/changelog-markdown.ts +11 -6
  185. package/src/ai/component-markdown.ts +1 -1
  186. package/src/ai/cors.ts +12 -3
  187. package/src/ai/mcp/query.ts +14 -6
  188. package/src/ai/openapi-components.ts +28 -4
  189. package/src/ai/relative-links.ts +4 -38
  190. package/src/astro/generate.ts +78 -48
  191. package/src/astro/integration.ts +16 -13
  192. package/src/astro/markdown-negotiation.ts +3 -0
  193. package/src/astro/module-types.ts +3 -1
  194. package/src/astro/pages.ts +23 -0
  195. package/src/astro/templates.ts +125 -80
  196. package/src/audit/catalog.ts +19 -3
  197. package/src/audit/checks/links.ts +14 -1
  198. package/src/audit/checks/network.ts +110 -6
  199. package/src/audit/checks/redirects.ts +6 -4
  200. package/src/audit/checks/robots.ts +58 -2
  201. package/src/audit/run.ts +3 -0
  202. package/src/audit/types.ts +2 -0
  203. package/src/audit/url.ts +14 -5
  204. package/src/blume-modules.d.ts +5 -1
  205. package/src/cli/args.ts +51 -0
  206. package/src/cli/build-failure.ts +23 -0
  207. package/src/cli/commands/audit.ts +10 -1
  208. package/src/cli/commands/dev.ts +18 -2
  209. package/src/cli/commands/doctor.ts +45 -12
  210. package/src/cli/commands/eval.ts +36 -4
  211. package/src/cli/commands/init.ts +6 -4
  212. package/src/cli/commands/validate.ts +10 -1
  213. package/src/cli/init/scaffold.ts +3 -3
  214. package/src/cli/prepare.ts +6 -3
  215. package/src/cli/required-secrets.ts +1 -1
  216. package/src/components/content/ApiPlayground.astro +6 -2
  217. package/src/components/content/api-field.ts +4 -1
  218. package/src/components/content/api-page.ts +31 -7
  219. package/src/components/content/mermaid-element.ts +15 -1
  220. package/src/components/islands/hooks.ts +27 -1
  221. package/src/components/layout/PageActions.astro +139 -24
  222. package/src/components/layout/RootLayout.astro +10 -2
  223. package/src/components/layout/Search.astro +17 -3
  224. package/src/components/layout/TableOfContents.astro +24 -17
  225. package/src/components/layout/head-scripts.ts +6 -1
  226. package/src/components/layout/search/algolia.ts +10 -1
  227. package/src/components/layout/search/analytics.ts +42 -14
  228. package/src/components/layout/search/endpoint.ts +48 -5
  229. package/src/components/layout/search/pagefind.ts +114 -5
  230. package/src/components/layout/search/types.ts +12 -0
  231. package/src/components/layout/search/typesense.ts +18 -6
  232. package/src/components/openapi/AsyncApiOperation.astro +14 -7
  233. package/src/components/openapi/Authorization.astro +10 -0
  234. package/src/components/openapi/GraphqlOperation.astro +5 -0
  235. package/src/components/openapi/Operation.astro +24 -1
  236. package/src/components/openapi/ParametersTable.astro +8 -4
  237. package/src/components/openapi/Playground.astro +7 -1
  238. package/src/components/openapi/RequestBody.astro +19 -2
  239. package/src/components/openapi/Responses.astro +1 -0
  240. package/src/components/openapi/SchemaTable.astro +15 -3
  241. package/src/components/openapi/async-snippets.ts +61 -5
  242. package/src/components/openapi/async.ts +123 -29
  243. package/src/components/openapi/graphql-helpers.ts +35 -12
  244. package/src/components/openapi/helpers.ts +36 -2
  245. package/src/components/openapi/message-model.ts +54 -11
  246. package/src/components/openapi/message.ts +14 -4
  247. package/src/components/openapi/operation-model.ts +16 -7
  248. package/src/components/openapi/playground-client.ts +24 -5
  249. package/src/components/openapi/playground-schema.ts +1 -1
  250. package/src/components/openapi/schema-tree.ts +44 -14
  251. package/src/components/openapi/security.ts +10 -0
  252. package/src/components/openapi/snippets.ts +5 -3
  253. package/src/components/openapi/validate-json.ts +4 -3
  254. package/src/core/changelog-index.ts +31 -1
  255. package/src/core/component-diagnostics.ts +53 -0
  256. package/src/core/component-overrides.ts +32 -0
  257. package/src/core/config-input.ts +31 -3
  258. package/src/core/data.ts +2 -0
  259. package/src/core/diagnostics.ts +5 -0
  260. package/src/core/i18n-ui.ts +2 -0
  261. package/src/core/includes.ts +1 -1
  262. package/src/core/links.ts +47 -17
  263. package/src/core/probe.ts +26 -6
  264. package/src/core/project-graph.ts +59 -18
  265. package/src/core/redirect-patterns.ts +36 -7
  266. package/src/core/schema.ts +21 -2
  267. package/src/core/sources/cache.ts +6 -0
  268. package/src/core/sources/contentful-rich-text.ts +29 -6
  269. package/src/core/sources/contentful.ts +135 -25
  270. package/src/core/sources/filesystem.ts +26 -4
  271. package/src/core/sources/github-releases.ts +12 -1
  272. package/src/core/sources/lexical.ts +15 -10
  273. package/src/core/sources/mdx-remote.ts +62 -10
  274. package/src/core/sources/normalize.ts +227 -41
  275. package/src/core/sources/notion.ts +7 -1
  276. package/src/core/sources/obsidian.ts +16 -3
  277. package/src/core/sources/payload.ts +38 -15
  278. package/src/core/sources/remote.ts +72 -15
  279. package/src/core/sources/resolve.ts +11 -1
  280. package/src/core/sources/sanity.ts +43 -25
  281. package/src/core/sources/strapi.ts +2 -2
  282. package/src/core/types.ts +18 -0
  283. package/src/core/ui-packs/ar.ts +1 -0
  284. package/src/core/ui-packs/bg.ts +1 -0
  285. package/src/core/ui-packs/bn.ts +1 -0
  286. package/src/core/ui-packs/ca.ts +1 -0
  287. package/src/core/ui-packs/cs.ts +1 -0
  288. package/src/core/ui-packs/da.ts +1 -0
  289. package/src/core/ui-packs/de.ts +1 -0
  290. package/src/core/ui-packs/el.ts +1 -0
  291. package/src/core/ui-packs/es.ts +1 -0
  292. package/src/core/ui-packs/fa.ts +1 -0
  293. package/src/core/ui-packs/fi.ts +1 -0
  294. package/src/core/ui-packs/fr.ts +1 -0
  295. package/src/core/ui-packs/he.ts +1 -0
  296. package/src/core/ui-packs/hi.ts +1 -0
  297. package/src/core/ui-packs/hr.ts +1 -0
  298. package/src/core/ui-packs/hu.ts +1 -0
  299. package/src/core/ui-packs/id.ts +1 -0
  300. package/src/core/ui-packs/it.ts +1 -0
  301. package/src/core/ui-packs/ja.ts +1 -0
  302. package/src/core/ui-packs/ko.ts +1 -0
  303. package/src/core/ui-packs/nl.ts +1 -0
  304. package/src/core/ui-packs/no.ts +1 -0
  305. package/src/core/ui-packs/pl.ts +1 -0
  306. package/src/core/ui-packs/pt-br.ts +1 -0
  307. package/src/core/ui-packs/pt.ts +1 -0
  308. package/src/core/ui-packs/ro.ts +1 -0
  309. package/src/core/ui-packs/ru.ts +1 -0
  310. package/src/core/ui-packs/sk.ts +1 -0
  311. package/src/core/ui-packs/sr.ts +1 -0
  312. package/src/core/ui-packs/sv.ts +1 -0
  313. package/src/core/ui-packs/th.ts +1 -0
  314. package/src/core/ui-packs/tr.ts +1 -0
  315. package/src/core/ui-packs/uk.ts +1 -0
  316. package/src/core/ui-packs/vi.ts +1 -0
  317. package/src/core/ui-packs/zh-tw.ts +1 -0
  318. package/src/core/ui-packs/zh.ts +1 -0
  319. package/src/deploy/adapter-output.ts +7 -2
  320. package/src/deploy/adapters/cloudflare.ts +7 -5
  321. package/src/deploy/adapters/node.ts +47 -9
  322. package/src/deploy/adapters/types.ts +7 -3
  323. package/src/deploy/artifacts.ts +2 -1
  324. package/src/deploy/platforms/cloudflare.ts +13 -9
  325. package/src/deploy/platforms/netlify.ts +2 -1
  326. package/src/deploy/platforms/node.ts +12 -2
  327. package/src/deploy/platforms/types.ts +21 -7
  328. package/src/deploy/platforms/vercel.ts +113 -16
  329. package/src/deploy/redirects.ts +66 -6
  330. package/src/deploy/rss.ts +3 -1
  331. package/src/deploy/sitemap.ts +39 -5
  332. package/src/deploy/vercel-negotiation.ts +290 -102
  333. package/src/eval/agents.ts +18 -1
  334. package/src/eval/prompts.ts +6 -3
  335. package/src/eval/report.ts +34 -13
  336. package/src/eval/run.ts +5 -0
  337. package/src/markdown/relative-links.ts +3 -2
  338. package/src/openapi/checks.ts +273 -0
  339. package/src/openapi/graphql-build.ts +21 -0
  340. package/src/openapi/graphql.ts +11 -0
  341. package/src/openapi/model.ts +15 -3
  342. package/src/openapi/parse.ts +127 -2
  343. package/src/openapi/references.ts +43 -3
  344. package/src/openapi/source.ts +39 -14
  345. package/src/ratelimit/index.ts +1 -1
  346. package/src/ratelimit/runtime.ts +37 -19
  347. package/src/ratelimit/upstash.ts +40 -10
  348. package/src/reference/graphql.ts +15 -1
  349. package/src/reference/index.ts +1 -0
  350. package/src/reference/openapi.ts +2 -2
  351. package/src/reference/options.ts +29 -1
  352. package/src/registry/eject.ts +3 -1
  353. package/src/search/adapters/locale-scope.ts +30 -0
  354. package/src/search/adapters/typesense.ts +14 -4
  355. package/src/search/build.ts +21 -3
  356. package/src/search/orama-index.ts +163 -31
  357. package/src/search/source-pages.ts +29 -0
  358. package/src/search/sync/algolia.ts +99 -9
  359. package/src/search/sync/index.ts +52 -13
  360. package/src/search/sync/typesense.ts +72 -27
  361. package/src/sources/contentful.ts +12 -0
  362. package/src/sources/github-releases.ts +7 -1
  363. package/src/sources/shared.ts +3 -0
  364. package/src/theme/entry.ts +29 -3
  365. package/src/translate/validate.ts +23 -1
  366. package/dist/cli/chunk-0gz36akr.js.map +0 -12
  367. package/dist/cli/chunk-2n4ps1b3.js.map +0 -15
  368. package/dist/cli/chunk-43zcf4gz.js.map +0 -36
  369. package/dist/cli/chunk-4ejxbzee.js +0 -39
  370. package/dist/cli/chunk-4ejxbzee.js.map +0 -10
  371. package/dist/cli/chunk-4h8z9vv5.js.map +0 -16
  372. package/dist/cli/chunk-713mngdq.js.map +0 -14
  373. package/dist/cli/chunk-9xr4dgee.js.map +0 -10
  374. package/dist/cli/chunk-amrb6hgh.js +0 -145
  375. package/dist/cli/chunk-amrb6hgh.js.map +0 -11
  376. package/dist/cli/chunk-nd1821sk.js.map +0 -10
  377. package/dist/cli/chunk-rekqz4qg.js.map +0 -10
  378. package/dist/cli/chunk-ta27feev.js.map +0 -10
  379. package/dist/cli/chunk-xkz5xbtv.js.map +0 -213
  380. package/dist/cli/chunk-y5h4r2y0.js.map +0 -10
  381. /package/dist/cli/{chunk-gp84za0h.js.map → chunk-3v3ffbrj.js.map} +0 -0
  382. /package/dist/cli/{chunk-p804f3pe.js.map → chunk-8y2kmjv8.js.map} +0 -0
  383. /package/dist/cli/{chunk-2f7n4qzt.js.map → chunk-c1y538kd.js.map} +0 -0
  384. /package/dist/cli/{chunk-1n228xqb.js.map → chunk-c887fj0s.js.map} +0 -0
  385. /package/dist/cli/{chunk-cmtcnh9f.js.map → chunk-dzwehpy7.js.map} +0 -0
  386. /package/dist/cli/{chunk-ntv4qrt7.js.map → chunk-e9q7a2ak.js.map} +0 -0
  387. /package/dist/cli/{chunk-5wj2qwn2.js.map → chunk-ft9vfys6.js.map} +0 -0
  388. /package/dist/cli/{chunk-zhvd6adm.js.map → chunk-hx3xqnk9.js.map} +0 -0
  389. /package/dist/cli/{chunk-y4ykbark.js.map → chunk-kma9f6sf.js.map} +0 -0
  390. /package/dist/cli/{chunk-py62fewh.js.map → chunk-mrcccgnh.js.map} +0 -0
  391. /package/dist/cli/{chunk-2f3ndkpw.js.map → chunk-n0v7m8ry.js.map} +0 -0
  392. /package/dist/cli/{chunk-9geymqns.js.map → chunk-nq1d20w2.js.map} +0 -0
  393. /package/dist/cli/{chunk-g2z9x01v.js.map → chunk-nrns10mj.js.map} +0 -0
  394. /package/dist/cli/{chunk-e7vvk5ya.js.map → chunk-sds923fa.js.map} +0 -0
  395. /package/dist/cli/{chunk-yj17vs39.js.map → chunk-tdqhyxfz.js.map} +0 -0
  396. /package/dist/cli/{chunk-q3wxxq39.js.map → chunk-tphac74f.js.map} +0 -0
  397. /package/dist/cli/{chunk-6bm0xpgd.js.map → chunk-w1r4vase.js.map} +0 -0
@@ -135,7 +135,23 @@ export const mergeParameters = (
135
135
  export const refName = (ref: string): string =>
136
136
  REF_PATTERN.exec(ref)?.groups?.name ?? ref.split("/").at(-1) ?? ref;
137
137
 
138
- /** Resolve one level of `$ref` against the document's component schemas. */
138
+ /**
139
+ * The one member of an `allOf` that only wraps it: `allOf: [{ $ref }]` beside
140
+ * a `description`, `readOnly`, or `default`, which is how drf-spectacular and
141
+ * other generators attach keywords a 3.0 `$ref` can't carry. `undefined` for
142
+ * a real composition: several members, or properties or branches of its own.
143
+ */
144
+ export const soleAllOfMember = (schema: SchemaLike): SchemaLike | undefined =>
145
+ schema.allOf?.length === 1 &&
146
+ !(schema.properties || schema.oneOf || schema.anyOf)
147
+ ? schema.allOf[0]
148
+ : undefined;
149
+
150
+ /**
151
+ * Resolve one level of `$ref` against the document's component schemas. A
152
+ * single-member `allOf` wrapper resolves like its member, with the wrapper's
153
+ * own keywords on top: its `description` is about this field.
154
+ */
139
155
  export const resolveSchema = (
140
156
  schemas: Record<string, SchemaLike>,
141
157
  schema?: SchemaLike
@@ -143,6 +159,11 @@ export const resolveSchema = (
143
159
  if (!schema) {
144
160
  return {};
145
161
  }
162
+ const member = soleAllOfMember(schema);
163
+ if (member) {
164
+ const { allOf: _wrapped, ...own } = schema;
165
+ return { ...resolveSchema(schemas, member), ...own };
166
+ }
146
167
  if (isString(schema.$ref)) {
147
168
  const name = REF_PATTERN.exec(schema.$ref)?.groups?.name;
148
169
  if (name && schemas[name]) {
@@ -152,6 +173,16 @@ export const resolveSchema = (
152
173
  return schema;
153
174
  };
154
175
 
176
+ /**
177
+ * A parameter's description: its own, else its schema's (resolved one `$ref`
178
+ * level), which is where generators like Elysia and oRPC write it.
179
+ */
180
+ export const parameterDescription = (
181
+ param: { description?: string; schema?: SchemaLike },
182
+ schemas: Record<string, SchemaLike>
183
+ ): string | undefined =>
184
+ param.description ?? resolveSchema(schemas, param.schema).description;
185
+
155
186
  const declaredTypeList = (type: string | string[] | undefined): string[] => {
156
187
  if (!type) {
157
188
  return [];
@@ -177,6 +208,8 @@ const isNullType = (schema: SchemaLike): boolean => {
177
208
  * (`Pet`, `Pet[]`) without resolving — which also means circular refs through
178
209
  * array items can't recurse forever. A `null` member stays out of a union's
179
210
  * label: rows mark it with {@link isNullable}, as they do `type: [T, "null"]`.
211
+ * A single-member `allOf` wrapper labels as its member; a real composition is
212
+ * an `object`.
180
213
  */
181
214
  export const typeLabel = (schema: SchemaLike): string => {
182
215
  if (isString(schema.$ref)) {
@@ -192,7 +225,8 @@ export const typeLabel = (schema: SchemaLike): string => {
192
225
  return [...new Set(labels)].join(" | ") || "any";
193
226
  }
194
227
  if (schema.allOf) {
195
- return "object";
228
+ const member = soleAllOfMember(schema);
229
+ return member ? typeLabel(member) : "object";
196
230
  }
197
231
  const types = nonNullTypes(schema.type);
198
232
  const arrayLabel = (): string => `${typeLabel(schema.items ?? {})}[]`;
@@ -1,10 +1,15 @@
1
1
  import type {
2
2
  AsyncApiAction,
3
+ AsyncApiDocument,
3
4
  AsyncApiServerObject,
4
5
  } from "../../openapi/asyncapi.ts";
5
6
  import { withServerDefaults } from "../../openapi/model.ts";
6
7
  import type { AsyncApiMessageLike, NamedMessage } from "./async.ts";
7
- import { payloadSchema } from "./async.ts";
8
+ import {
9
+ kafkaKeySchema,
10
+ payloadSchema,
11
+ resolvedServerSecurity,
12
+ } from "./async.ts";
8
13
  import { exampleValue, toJson } from "./helpers.ts";
9
14
  import type { ParameterLike, SchemaLike } from "./helpers.ts";
10
15
  import type {
@@ -76,14 +81,34 @@ const messagePayload = (
76
81
  };
77
82
  };
78
83
 
84
+ /**
85
+ * The first message's Kafka key as the kcat sample writes it: sampled from
86
+ * its binding's `key` schema the way a payload is (a declared example wins),
87
+ * a non-string value as JSON. None when the message declares no key.
88
+ */
89
+ const messageKey = (
90
+ message: AsyncApiMessageLike | undefined,
91
+ schemas: Record<string, SchemaLike>,
92
+ components: AsyncApiDocument["components"]
93
+ ): string | undefined => {
94
+ const schema = kafkaKeySchema(message, components);
95
+ const key = inputValue(schema ? exampleValue(schema, schemas) : null);
96
+ return key === "" ? undefined : key;
97
+ };
98
+
79
99
  /**
80
100
  * A server's base URL for the picker. Falls back to the bare host when the
81
101
  * spec omits `protocol` — a label is a label, and the snippet builders read
82
102
  * the server object itself rather than this string. Server variables in the
83
103
  * host and pathname (`{env}.events.example.com`) resolve to their declared
84
104
  * defaults, in the label and in the object the samples and connect URL read.
105
+ * Security refs resolve here too, so the kcat sample can name the server's
106
+ * SASL mechanism.
85
107
  */
86
- const serverOption = (spec: AsyncApiServerObject): MessageServerOption => {
108
+ const serverOption = (
109
+ spec: AsyncApiServerObject,
110
+ components: AsyncApiDocument["components"]
111
+ ): MessageServerOption => {
87
112
  const server = { ...spec };
88
113
  if (spec.host !== undefined) {
89
114
  server.host = withServerDefaults(spec.host, spec.variables);
@@ -91,6 +116,9 @@ const serverOption = (spec: AsyncApiServerObject): MessageServerOption => {
91
116
  if (spec.pathname !== undefined) {
92
117
  server.pathname = withServerDefaults(spec.pathname, spec.variables);
93
118
  }
119
+ if (spec.security !== undefined) {
120
+ server.security = resolvedServerSecurity(spec, components);
121
+ }
94
122
  const host = `${server.host ?? ""}${server.pathname ?? ""}`;
95
123
  return {
96
124
  label: server.protocol ? `${server.protocol}://${host}` : host,
@@ -102,17 +130,32 @@ const serverOption = (spec: AsyncApiServerObject): MessageServerOption => {
102
130
  export const messageModel = (args: {
103
131
  action: AsyncApiAction;
104
132
  address: string;
133
+ /** The document's `components`, which bindings and security refs resolve against. */
134
+ components?: AsyncApiDocument["components"];
105
135
  messages: NamedMessage[];
106
136
  parameters: ParameterLike[];
107
137
  protocol?: string;
108
138
  schemas: Record<string, SchemaLike>;
109
139
  servers: AsyncApiServerObject[];
110
- }): MessageModel => ({
111
- action: args.action,
112
- address: args.address,
113
- connectable: Object.hasOwn(LIVE_PROTOCOLS, args.protocol ?? ""),
114
- params: messageParams(args.parameters),
115
- payload: messagePayload(args.messages[0]?.message, args.schemas),
116
- protocol: args.protocol,
117
- servers: args.servers.map(serverOption),
118
- });
140
+ }): MessageModel => {
141
+ const model: MessageModel = {
142
+ action: args.action,
143
+ address: args.address,
144
+ connectable: Object.hasOwn(LIVE_PROTOCOLS, args.protocol ?? ""),
145
+ params: messageParams(args.parameters),
146
+ payload: messagePayload(args.messages[0]?.message, args.schemas),
147
+ protocol: args.protocol,
148
+ servers: args.servers.map((server) =>
149
+ serverOption(server, args.components)
150
+ ),
151
+ };
152
+ const key = messageKey(
153
+ args.messages[0]?.message,
154
+ args.schemas,
155
+ args.components
156
+ );
157
+ if (key !== undefined) {
158
+ model.key = key;
159
+ }
160
+ return model;
161
+ };
@@ -41,15 +41,19 @@ export interface MessageServerOption {
41
41
  /** `protocol://host+pathname` — what the reader picks between. */
42
42
  label: string;
43
43
  /**
44
- * The spec server with its host/pathname variables at their defaults; the
45
- * snippet builders read host/pathname/protocol.
44
+ * The spec server with its host/pathname variables at their defaults and
45
+ * its `security` refs resolved; the snippet builders read
46
+ * host/pathname/protocol/security.
46
47
  */
47
48
  server: AsyncApiServerObject;
48
49
  }
49
50
 
50
51
  export interface MessageModel {
51
52
  action: AsyncApiAction;
52
- /** Channel address with `{param}` templates intact, e.g. `user/{id}/signedup`. */
53
+ /**
54
+ * Channel address with `{param}` templates intact, e.g. `user/{id}/signedup`
55
+ * — or the Kafka binding's `topic` when the channel names one.
56
+ */
53
57
  address: string;
54
58
  /**
55
59
  * Whether the panel offers a live connection. Only WebSocket bindings can be
@@ -57,6 +61,8 @@ export interface MessageModel {
57
61
  * CLI samples rather than faked connectivity.
58
62
  */
59
63
  connectable: boolean;
64
+ /** Example Kafka message key, sampled from the first message's binding. */
65
+ key?: string;
60
66
  params: MessageParam[];
61
67
  payload: MessagePayload;
62
68
  /** Normalized binding key (`ws`, `kafka`, `mqtt`, …) when the spec implies one. */
@@ -149,7 +155,7 @@ export const buildMessage = (
149
155
  } catch {
150
156
  payload = undefined;
151
157
  }
152
- return {
158
+ const sample: MessageSample = {
153
159
  action: model.action,
154
160
  address: model.address.replaceAll(PARAM_TEMPLATE, (template, name) => {
155
161
  const value = values.params[String(name)] ?? "";
@@ -158,6 +164,10 @@ export const buildMessage = (
158
164
  payload,
159
165
  server: custom === "" ? picked?.server : customServer(custom),
160
166
  };
167
+ if (model.key !== undefined) {
168
+ sample.key = model.key;
169
+ }
170
+ return sample;
161
171
  };
162
172
 
163
173
  /**
@@ -3,6 +3,7 @@ import {
3
3
  declaredExample,
4
4
  exampleValue,
5
5
  objectProperties,
6
+ parameterDescription,
6
7
  resolveSchema,
7
8
  toJson,
8
9
  } from "./helpers.ts";
@@ -142,7 +143,7 @@ const modelParams = (
142
143
  const required = where === "path" ? true : param.required === true;
143
144
  const schema = resolveSchema(schemas, param.schema);
144
145
  params.push({
145
- description: param.description,
146
+ description: parameterDescription(param, schemas),
146
147
  enum: schema.enum?.map(String),
147
148
  in: where,
148
149
  name: param.name,
@@ -330,6 +331,19 @@ const authInput = (
330
331
  }
331
332
  };
332
333
 
334
+ /**
335
+ * The playground's credential inputs for an operation's security: the first
336
+ * alternative only — the spec's preferred way to authorize, matching what the
337
+ * static samples always showed.
338
+ */
339
+ export const playgroundAuth = (
340
+ security: OperationSecurity
341
+ ): PlaygroundAuthInput[] =>
342
+ (security.alternatives[0] ?? []).flatMap((resolved) => {
343
+ const input = authInput(resolved);
344
+ return input ? [input] : [];
345
+ });
346
+
333
347
  /** Derive the playground request model for one operation, at build time. */
334
348
  export const operationModel = (args: {
335
349
  method: string;
@@ -344,12 +358,7 @@ export const operationModel = (args: {
344
358
  components?: ComponentsLike;
345
359
  security: OperationSecurity;
346
360
  }): PlaygroundModel => ({
347
- // First alternative only — the spec's preferred way to authorize, matching
348
- // what the static samples always showed.
349
- auth: (args.security.alternatives[0] ?? []).flatMap((resolved) => {
350
- const input = authInput(resolved);
351
- return input ? [input] : [];
352
- }),
361
+ auth: playgroundAuth(args.security),
353
362
  authOptional: args.security.optional,
354
363
  body: modelBody(args.requestBody, args.schemas, args.components),
355
364
  method: args.method.toUpperCase(),
@@ -26,16 +26,34 @@ import { fetchRefusesMethod, sampleLanguages } from "./snippets.ts";
26
26
  import type { RequestSample } from "./snippets.ts";
27
27
  import { validateJson } from "./validate-json.ts";
28
28
 
29
+ const OPENAPI_PROXY_SETTING =
30
+ "`playground: { proxy: true }` on the `openapi()` reference";
31
+
32
+ /**
33
+ * The Blume config setting that turns on the proxy for a panel, keyed by the
34
+ * `data-proxy-config` the rendering surface stamps on it: an `openapi()` or
35
+ * `graphql()` reference's `playground` option, or `api.playground` for
36
+ * hand-written API pages.
37
+ */
38
+ const PROXY_SETTINGS = new Map([
39
+ ["api", "`api: { playground: { proxy: true } }`"],
40
+ ["graphql", "`playground: { proxy: true }` on the `graphql()` reference"],
41
+ ["openapi", OPENAPI_PROXY_SETTING],
42
+ ]);
43
+
29
44
  /**
30
45
  * A failed fetch surfaces as a TypeError with no status — almost always the
31
46
  * browser's CORS wall, not the API being down — so the message explains the
32
- * one fix docs authors control instead of parroting "failed to fetch".
47
+ * one fix docs authors control instead of parroting "failed to fetch", naming
48
+ * the setting for the surface this panel is on and the server output the
49
+ * built-in proxy needs.
33
50
  */
34
- const CORS_MESSAGE =
51
+ const corsMessage = (config: string): string =>
35
52
  "The browser blocked this request before it reached the API — the API " +
36
53
  "likely does not allow cross-origin requests from this docs site. Set " +
37
- "`playground: { proxy: true }` on the `openapi()` reference in the Blume " +
38
- "config to route playground requests through the docs server instead.";
54
+ `${PROXY_SETTINGS.get(config) ?? OPENAPI_PROXY_SETTING} in the Blume ` +
55
+ "config to route playground requests through the docs server instead. " +
56
+ "The proxy needs server output: a host adapter in `deployment`.";
39
57
 
40
58
  /**
41
59
  * `Cookie` is a forbidden header name: a page cannot set it, so a credential
@@ -294,6 +312,7 @@ export const initPlayground = (root: HTMLElement): void => {
294
312
  const response = root.querySelector<HTMLElement>("[data-response]");
295
313
  const storageKey = root.dataset.storageKey ?? "";
296
314
  const proxy = root.dataset.proxy ?? "";
315
+ const proxyConfig = root.dataset.proxyConfig ?? "";
297
316
 
298
317
  /** True while a send is outstanding, so a second click can't race it. */
299
318
  let sending = false;
@@ -607,7 +626,7 @@ export const initPlayground = (root: HTMLElement): void => {
607
626
  const crossOrigin = !proxy && !sample.url.startsWith("/");
608
627
  message =
609
628
  crossOrigin && (await reachable(sample.url))
610
- ? CORS_MESSAGE
629
+ ? corsMessage(proxyConfig)
611
630
  : UNREACHABLE_MESSAGE;
612
631
  }
613
632
  response.textContent = "";
@@ -62,7 +62,7 @@ const isReadOnly = (
62
62
  * Prune a spec schema into the tiny subset `validate-json.ts` understands:
63
63
  * `$ref`s resolved inline, cycles cut (the visited set is copied per branch so
64
64
  * a ref reused by siblings still prunes fully), depth capped. Structure beyond
65
- * the cut simply goes unvalidated — advisory checks, not a gate.
65
+ * the cut simply goes unvalidated, so it can never block a send.
66
66
  */
67
67
  const pruneSchema = (
68
68
  schema: SchemaLike | undefined,
@@ -2,6 +2,7 @@ import {
2
2
  objectProperties,
3
3
  refName,
4
4
  resolveSchema,
5
+ soleAllOfMember,
5
6
  typeLabel,
6
7
  } from "./helpers.ts";
7
8
  import type { SchemaLike, SpecValue } from "./helpers.ts";
@@ -67,6 +68,15 @@ export type SchemaNode =
67
68
  const isString = (value: SpecValue): value is string =>
68
69
  typeof value === "string";
69
70
 
71
+ /**
72
+ * The `$ref` a schema stands for: its own, or its member's when it is a
73
+ * single-member `allOf` wrapper, which plans (and stops at a circle) the same.
74
+ */
75
+ const refOf = (schema: SchemaLike): string | undefined => {
76
+ const ref = schema.$ref ?? soleAllOfMember(schema)?.$ref;
77
+ return isString(ref) ? ref : undefined;
78
+ };
79
+
70
80
  const typesOf = (schema: SchemaLike): (string | undefined)[] =>
71
81
  Array.isArray(schema.type) ? schema.type : [schema.type];
72
82
 
@@ -88,13 +98,32 @@ interface PendingRef {
88
98
  slot: SchemaSlot;
89
99
  }
90
100
 
91
- /** Plan the table tree for one schema (a request body, a response, a payload). */
101
+ /**
102
+ * Which way a schema's data travels, when its table has one: a request body
103
+ * leaves out the `readOnly` fields the server generates, and a response the
104
+ * `writeOnly` ones it never returns, as the examples beside them do.
105
+ */
106
+ export type SchemaDirection = "request" | "response";
107
+
108
+ /**
109
+ * Plan the table tree for one schema (a request body, a response, a payload).
110
+ * With a `direction`, every table in the tree leaves out the fields that
111
+ * don't travel that way.
112
+ */
92
113
  export const schemaTree = (
93
114
  root: SchemaLike,
94
- schemas: Record<string, SchemaLike>
115
+ schemas: Record<string, SchemaLike>,
116
+ direction?: SchemaDirection
95
117
  ): SchemaNode => {
96
118
  const queue: PendingRef[] = [];
97
119
  const expanded = new Set<string>();
120
+ const omitted = direction === "request" ? "readOnly" : "writeOnly";
121
+
122
+ /** Whether a property stays out of this tree's tables. */
123
+ const hidden = (property: SchemaLike): boolean =>
124
+ direction !== undefined &&
125
+ (property[omitted] === true ||
126
+ resolveSchema(schemas, property)[omitted] === true);
98
127
 
99
128
  /**
100
129
  * A table for `schema`, where `ancestors` are the named schemas already
@@ -107,8 +136,9 @@ export const schemaTree = (
107
136
  ancestors: string[],
108
137
  resolved = false
109
138
  ): SchemaSlot => {
110
- if (!resolved && isString(schema.$ref)) {
111
- const name = refName(schema.$ref);
139
+ const ref = resolved ? undefined : refOf(schema);
140
+ if (ref) {
141
+ const name = refName(ref);
112
142
  if (ancestors.includes(name)) {
113
143
  return { node: { kind: "circular", name } };
114
144
  }
@@ -132,10 +162,8 @@ export const schemaTree = (
132
162
  }
133
163
  // A row discloses nested structure — never a model inside itself.
134
164
  const rowChildren = (property: SchemaLike): SchemaSlot | undefined => {
135
- if (
136
- isString(property.$ref) &&
137
- ancestors.includes(refName(property.$ref))
138
- ) {
165
+ const propertyRef = refOf(property);
166
+ if (propertyRef && ancestors.includes(refName(propertyRef))) {
139
167
  return undefined;
140
168
  }
141
169
  const target = resolveSchema(schemas, property);
@@ -147,12 +175,14 @@ export const schemaTree = (
147
175
  : undefined;
148
176
  };
149
177
  const { properties, required } = objectProperties(schema, schemas);
150
- const rows: SchemaRow[] = properties.map(([name, property]) => ({
151
- children: rowChildren(property),
152
- name,
153
- required: required.has(name),
154
- schema: property,
155
- }));
178
+ const rows: SchemaRow[] = properties
179
+ .filter(([, property]) => !hidden(property))
180
+ .map(([name, property]) => ({
181
+ children: rowChildren(property),
182
+ name,
183
+ required: required.has(name),
184
+ schema: property,
185
+ }));
156
186
  // Shared properties beside a `oneOf`/`anyOf` (`amount` and `currency`
157
187
  // next to `Card | BankAccount`) render above the variants, planned first
158
188
  // as they read first.
@@ -32,6 +32,11 @@ export interface ResolvedScheme {
32
32
  /** The scheme object; undefined when the requirement names an unknown one. */
33
33
  scheme?: SecuritySchemeLike;
34
34
  scopes: string[];
35
+ /**
36
+ * AsyncAPI: the servers that declare this scheme, set only when the
37
+ * channel's servers don't all declare the same ones.
38
+ */
39
+ servers?: string[];
35
40
  }
36
41
 
37
42
  /** The security state one operation renders. */
@@ -40,6 +45,11 @@ export interface OperationSecurity {
40
45
  alternatives: ResolvedScheme[][];
41
46
  /** True when an empty requirement also allows unauthenticated calls. */
42
47
  optional: boolean;
48
+ /**
49
+ * AsyncAPI: the servers that declare no security while others do, so the
50
+ * schemes apply on the other servers only.
51
+ */
52
+ unauthenticatedServers?: string[];
43
53
  }
44
54
 
45
55
  /**
@@ -1053,19 +1053,21 @@ export const sampleLanguageInfo = (raw: string): SampleLanguageInfo | null => {
1053
1053
  return language ? { label: language.label, lang: language.lang } : null;
1054
1054
  };
1055
1055
 
1056
+ /** `openapi()`'s default `codeSamples`, which hand-written endpoint pages always use. */
1057
+ export const DEFAULT_SAMPLE_LANGUAGES = ["curl", "js", "python"];
1058
+
1056
1059
  /**
1057
1060
  * The sample languages to render, resolved from config ids (unknown ids
1058
- * dropped). `false` renders none; an empty list, the defaults.
1061
+ * dropped), in order. `false` and an empty list both render none.
1059
1062
  */
1060
1063
  export const sampleLanguages = (ids: string[] | false): SampleLanguage[] => {
1061
1064
  if (ids === false) {
1062
1065
  return [];
1063
1066
  }
1064
- const wanted = ids.length > 0 ? ids : ["curl", "js", "python"];
1065
1067
  const byId = new Map(LANGUAGES.map((entry) => [entry.id, entry]));
1066
1068
  const out: SampleLanguage[] = [];
1067
1069
  const seen = new Set<string>();
1068
- for (const raw of wanted) {
1070
+ for (const raw of ids) {
1069
1071
  const id = sampleLanguageId(raw);
1070
1072
  const language = byId.get(id);
1071
1073
  if (language && !seen.has(id)) {
@@ -4,9 +4,10 @@ import type { ValidationSchema } from "./request.ts";
4
4
  * Minimal JSON-schema validation for the playground body editor. Client-safe
5
5
  * and dependency-free by design: the server prunes the operation's schema into
6
6
  * the tiny `ValidationSchema` subset (`operation-model.ts`), so a full
7
- * draft-2020 validator would be dead weight in the browser bundle. Checks are
8
- * advisory — they catch the common "typo'd a required field" mistakes, they do
9
- * not gate the Send button.
7
+ * draft-2020 validator would be dead weight in the browser bundle. The checks
8
+ * catch the common "typo'd a required field" mistakes, and any error they
9
+ * report blocks the Try it send (`playground-client.ts`) and the event
10
+ * composer's connect and send (`message-composer.ts`).
10
11
  */
11
12
 
12
13
  /** An already-parsed JSON object — string keys, parsed-JSON values. */
@@ -1,4 +1,6 @@
1
- import type { ResolvedConfig } from "./schema.ts";
1
+ import type { UIStrings } from "./i18n-ui.ts";
2
+ import { resolveLocalizable } from "./localizable.ts";
3
+ import type { LocalizableLabel, ResolvedConfig } from "./schema.ts";
2
4
  import { sourcesOfKind } from "./sources/collection.ts";
3
5
  import type { PageRecord } from "./types.ts";
4
6
 
@@ -22,3 +24,31 @@ export const hasChangelogIndex = (
22
24
  page.contentType === "changelog" &&
23
25
  !(page.meta.draft || page.meta.sidebar.hidden)
24
26
  ) || sourcesOfKind(config, "github-releases").length > 0;
27
+
28
+ /**
29
+ * A locale's UI strings with the index's title and description taken from
30
+ * the `changelog` config where it sets them (a string, or a per-locale map
31
+ * resolved like a header label), so every surface that reads the
32
+ * `changelog` strings (the page, its OG card, its Markdown mirror) agrees.
33
+ */
34
+ export const withChangelogIndexText = (
35
+ config: ResolvedConfig,
36
+ ui: UIStrings,
37
+ locale?: string
38
+ ): UIStrings => {
39
+ const text = (label: LocalizableLabel | undefined, fallback: string) =>
40
+ label === undefined
41
+ ? fallback
42
+ : resolveLocalizable(label, locale, config.i18n?.defaultLocale);
43
+ return {
44
+ ...ui,
45
+ changelog: {
46
+ ...ui.changelog,
47
+ description: text(
48
+ config.changelog?.description,
49
+ ui.changelog.description
50
+ ),
51
+ title: text(config.changelog?.title, ui.changelog.title),
52
+ },
53
+ };
54
+ };
@@ -1,3 +1,5 @@
1
+ import { relative } from "pathe";
2
+
1
3
  import { BUILTIN_MDX_TAGS } from "./builtin-tags.ts";
2
4
  import type { Diagnostic, PageRecord } from "./types.ts";
3
5
 
@@ -42,3 +44,54 @@ export const validateUsedComponents = (
42
44
  }
43
45
  return diagnostics;
44
46
  };
47
+
48
+ /** What example discovery found: where it looked, and each example's key. */
49
+ export interface ExampleKeys {
50
+ /** Absolute directory the examples were discovered under. */
51
+ dir: string;
52
+ examples: readonly { path: string }[];
53
+ }
54
+
55
+ /**
56
+ * Warn about each `<Component path>` in an `.mdx` page that names no
57
+ * discovered example. The page still renders, with a "No example found" box
58
+ * where the preview should be, so without this a typo or a moved example
59
+ * ships silently. Reported at the `path` value, in the partial that holds it
60
+ * when an `<include>` brought it in; a file shared by several locales is
61
+ * reported once. `extraTags` are the project's own components (islands +
62
+ * overrides), as for {@link validateUsedComponents}: one named `Component`
63
+ * replaces the built-in and resolves `path` its own way, so none is checked.
64
+ */
65
+ export const missingExampleDiagnostics = (
66
+ pages: readonly PageRecord[],
67
+ discovery: ExampleKeys,
68
+ root: string,
69
+ extraTags: ReadonlySet<string>
70
+ ): Diagnostic[] => {
71
+ if (extraTags.has("Component")) {
72
+ return [];
73
+ }
74
+ const known = new Set(discovery.examples.map((example) => example.path));
75
+ const dir = relative(root, discovery.dir) || ".";
76
+ const diagnostics: Diagnostic[] = [];
77
+ const seen = new Set<string>();
78
+ for (const page of pages) {
79
+ for (const use of page.examplesUsed ?? []) {
80
+ const file = use.file ?? page.sourcePath ?? page.id;
81
+ const key = `${file}:${use.line}:${use.column}`;
82
+ if (!(known.has(use.path) || seen.has(key))) {
83
+ seen.add(key);
84
+ diagnostics.push({
85
+ code: "BLUME_EXAMPLE_NOT_FOUND",
86
+ column: use.column,
87
+ file,
88
+ line: use.line,
89
+ message: `<Component path="${use.path}"> in ${page.route} names no example, so the page shows "No example found" in its place.`,
90
+ severity: "warning",
91
+ suggestion: `Fix the path, or add the example under ${dir}/: \`path\` is its location there, without the extension.`,
92
+ });
93
+ }
94
+ }
95
+ }
96
+ return diagnostics;
97
+ };
@@ -69,6 +69,29 @@ type Group = (typeof GROUPS)[number];
69
69
 
70
70
  const isGroup = (name: string): name is Group => GROUP_SET.has(name);
71
71
 
72
+ /**
73
+ * The `layout` keys the built-in chrome reads (`RootLayout.astro` and
74
+ * `Header.astro`). Any other key is never rendered, so it's warned about
75
+ * rather than silently dropped; a typo or wrong case would otherwise leave
76
+ * the built-in in place with no sign why.
77
+ */
78
+ const LAYOUT_SLOTS = [
79
+ "Layout",
80
+ "Header",
81
+ "Logo",
82
+ "Search",
83
+ "Sidebar",
84
+ "MobileNav",
85
+ "Breadcrumbs",
86
+ "TableOfContents",
87
+ "Pagination",
88
+ "Feedback",
89
+ "PageHeader",
90
+ "PageFooter",
91
+ "Footer",
92
+ ];
93
+ const LAYOUT_SLOT_SET: ReadonlySet<string> = new Set(LAYOUT_SLOTS);
94
+
72
95
  /** The authoring forms an override accepts; the fix every rejection points at. */
73
96
  export const ACCEPTED_OVERRIDE_FORMS =
74
97
  "Each override must be an imported identifier, a path string, or a `{ component, client, media }` object literal whose `component` is an imported identifier or a path string.";
@@ -628,6 +651,15 @@ const collectGroupOverrides = (
628
651
  if (normalized) {
629
652
  result[name].push(normalized);
630
653
  }
654
+ if (
655
+ name === "layout" &&
656
+ normalized &&
657
+ !LAYOUT_SLOT_SET.has(normalized.key)
658
+ ) {
659
+ context.warnings.push(
660
+ `Layout override "${normalized.key}" isn't a layout slot, so nothing renders it. Use one of: ${LAYOUT_SLOTS.join(", ")}.`
661
+ );
662
+ }
631
663
  }
632
664
  };
633
665