blume 2.0.1 → 2.0.3

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 (492) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/dist/cli/{chunk-qwsrynx5.js → chunk-1d7ve1dm.js} +38 -19
  3. package/dist/cli/{chunk-qwsrynx5.js.map → chunk-1d7ve1dm.js.map} +4 -4
  4. package/dist/cli/{chunk-s6jhgk0q.js → chunk-2eytanqx.js} +2 -2
  5. package/dist/cli/{chunk-kdp5q7ke.js → chunk-2hsdwb9n.js} +18 -19
  6. package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-2hsdwb9n.js.map} +2 -2
  7. package/dist/cli/{chunk-hdpx1tax.js → chunk-2z928egk.js} +5 -5
  8. package/dist/cli/{chunk-jwyddg7y.js → chunk-35d4wj9f.js} +30 -24
  9. package/dist/cli/chunk-35d4wj9f.js.map +15 -0
  10. package/dist/cli/{chunk-ah61y8py.js → chunk-364znk6q.js} +2 -2
  11. package/dist/cli/{chunk-jts8mvcz.js → chunk-3em5wd2y.js} +25 -6
  12. package/dist/cli/{chunk-jts8mvcz.js.map → chunk-3em5wd2y.js.map} +3 -3
  13. package/dist/cli/{chunk-s1p84fyh.js → chunk-5f86nr5m.js} +63 -22
  14. package/dist/cli/chunk-5f86nr5m.js.map +11 -0
  15. package/dist/cli/{chunk-2hn4b8z7.js → chunk-5m5nmvyq.js} +170 -76
  16. package/dist/cli/chunk-5m5nmvyq.js.map +13 -0
  17. package/dist/cli/{chunk-epjnccmv.js → chunk-5xvm6tfj.js} +18 -15
  18. package/dist/cli/chunk-5xvm6tfj.js.map +10 -0
  19. package/dist/cli/{chunk-fz5wtpmh.js → chunk-6dsbexzp.js} +18 -15
  20. package/dist/cli/chunk-6dsbexzp.js.map +10 -0
  21. package/dist/cli/{chunk-vtk4a6dg.js → chunk-8ktnccpt.js} +1 -1
  22. package/dist/cli/{chunk-6hsn950k.js → chunk-9t7a85s3.js} +178 -48
  23. package/dist/cli/chunk-9t7a85s3.js.map +10 -0
  24. package/dist/cli/{chunk-fxypxtvm.js → chunk-a58773jm.js} +2 -2
  25. package/dist/cli/{chunk-mb2919y2.js → chunk-acanzt5p.js} +17 -6
  26. package/dist/cli/chunk-acanzt5p.js.map +10 -0
  27. package/dist/cli/{chunk-27g6wdth.js → chunk-akbpwfxc.js} +90 -26
  28. package/dist/cli/chunk-akbpwfxc.js.map +10 -0
  29. package/dist/cli/{chunk-wm7js3j9.js → chunk-b07cmahc.js} +2 -2
  30. package/dist/cli/{chunk-wgm7m9qk.js → chunk-c8chx29p.js} +179 -51
  31. package/dist/cli/chunk-c8chx29p.js.map +36 -0
  32. package/dist/cli/{chunk-qs4q5p4e.js → chunk-crgn1q09.js} +32 -14
  33. package/dist/cli/chunk-crgn1q09.js.map +10 -0
  34. package/dist/cli/chunk-e04dxsz1.js +39 -0
  35. package/dist/cli/chunk-e04dxsz1.js.map +10 -0
  36. package/dist/cli/{chunk-yt5n7ppj.js → chunk-ey84smr6.js} +17 -7
  37. package/dist/cli/chunk-ey84smr6.js.map +10 -0
  38. package/dist/cli/{chunk-f2z5v128.js → chunk-g4hq16wv.js} +14 -15
  39. package/dist/cli/{chunk-f2z5v128.js.map → chunk-g4hq16wv.js.map} +2 -2
  40. package/dist/cli/{chunk-fa25z98p.js → chunk-ga0pf4aj.js} +9 -8
  41. package/dist/cli/chunk-ga0pf4aj.js.map +11 -0
  42. package/dist/cli/{chunk-kpf8rrjc.js → chunk-hm3vjy5s.js} +109 -58
  43. package/dist/cli/chunk-hm3vjy5s.js.map +19 -0
  44. package/dist/cli/{chunk-fs23ddbb.js → chunk-j85vccga.js} +625 -750
  45. package/dist/cli/chunk-j85vccga.js.map +36 -0
  46. package/dist/cli/{chunk-ch6g3ar0.js → chunk-p3v96n38.js} +6 -6
  47. package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-p3v96n38.js.map} +3 -3
  48. package/dist/cli/{chunk-q5163e60.js → chunk-p73c0m7w.js} +21 -19
  49. package/dist/cli/chunk-p73c0m7w.js.map +11 -0
  50. package/dist/cli/{chunk-dh8cwk36.js → chunk-pehfxfta.js} +24 -9
  51. package/dist/cli/chunk-pehfxfta.js.map +10 -0
  52. package/dist/cli/{chunk-qkqwkpte.js → chunk-pv29h0wf.js} +3688 -1313
  53. package/dist/cli/chunk-pv29h0wf.js.map +190 -0
  54. package/dist/cli/{chunk-6vm74dry.js → chunk-q58y5e6a.js} +10 -10
  55. package/dist/cli/{chunk-6vm74dry.js.map → chunk-q58y5e6a.js.map} +3 -3
  56. package/dist/cli/{chunk-zxcczpyx.js → chunk-r20tn01b.js} +1 -1
  57. package/dist/cli/{chunk-m3vmjgmq.js → chunk-r9rcc4w7.js} +16 -8
  58. package/dist/cli/chunk-r9rcc4w7.js.map +10 -0
  59. package/dist/cli/{chunk-5shv93fd.js → chunk-tkacnehg.js} +2 -2
  60. package/dist/cli/{chunk-zxh4d9vy.js → chunk-tzmab476.js} +4 -4
  61. package/dist/cli/{chunk-yw7dm696.js → chunk-vg9r4eb9.js} +24 -11
  62. package/dist/cli/chunk-vg9r4eb9.js.map +14 -0
  63. package/dist/cli/{chunk-79jhk4py.js → chunk-wrr3j9w9.js} +260 -132
  64. package/dist/cli/chunk-wrr3j9w9.js.map +35 -0
  65. package/dist/cli/{chunk-6crbhc3x.js → chunk-yfyb25rh.js} +54 -27
  66. package/dist/cli/chunk-yfyb25rh.js.map +14 -0
  67. package/dist/cli/index.js +162 -35
  68. package/dist/cli/index.js.map +4 -4
  69. package/dist/types/ai/agent-surface.d.ts +32 -0
  70. package/dist/types/ai/api-catalog.d.ts +7 -1
  71. package/dist/types/ai/ask-context.d.ts +7 -0
  72. package/dist/types/ai/component-markdown.d.ts +4 -4
  73. package/dist/types/ai/link-headers.d.ts +8 -1
  74. package/dist/types/ai/openapi-components.d.ts +5 -2
  75. package/dist/types/ai/relative-links.d.ts +11 -4
  76. package/dist/types/ai/skills.d.ts +4 -1
  77. package/dist/types/ai/static-expression.d.ts +28 -0
  78. package/dist/types/ai/tar.d.ts +1 -3
  79. package/dist/types/analytics/databuddy.d.ts +43 -0
  80. package/dist/types/analytics/index.d.ts +4 -0
  81. package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
  82. package/dist/types/analytics/schema.d.ts +28 -0
  83. package/dist/types/astro/integration.d.ts +3 -2
  84. package/dist/types/cli/env.d.ts +5 -0
  85. package/dist/types/cli/init/scaffold.d.ts +19 -3
  86. package/dist/types/cli/init/starter-spec.d.ts +11 -0
  87. package/dist/types/core/base-path.d.ts +24 -1
  88. package/dist/types/core/config-input.d.ts +13 -11
  89. package/dist/types/core/config.d.ts +2 -2
  90. package/dist/types/core/directive-diagnostics.d.ts +12 -0
  91. package/dist/types/core/graph.d.ts +2 -0
  92. package/dist/types/core/heading-markers.d.ts +5 -7
  93. package/dist/types/core/i18n-ui.d.ts +31 -0
  94. package/dist/types/core/i18n.d.ts +9 -1
  95. package/dist/types/core/last-modified.d.ts +10 -0
  96. package/dist/types/core/links.d.ts +3 -1
  97. package/dist/types/core/load-module.d.ts +10 -0
  98. package/dist/types/core/locale-links.d.ts +12 -2
  99. package/dist/types/core/meta.d.ts +13 -1
  100. package/dist/types/core/nav-diagnostics.d.ts +10 -0
  101. package/dist/types/core/navigation.d.ts +38 -0
  102. package/dist/types/core/ordering-prefix.d.ts +4 -0
  103. package/dist/types/core/safe-links.d.ts +3 -1
  104. package/dist/types/core/schema.d.ts +59 -13
  105. package/dist/types/core/sources/github-releases.d.ts +5 -0
  106. package/dist/types/core/sources/lower.d.ts +38 -13
  107. package/dist/types/core/sources/normalize.d.ts +23 -2
  108. package/dist/types/core/sources/remote.d.ts +11 -1
  109. package/dist/types/core/sources/resolve.d.ts +12 -0
  110. package/dist/types/core/sources/types.d.ts +31 -0
  111. package/dist/types/core/sources/watch.d.ts +12 -5
  112. package/dist/types/core/standard-schema.d.ts +5 -0
  113. package/dist/types/core/types.d.ts +9 -0
  114. package/dist/types/deploy/adapters/node.d.ts +5 -2
  115. package/dist/types/deploy/adapters/types.d.ts +7 -0
  116. package/dist/types/deploy/artifacts.d.ts +6 -4
  117. package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
  118. package/dist/types/deploy/headers.d.ts +36 -7
  119. package/dist/types/deploy/node-headers.d.ts +43 -8
  120. package/dist/types/deploy/platforms/netlify.d.ts +27 -2
  121. package/dist/types/deploy/platforms/node.d.ts +6 -5
  122. package/dist/types/deploy/platforms/types.d.ts +15 -0
  123. package/dist/types/deploy/platforms/vercel.d.ts +3 -2
  124. package/dist/types/deploy/redirects.d.ts +31 -15
  125. package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
  126. package/dist/types/markdown/directives.d.ts +62 -0
  127. package/dist/types/markdown/features.d.ts +21 -0
  128. package/dist/types/markdown/mdast.d.ts +63 -0
  129. package/dist/types/openapi/asyncapi.d.ts +4 -2
  130. package/dist/types/openapi/model.d.ts +20 -6
  131. package/dist/types/search/sync/algolia.d.ts +3 -1
  132. package/docs/01-quickstart.mdx +3 -2
  133. package/docs/02-deployment.mdx +20 -9
  134. package/docs/08-faq.mdx +10 -3
  135. package/docs/advanced/changelog.mdx +1 -1
  136. package/docs/advanced/custom-pages.mdx +7 -5
  137. package/docs/cli/audit.mdx +19 -3
  138. package/docs/cli/doctor.mdx +2 -2
  139. package/docs/cli/evals.mdx +4 -4
  140. package/docs/cli/index.mdx +4 -1
  141. package/docs/cli/translate.mdx +4 -4
  142. package/docs/cli/version.mdx +1 -1
  143. package/docs/configuration/analytics.mdx +42 -2
  144. package/docs/configuration/assistant.mdx +1 -1
  145. package/docs/configuration/customization.mdx +6 -3
  146. package/docs/configuration/index.mdx +5 -3
  147. package/docs/configuration/search.mdx +2 -2
  148. package/docs/content/components.mdx +2 -2
  149. package/docs/content/frontmatter.mdx +5 -1
  150. package/docs/content/i18n.mdx +3 -1
  151. package/docs/content/index.mdx +8 -4
  152. package/docs/content/islands.mdx +1 -1
  153. package/docs/content/meta.mdx +7 -3
  154. package/docs/content/navigation.mdx +29 -4
  155. package/docs/content/sources.mdx +18 -16
  156. package/docs/content/syntax.mdx +14 -0
  157. package/docs/content/versioning.mdx +2 -1
  158. package/docs/discoverability/agent-discovery.mdx +22 -8
  159. package/docs/discoverability/index.mdx +4 -3
  160. package/docs/discoverability/llms-txt.mdx +2 -5
  161. package/docs/discoverability/markdown.mdx +6 -4
  162. package/docs/discoverability/mcp.mdx +4 -0
  163. package/docs/discoverability/metadata.mdx +3 -2
  164. package/docs/discoverability/open-graph.mdx +8 -4
  165. package/docs/discoverability/rss.mdx +4 -2
  166. package/docs/references/asyncapi.mdx +2 -2
  167. package/docs/references/graphql.mdx +2 -2
  168. package/docs/references/openapi.mdx +6 -4
  169. package/package.json +1 -1
  170. package/skills/blume-migrate/SKILL.md +6 -6
  171. package/skills/blume-migrate/references/docusaurus.md +6 -6
  172. package/skills/blume-migrate/references/fumadocs.md +1 -1
  173. package/skills/blume-migrate/references/mintlify.md +3 -3
  174. package/skills/blume-migrate/references/monorepo.md +1 -1
  175. package/skills/blume-migrate/references/nextra.md +2 -2
  176. package/skills/blume-migrate/references/starlight.md +5 -5
  177. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +9 -4
  178. package/skills/blume-update-docs/references/audit-checklist.md +1 -1
  179. package/src/ai/agent-readability.ts +2 -2
  180. package/src/ai/agent-surface.ts +56 -0
  181. package/src/ai/ai-catalog.ts +6 -2
  182. package/src/ai/api/handlers.ts +2 -2
  183. package/src/ai/api/spec.ts +17 -4
  184. package/src/ai/api-catalog.ts +13 -3
  185. package/src/ai/ask-context.ts +14 -2
  186. package/src/ai/ask-data.ts +26 -12
  187. package/src/ai/changelog-markdown.ts +2 -2
  188. package/src/ai/component-markdown.ts +43 -37
  189. package/src/ai/link-headers.ts +22 -8
  190. package/src/ai/llms.ts +22 -10
  191. package/src/ai/markdown.ts +23 -11
  192. package/src/ai/mcp/discovery.ts +2 -2
  193. package/src/ai/mcp/query.ts +2 -2
  194. package/src/ai/mcp/server.ts +80 -9
  195. package/src/ai/openapi-components.ts +22 -6
  196. package/src/ai/relative-links.ts +99 -15
  197. package/src/ai/serializers.ts +2 -1
  198. package/src/ai/skills.ts +14 -1
  199. package/src/ai/static-expression.ts +416 -0
  200. package/src/ai/tar.ts +139 -12
  201. package/src/ai/visibility.ts +45 -14
  202. package/src/analytics/databuddy.ts +67 -0
  203. package/src/analytics/head.ts +8 -0
  204. package/src/analytics/index.ts +7 -0
  205. package/src/analytics/one-dollar-stats.ts +86 -0
  206. package/src/analytics/posthog.ts +21 -3
  207. package/src/analytics/schema.ts +4 -0
  208. package/src/astro/generate.ts +72 -28
  209. package/src/astro/include-hmr.ts +31 -12
  210. package/src/astro/include-refresh.ts +19 -8
  211. package/src/astro/integration.ts +108 -14
  212. package/src/astro/runtime-modules.ts +28 -13
  213. package/src/astro/templates.ts +139 -57
  214. package/src/audit/catalog.ts +2 -2
  215. package/src/audit/checks/assets.ts +25 -5
  216. package/src/audit/checks/content.ts +20 -2
  217. package/src/audit/checks/i18n.ts +46 -8
  218. package/src/audit/checks/indexability.ts +39 -19
  219. package/src/audit/checks/links.ts +22 -1
  220. package/src/audit/checks/llms.ts +6 -3
  221. package/src/audit/checks/network.ts +3 -1
  222. package/src/audit/checks/og-image.ts +10 -0
  223. package/src/audit/checks/robots.ts +6 -1
  224. package/src/audit/checks/sitemap.ts +56 -31
  225. package/src/audit/checks/social.ts +21 -2
  226. package/src/audit/crawl.ts +88 -15
  227. package/src/audit/graph.ts +3 -1
  228. package/src/audit/report.ts +54 -17
  229. package/src/audit/run.ts +13 -9
  230. package/src/audit/snapshot.ts +5 -0
  231. package/src/audit/types.ts +18 -0
  232. package/src/audit/url.ts +37 -6
  233. package/src/cli/args.ts +32 -0
  234. package/src/cli/build-failure.ts +50 -0
  235. package/src/cli/commands/audit.ts +11 -1
  236. package/src/cli/commands/build.ts +19 -5
  237. package/src/cli/commands/check.ts +2 -0
  238. package/src/cli/commands/doctor.ts +3 -1
  239. package/src/cli/commands/eval.ts +20 -18
  240. package/src/cli/commands/init.ts +15 -5
  241. package/src/cli/commands/preview.ts +15 -0
  242. package/src/cli/commands/sync.ts +2 -0
  243. package/src/cli/commands/translate.ts +18 -18
  244. package/src/cli/commands/upgrade.ts +11 -0
  245. package/src/cli/commands/validate.ts +3 -1
  246. package/src/cli/dev-lock.ts +157 -37
  247. package/src/cli/eject-scripts.ts +32 -7
  248. package/src/cli/env.ts +12 -1
  249. package/src/cli/init/scaffold.ts +117 -11
  250. package/src/cli/init/starter-spec.ts +235 -0
  251. package/src/cli/report-format.ts +11 -6
  252. package/src/components/colors.ts +19 -0
  253. package/src/components/content/AccordionItem.astro +26 -22
  254. package/src/components/content/Badge.astro +7 -12
  255. package/src/components/content/Card.astro +2 -2
  256. package/src/components/content/Component.astro +11 -5
  257. package/src/components/content/Expandable.astro +5 -1
  258. package/src/components/content/Frame.astro +2 -7
  259. package/src/components/content/GithubInfo.astro +12 -2
  260. package/src/components/content/Prompt.astro +2 -7
  261. package/src/components/content/Tab.astro +0 -1
  262. package/src/components/content/Tabs.astro +58 -5
  263. package/src/components/content/Tile.astro +1 -1
  264. package/src/components/content/Tooltip.astro +69 -7
  265. package/src/components/content/Tree.astro +7 -2
  266. package/src/components/content/TypeTable.astro +10 -5
  267. package/src/components/content/Update.astro +8 -2
  268. package/src/components/content/auto-type-table.ts +4 -1
  269. package/src/components/content/badge-color.ts +20 -0
  270. package/src/components/content/base-href.ts +14 -22
  271. package/src/components/content/inline-markdown.ts +27 -7
  272. package/src/components/copy-feedback.ts +35 -8
  273. package/src/components/islands/assistant.tsx +37 -6
  274. package/src/components/islands/base-path.ts +47 -10
  275. package/src/components/islands/hooks.ts +42 -21
  276. package/src/components/islands/webmcp.ts +16 -10
  277. package/src/components/layout/Banner.astro +23 -4
  278. package/src/components/layout/Breadcrumbs.astro +5 -2
  279. package/src/components/layout/DiscoveryLinks.astro +9 -5
  280. package/src/components/layout/Header.astro +23 -10
  281. package/src/components/layout/LanguageSwitcher.astro +2 -2
  282. package/src/components/layout/Logo.astro +5 -0
  283. package/src/components/layout/NavSelector.astro +8 -3
  284. package/src/components/layout/NavTabMenu.astro +133 -0
  285. package/src/components/layout/NavTree.astro +31 -12
  286. package/src/components/layout/NavTreeCache.astro +5 -2
  287. package/src/components/layout/NavTreeScript.astro +45 -5
  288. package/src/components/layout/PageActions.astro +4 -3
  289. package/src/components/layout/PageLayout.astro +28 -13
  290. package/src/components/layout/Pagination.astro +3 -3
  291. package/src/components/layout/ReferenceLayout.astro +4 -1
  292. package/src/components/layout/RootLayout.astro +25 -12
  293. package/src/components/layout/Search.astro +38 -14
  294. package/src/components/layout/VersionBanner.astro +2 -2
  295. package/src/components/layout/analytics-client.ts +14 -0
  296. package/src/components/layout/toc-active.ts +41 -0
  297. package/src/components/layout/toc-element.ts +8 -14
  298. package/src/components/openapi/ApiTagOperations.astro +2 -2
  299. package/src/components/openapi/AsyncApiOperation.astro +7 -4
  300. package/src/components/openapi/GraphqlChip.astro +2 -2
  301. package/src/components/openapi/GraphqlType.astro +11 -3
  302. package/src/components/openapi/MessageComposer.astro +1 -1
  303. package/src/components/openapi/Operation.astro +23 -5
  304. package/src/components/openapi/PanelTabs.astro +4 -1
  305. package/src/components/openapi/Playground.astro +8 -2
  306. package/src/components/openapi/RequestPanel.astro +13 -6
  307. package/src/components/openapi/SchemaProperty.astro +11 -33
  308. package/src/components/openapi/SchemaTable.astro +34 -52
  309. package/src/components/openapi/async.ts +38 -6
  310. package/src/components/openapi/helpers.ts +100 -12
  311. package/src/components/openapi/message-composer.ts +14 -1
  312. package/src/components/openapi/message-model.ts +12 -2
  313. package/src/components/openapi/message.ts +21 -3
  314. package/src/components/openapi/operation-model.ts +119 -17
  315. package/src/components/openapi/panel.ts +31 -5
  316. package/src/components/openapi/param-style.ts +181 -0
  317. package/src/components/openapi/playground-client.ts +110 -23
  318. package/src/components/openapi/playground-schema.ts +25 -6
  319. package/src/components/openapi/request.ts +192 -26
  320. package/src/components/openapi/schema-tree.ts +209 -0
  321. package/src/components/openapi/snippets.ts +113 -19
  322. package/src/components/openapi/validate-json.ts +1 -1
  323. package/src/components/openapi/ws-client.ts +18 -2
  324. package/src/core/base-path.ts +69 -8
  325. package/src/core/config-input.ts +13 -11
  326. package/src/core/config.ts +18 -4
  327. package/src/core/diagnostics.ts +219 -30
  328. package/src/core/directive-diagnostics.ts +99 -0
  329. package/src/core/frontmatter.ts +21 -18
  330. package/src/core/graph.ts +120 -11
  331. package/src/core/heading-markers.ts +5 -18
  332. package/src/core/i18n-ui.ts +39 -2
  333. package/src/core/i18n.ts +44 -5
  334. package/src/core/last-modified.ts +25 -3
  335. package/src/core/links.ts +7 -4
  336. package/src/core/load-module.ts +20 -0
  337. package/src/core/locale-links.ts +22 -18
  338. package/src/core/manifest.ts +3 -2
  339. package/src/core/meta.ts +89 -12
  340. package/src/core/nav-diagnostics.ts +56 -1
  341. package/src/core/navigation.ts +272 -83
  342. package/src/core/ordering-prefix.ts +27 -0
  343. package/src/core/project-graph.ts +50 -6
  344. package/src/core/safe-href.ts +53 -1
  345. package/src/core/safe-links.ts +11 -2
  346. package/src/core/schema.ts +94 -18
  347. package/src/core/sources/assets.ts +83 -41
  348. package/src/core/sources/contentful-rich-text.ts +28 -20
  349. package/src/core/sources/contentful.ts +25 -12
  350. package/src/core/sources/filesystem.ts +25 -3
  351. package/src/core/sources/github-releases.ts +131 -11
  352. package/src/core/sources/lexical.ts +30 -20
  353. package/src/core/sources/lower.ts +276 -56
  354. package/src/core/sources/mdx-remote.ts +52 -16
  355. package/src/core/sources/normalize.ts +456 -119
  356. package/src/core/sources/notion.ts +77 -34
  357. package/src/core/sources/obsidian.ts +40 -9
  358. package/src/core/sources/payload.ts +1 -0
  359. package/src/core/sources/portable-text.ts +85 -49
  360. package/src/core/sources/remote.ts +18 -2
  361. package/src/core/sources/resolve.ts +52 -33
  362. package/src/core/sources/sanity.ts +1 -0
  363. package/src/core/sources/strapi-blocks.ts +28 -19
  364. package/src/core/sources/strapi.ts +1 -0
  365. package/src/core/sources/types.ts +31 -0
  366. package/src/core/sources/watch.ts +20 -7
  367. package/src/core/standard-schema.ts +10 -6
  368. package/src/core/types.ts +9 -0
  369. package/src/core/ui-packs/ar.ts +13 -0
  370. package/src/core/ui-packs/bg.ts +13 -0
  371. package/src/core/ui-packs/bn.ts +13 -0
  372. package/src/core/ui-packs/ca.ts +13 -0
  373. package/src/core/ui-packs/cs.ts +13 -0
  374. package/src/core/ui-packs/da.ts +13 -0
  375. package/src/core/ui-packs/de.ts +13 -0
  376. package/src/core/ui-packs/el.ts +13 -0
  377. package/src/core/ui-packs/es.ts +13 -0
  378. package/src/core/ui-packs/fa.ts +13 -0
  379. package/src/core/ui-packs/fi.ts +13 -0
  380. package/src/core/ui-packs/fr.ts +13 -0
  381. package/src/core/ui-packs/he.ts +13 -0
  382. package/src/core/ui-packs/hi.ts +13 -0
  383. package/src/core/ui-packs/hr.ts +13 -0
  384. package/src/core/ui-packs/hu.ts +13 -0
  385. package/src/core/ui-packs/id.ts +13 -0
  386. package/src/core/ui-packs/it.ts +13 -0
  387. package/src/core/ui-packs/ja.ts +13 -0
  388. package/src/core/ui-packs/ko.ts +13 -0
  389. package/src/core/ui-packs/nl.ts +13 -0
  390. package/src/core/ui-packs/no.ts +13 -0
  391. package/src/core/ui-packs/pl.ts +13 -0
  392. package/src/core/ui-packs/pt-br.ts +13 -0
  393. package/src/core/ui-packs/pt.ts +13 -0
  394. package/src/core/ui-packs/ro.ts +13 -0
  395. package/src/core/ui-packs/ru.ts +13 -0
  396. package/src/core/ui-packs/sk.ts +13 -0
  397. package/src/core/ui-packs/sr.ts +13 -0
  398. package/src/core/ui-packs/sv.ts +13 -0
  399. package/src/core/ui-packs/th.ts +13 -0
  400. package/src/core/ui-packs/tr.ts +13 -0
  401. package/src/core/ui-packs/uk.ts +13 -0
  402. package/src/core/ui-packs/vi.ts +13 -0
  403. package/src/core/ui-packs/zh-tw.ts +13 -0
  404. package/src/core/ui-packs/zh.ts +13 -0
  405. package/src/core/version-cut.ts +69 -17
  406. package/src/core/versions.ts +4 -1
  407. package/src/deploy/adapters/node.ts +5 -2
  408. package/src/deploy/adapters/registry.ts +2 -1
  409. package/src/deploy/adapters/types.ts +13 -1
  410. package/src/deploy/artifacts.ts +52 -11
  411. package/src/deploy/cloudflare-negotiation.ts +27 -16
  412. package/src/deploy/headers.ts +75 -55
  413. package/src/deploy/node-headers.ts +148 -27
  414. package/src/deploy/platforms/cloudflare.ts +13 -3
  415. package/src/deploy/platforms/netlify.ts +83 -5
  416. package/src/deploy/platforms/node.ts +8 -5
  417. package/src/deploy/platforms/static.ts +2 -0
  418. package/src/deploy/platforms/types.ts +15 -0
  419. package/src/deploy/platforms/vercel.ts +10 -3
  420. package/src/deploy/redirects.ts +68 -21
  421. package/src/deploy/robots.ts +2 -2
  422. package/src/deploy/rss.ts +4 -3
  423. package/src/deploy/sitemap.ts +7 -5
  424. package/src/deploy/vercel-negotiation.ts +35 -3
  425. package/src/eval/agents.ts +10 -2
  426. package/src/eval/run.ts +25 -0
  427. package/src/markdown/base-links.ts +74 -29
  428. package/src/markdown/directives.ts +242 -36
  429. package/src/markdown/features.ts +17 -0
  430. package/src/markdown/index.ts +13 -9
  431. package/src/markdown/mdast.ts +5 -2
  432. package/src/markdown/relative-links.ts +15 -27
  433. package/src/markdown/route-snapshot.ts +37 -0
  434. package/src/og/card.ts +149 -9
  435. package/src/og/derive.ts +156 -5
  436. package/src/og/index.ts +1 -0
  437. package/src/openapi/asyncapi.ts +4 -2
  438. package/src/openapi/graphql-build.ts +28 -2
  439. package/src/openapi/model.ts +99 -27
  440. package/src/openapi/proxy.ts +63 -10
  441. package/src/openapi/render-mdx.ts +51 -3
  442. package/src/registry/eject.ts +297 -43
  443. package/src/search/adapters/version-scope.ts +30 -0
  444. package/src/search/documents.ts +89 -27
  445. package/src/search/popular.ts +2 -1
  446. package/src/search/sync/algolia.ts +36 -2
  447. package/src/seo/jsonld.ts +7 -3
  448. package/src/sources/registry.ts +5 -0
  449. package/src/theme/entry.ts +11 -4
  450. package/src/translate/agents.ts +6 -1
  451. package/src/translate/ledger.ts +26 -3
  452. package/src/translate/meta.ts +76 -24
  453. package/src/translate/run.ts +14 -8
  454. package/src/translate/validate.ts +14 -2
  455. package/src/translate/work-list.ts +91 -19
  456. package/src/upgrade/upgrade.ts +36 -4
  457. package/dist/cli/chunk-27g6wdth.js.map +0 -10
  458. package/dist/cli/chunk-2hn4b8z7.js.map +0 -12
  459. package/dist/cli/chunk-6crbhc3x.js.map +0 -14
  460. package/dist/cli/chunk-6hsn950k.js.map +0 -10
  461. package/dist/cli/chunk-79jhk4py.js.map +0 -35
  462. package/dist/cli/chunk-82bbrxdn.js +0 -51
  463. package/dist/cli/chunk-82bbrxdn.js.map +0 -10
  464. package/dist/cli/chunk-abh8yjkn.js +0 -31
  465. package/dist/cli/chunk-abh8yjkn.js.map +0 -10
  466. package/dist/cli/chunk-ce574jw2.js +0 -23
  467. package/dist/cli/chunk-ce574jw2.js.map +0 -10
  468. package/dist/cli/chunk-dh8cwk36.js.map +0 -10
  469. package/dist/cli/chunk-epjnccmv.js.map +0 -10
  470. package/dist/cli/chunk-fa25z98p.js.map +0 -11
  471. package/dist/cli/chunk-fs23ddbb.js.map +0 -35
  472. package/dist/cli/chunk-fz5wtpmh.js.map +0 -10
  473. package/dist/cli/chunk-jwyddg7y.js.map +0 -15
  474. package/dist/cli/chunk-kpf8rrjc.js.map +0 -19
  475. package/dist/cli/chunk-m3vmjgmq.js.map +0 -10
  476. package/dist/cli/chunk-mb2919y2.js.map +0 -10
  477. package/dist/cli/chunk-q5163e60.js.map +0 -11
  478. package/dist/cli/chunk-qkqwkpte.js.map +0 -182
  479. package/dist/cli/chunk-qs4q5p4e.js.map +0 -10
  480. package/dist/cli/chunk-s1p84fyh.js.map +0 -10
  481. package/dist/cli/chunk-wgm7m9qk.js.map +0 -36
  482. package/dist/cli/chunk-yt5n7ppj.js.map +0 -10
  483. package/dist/cli/chunk-yw7dm696.js.map +0 -14
  484. /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-2eytanqx.js.map} +0 -0
  485. /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-2z928egk.js.map} +0 -0
  486. /package/dist/cli/{chunk-ah61y8py.js.map → chunk-364znk6q.js.map} +0 -0
  487. /package/dist/cli/{chunk-vtk4a6dg.js.map → chunk-8ktnccpt.js.map} +0 -0
  488. /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-a58773jm.js.map} +0 -0
  489. /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-b07cmahc.js.map} +0 -0
  490. /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-r20tn01b.js.map} +0 -0
  491. /package/dist/cli/{chunk-5shv93fd.js.map → chunk-tkacnehg.js.map} +0 -0
  492. /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-tzmab476.js.map} +0 -0
@@ -3,33 +3,23 @@ import Description from "./Description.astro";
3
3
  import {
4
4
  constraints,
5
5
  isNullable,
6
- refName,
7
6
  resolveSchema,
8
7
  type SchemaLike,
9
8
  typeLabel,
10
9
  } from "./helpers.ts";
10
+ import { rowExpands, type SchemaRow } from "./schema-tree.ts";
11
11
  import SchemaTable from "./SchemaTable.astro";
12
12
 
13
13
  interface Props {
14
- name: string;
15
- schema: SchemaLike;
16
- required?: boolean;
14
+ /** One planned row of the parent table (see `schema-tree.ts`). */
15
+ row: SchemaRow;
17
16
  schemas: Record<string, SchemaLike>;
18
- seen?: string[];
19
17
  expandAll?: boolean;
20
18
  }
21
19
 
22
- const {
23
- name,
24
- schema,
25
- required = false,
26
- schemas,
27
- seen = [],
28
- expandAll = false,
29
- } = Astro.props;
20
+ const { row, schemas, expandAll = false } = Astro.props;
21
+ const { name, schema, required } = row;
30
22
 
31
- const refLabel = typeof schema.$ref === "string" ? refName(schema.$ref) : null;
32
- const circular = refLabel !== null && seen.includes(refLabel);
33
23
  const resolved = resolveSchema(schemas, schema);
34
24
 
35
25
  const type = typeLabel(schema);
@@ -39,20 +29,9 @@ const nullable = isNullable(resolved);
39
29
  const enumValues = Array.isArray(resolved.enum) ? resolved.enum : null;
40
30
  const limits = constraints(resolved);
41
31
 
42
- const types = Array.isArray(resolved.type) ? resolved.type : [resolved.type];
43
- const isArray = types.includes("array");
44
- const items = isArray ? resolveSchema(schemas, resolved.items) : null;
45
-
46
- const hasObjectShape = (candidate: SchemaLike): boolean =>
47
- Boolean(
48
- candidate.properties ||
49
- candidate.allOf ||
50
- candidate.oneOf ||
51
- candidate.anyOf ||
52
- typeof candidate.$ref === "string"
53
- );
54
- const expandable =
55
- !circular && (hasObjectShape(resolved) || Boolean(items && hasObjectShape(items)));
32
+ // Circles and schemas expanded elsewhere in the tree have no disclosure; the
33
+ // type label names them.
34
+ const children = rowExpands(row) ? row.children : undefined;
56
35
  ---
57
36
 
58
37
  {/* The row's vertical scale is 8 / 12 / 16px, and every other reference table copies it. A
@@ -103,17 +82,16 @@ const expandable =
103
82
  )
104
83
  }
105
84
  {
106
- expandable && (
85
+ children && (
107
86
  <details class="mt-3" open={expandAll}>
108
87
  <summary class="cursor-pointer select-none text-accent text-xs hover:underline">
109
88
  <span class="[details[open]>summary_&]:hidden">Show properties</span>
110
89
  <span class="hidden [details[open]>summary_&]:inline">Hide properties</span>
111
90
  </summary>
112
- <div class="mt-3 border-border border-l pl-4">
91
+ <div class="mt-3 border-border border-s ps-4">
113
92
  <SchemaTable
114
- schema={schema}
93
+ node={children.node}
115
94
  schemas={schemas}
116
- seen={seen}
117
95
  expandAll={expandAll}
118
96
  />
119
97
  </div>
@@ -1,86 +1,68 @@
1
1
  ---
2
- import {
3
- objectProperties,
4
- refName,
5
- resolveSchema,
6
- type SchemaLike,
7
- typeLabel,
8
- } from "./helpers.ts";
2
+ import type { SchemaLike } from "./helpers.ts";
3
+ import { type SchemaNode, schemaTree } from "./schema-tree.ts";
9
4
  import SchemaProperty from "./SchemaProperty.astro";
10
5
 
11
6
  interface Props {
12
- schema: SchemaLike;
7
+ /** The schema to render, planned here when no `node` is given. */
8
+ schema?: SchemaLike;
9
+ /** An already-planned subtree: how nested tables render. */
10
+ node?: SchemaNode;
13
11
  schemas: Record<string, SchemaLike>;
14
- /** `$ref` names already on the current branch, to break circular schemas. */
15
- seen?: string[];
16
12
  expandAll?: boolean;
17
13
  }
18
14
 
19
- const { schema, schemas, seen = [], expandAll = false } = Astro.props;
15
+ const { schema = {}, node: planned, schemas, expandAll = false } = Astro.props;
20
16
 
21
- // Track the ref so a self-referential model stops instead of recursing forever.
22
- const refLabel =
23
- typeof schema.$ref === "string" ? refName(schema.$ref) : null;
24
- const circular = refLabel !== null && seen.includes(refLabel);
25
- const nextSeen = refLabel ? [...seen, refLabel] : seen;
26
- const resolved = circular ? schema : resolveSchema(schemas, schema);
27
-
28
- const types = Array.isArray(resolved.type) ? resolved.type : [resolved.type];
29
- const isArray = types.includes("array");
30
- // Keep array items unresolved so a self-referential item `$ref` stays trackable
31
- // via `seen` — resolving here would drop the name and loop forever.
32
- const items = isArray ? (resolved.items ?? null) : null;
33
- const branches = resolved.oneOf ?? resolved.anyOf ?? null;
34
-
35
- const { properties, required } = circular
36
- ? { properties: [] as [string, SchemaLike][], required: new Set<string>() }
37
- : objectProperties(resolved, schemas);
17
+ // The whole tree is planned once, at the top-level table, so that which named
18
+ // schemas expand is decided for the tree as a whole (see `schema-tree.ts`).
19
+ const node = planned ?? schemaTree(schema, schemas);
38
20
  ---
39
21
 
40
22
  {
41
- circular ? (
23
+ node.kind === "circular" ? (
42
24
  <div class="text-muted-foreground text-sm">
43
- Circular reference to <code class="text-foreground">{refLabel}</code>.
25
+ Circular reference to <code class="text-foreground">{node.name}</code>.
44
26
  </div>
45
- ) : isArray ? (
27
+ ) : node.kind === "array" ? (
46
28
  <div>
47
29
  <div class="mb-2 text-muted-foreground text-xs">
48
- Array of <code class="text-foreground">{typeLabel(items ?? {})}</code>
30
+ Array of <code class="text-foreground">{node.itemsLabel}</code>
49
31
  </div>
50
- {items && (
51
- <Astro.self schema={items} schemas={schemas} seen={nextSeen} expandAll={expandAll} />
32
+ {node.items && (
33
+ <Astro.self node={node.items.node} schemas={schemas} expandAll={expandAll} />
52
34
  )}
53
35
  </div>
54
- ) : branches ? (
36
+ ) : node.kind === "branches" ? (
55
37
  <div class="flex flex-col gap-3">
56
- <div class="text-muted-foreground text-xs">
57
- {resolved.oneOf ? "One of" : "Any of"}:
58
- </div>
59
- {branches.map((branch, index) => (
38
+ {node.rows && (
39
+ <div class="not-prose">
40
+ {node.rows.map((row) => (
41
+ <SchemaProperty row={row} schemas={schemas} expandAll={expandAll} />
42
+ ))}
43
+ </div>
44
+ )}
45
+ <div class="text-muted-foreground text-xs">{node.label}:</div>
46
+ {node.branches.map((branch) => (
60
47
  <div class="rounded-blume border border-border p-3">
61
48
  <div class="mb-2 font-medium text-foreground text-xs">
62
- {typeLabel(branch) || `Option ${index + 1}`}
49
+ {branch.label}
63
50
  </div>
64
- <Astro.self schema={branch} schemas={schemas} seen={nextSeen} expandAll={expandAll} />
51
+ <Astro.self node={branch.slot.node} schemas={schemas} expandAll={expandAll} />
65
52
  </div>
66
53
  ))}
67
54
  </div>
68
- ) : properties.length > 0 ? (
55
+ ) : node.kind === "properties" ? (
69
56
  <div class="not-prose">
70
- {properties.map(([name, prop]) => (
71
- <SchemaProperty
72
- name={name}
73
- schema={prop}
74
- required={required.has(name)}
75
- schemas={schemas}
76
- seen={nextSeen}
77
- expandAll={expandAll}
78
- />
57
+ {node.rows.map((row) => (
58
+ <SchemaProperty row={row} schemas={schemas} expandAll={expandAll} />
79
59
  ))}
80
60
  </div>
81
61
  ) : (
82
62
  <div class="text-muted-foreground text-sm">
83
- <code class="text-foreground">{typeLabel(resolved)}</code>
63
+ <code class="text-foreground">
64
+ {node.kind === "named" ? node.name : node.label}
65
+ </code>
84
66
  </div>
85
67
  )
86
68
  }
@@ -265,6 +265,32 @@ export const channelServers = (
265
265
  return servers;
266
266
  };
267
267
 
268
+ /** A protocol-keyed `bindings` map, whatever object it sits on. */
269
+ type BindingMap = Record<string, AsyncApiSpecValue>;
270
+
271
+ const BINDINGS_REF =
272
+ /^#\/components\/(?<section>(?:server|channel|operation|message)Bindings)\/(?<name>[^/]+)$/u;
273
+
274
+ /**
275
+ * A `bindings` map as declared: inline, or — which AsyncAPI allows in its
276
+ * place — a `$ref` to a `#/components/*Bindings` entry, resolved here. Read
277
+ * as-is, a referenced map's only key is `$ref`, which would pass for the
278
+ * protocol. `undefined` when a ref resolves to nothing.
279
+ */
280
+ export const resolveBindings = (
281
+ bindings: BindingMap | undefined,
282
+ components?: Components
283
+ ): BindingMap | undefined => {
284
+ const ref = bindings?.$ref;
285
+ if (!isString(ref)) {
286
+ return bindings;
287
+ }
288
+ const groups = BINDINGS_REF.exec(ref)?.groups;
289
+ const target =
290
+ components?.[groups?.section ?? ""]?.[unescapePointer(groups?.name ?? "")];
291
+ return isObject(target) ? target : undefined;
292
+ };
293
+
268
294
  /** Normalize protocol spellings onto the binding key they document. */
269
295
  const PROTOCOL_ALIASES = {
270
296
  "kafka-secure": "kafka",
@@ -277,15 +303,17 @@ const PROTOCOL_ALIASES = {
277
303
  /**
278
304
  * The protocol an operation speaks, for binding-aware code samples: the first
279
305
  * operation/channel binding key, else the first relevant server's `protocol`.
306
+ * `components` resolves bindings given as a `$ref`.
280
307
  */
281
308
  export const protocolOf = (
282
309
  operation: AsyncApiOperationObject | undefined,
283
310
  channel: AsyncApiChannelObject | undefined,
284
- servers: AsyncApiServerObject[]
311
+ servers: AsyncApiServerObject[],
312
+ components?: Components
285
313
  ): string | undefined => {
286
314
  const declared =
287
- Object.keys(operation?.bindings ?? {})[0] ??
288
- Object.keys(channel?.bindings ?? {})[0] ??
315
+ Object.keys(resolveBindings(operation?.bindings, components) ?? {})[0] ??
316
+ Object.keys(resolveBindings(channel?.bindings, components) ?? {})[0] ??
289
317
  servers.find((server) => isString(server.protocol))?.protocol;
290
318
  if (!isString(declared) || declared === "") {
291
319
  return undefined;
@@ -338,13 +366,17 @@ export interface BindingGroup {
338
366
  /**
339
367
  * Binding maps flattened for display, `bindingVersion` (metadata, not
340
368
  * behavior) dropped. Values stay unformatted — the component renders schema-ish
341
- * objects as nested schema tables and everything else as code.
369
+ * objects as nested schema tables and everything else as code. `components`
370
+ * resolves a map given as a `$ref`.
342
371
  */
343
372
  export const bindingGroups = (
344
- bindings?: AsyncApiChannelObject["bindings"]
373
+ bindings?: BindingMap,
374
+ components?: Components
345
375
  ): BindingGroup[] => {
346
376
  const groups: BindingGroup[] = [];
347
- for (const [protocol, fields] of Object.entries(bindings ?? {})) {
377
+ for (const [protocol, fields] of Object.entries(
378
+ resolveBindings(bindings, components) ?? {}
379
+ )) {
348
380
  if (!isObject(fields)) {
349
381
  continue;
350
382
  }
@@ -152,17 +152,31 @@ export const resolveSchema = (
152
152
  return schema;
153
153
  };
154
154
 
155
- const nonNullTypes = (type: string | string[] | undefined): string[] => {
155
+ const declaredTypeList = (type: string | string[] | undefined): string[] => {
156
156
  if (!type) {
157
157
  return [];
158
158
  }
159
- return (Array.isArray(type) ? type : [type]).filter((t) => t !== "null");
159
+ return Array.isArray(type) ? type : [type];
160
+ };
161
+
162
+ const nonNullTypes = (type: string | string[] | undefined): string[] =>
163
+ declaredTypeList(type).filter((t) => t !== "null");
164
+
165
+ /**
166
+ * Whether a schema admits only `null`: `{ type: "null" }`, the branch Scalar's
167
+ * upgrade pairs with a 3.0 `nullable: true` `$ref` (`anyOf: [$ref, { type:
168
+ * "null" }]`).
169
+ */
170
+ const isNullType = (schema: SchemaLike): boolean => {
171
+ const types = declaredTypeList(schema.type);
172
+ return types.length > 0 && types.every((type) => type === "null");
160
173
  };
161
174
 
162
175
  /**
163
176
  * A short, human-readable type label for a schema row. `$ref`s label by name
164
177
  * (`Pet`, `Pet[]`) without resolving — which also means circular refs through
165
- * array items can't recurse forever.
178
+ * array items can't recurse forever. A `null` member stays out of a union's
179
+ * label: rows mark it with {@link isNullable}, as they do `type: [T, "null"]`.
166
180
  */
167
181
  export const typeLabel = (schema: SchemaLike): string => {
168
182
  if (isString(schema.$ref)) {
@@ -170,24 +184,42 @@ export const typeLabel = (schema: SchemaLike): string => {
170
184
  }
171
185
  if (schema.oneOf || schema.anyOf) {
172
186
  const branches = schema.oneOf ?? schema.anyOf ?? [];
173
- const labels = branches.map((branch) => typeLabel(branch));
187
+ const members = branches.filter((branch) => !isNullType(branch));
188
+ if (members.length === 0 && branches.length > 0) {
189
+ return "null";
190
+ }
191
+ const labels = members.map((branch) => typeLabel(branch));
174
192
  return [...new Set(labels)].join(" | ") || "any";
175
193
  }
176
194
  if (schema.allOf) {
177
195
  return "object";
178
196
  }
179
197
  const types = nonNullTypes(schema.type);
198
+ const arrayLabel = (): string => `${typeLabel(schema.items ?? {})}[]`;
199
+ if (types.length > 1) {
200
+ // A 3.1 type array names every type the value may take, not just the first.
201
+ return types
202
+ .map((type) => (type === "array" ? arrayLabel() : type))
203
+ .join(" | ");
204
+ }
180
205
  if (types.includes("array")) {
181
- return `${typeLabel(schema.items ?? {})}[]`;
206
+ return arrayLabel();
207
+ }
208
+ if (types.length === 0 && isNullType(schema)) {
209
+ return "null";
182
210
  }
183
211
  const base = types[0] ?? (schema.properties ? "object" : "any");
184
212
  return schema.format ? `${base}<${schema.format}>` : base;
185
213
  };
186
214
 
187
- /** Whether this schema is nullable (3.0 `nullable` or a 3.1 `"null"` in `type`). */
215
+ /**
216
+ * Whether this schema is nullable: 3.0 `nullable`, a 3.1 `"null"` in `type`,
217
+ * or a `{ type: "null" }` member of a `oneOf`/`anyOf` union.
218
+ */
188
219
  export const isNullable = (schema: SchemaLike): boolean =>
189
220
  schema.nullable === true ||
190
- (Array.isArray(schema.type) && schema.type.includes("null"));
221
+ (Array.isArray(schema.type) && schema.type.includes("null")) ||
222
+ [...(schema.oneOf ?? []), ...(schema.anyOf ?? [])].some(isNullType);
191
223
 
192
224
  /** Human-readable validation constraints for a schema, in display order. */
193
225
  export const constraints = (schema: SchemaLike): string[] => {
@@ -263,23 +295,26 @@ export const objectProperties = (
263
295
  * Build a representative example value for a schema via openapi-sampler
264
296
  * (Redoc's generator): declared `example`/`const`/`default`/`enum` values
265
297
  * win, formats produce realistic placeholders (`email`, `uuid`, `date-time`),
266
- * `readOnly` fields are skipped (these samples illustrate *requests*, and a
267
- * server-generated field has no place in one), and circular `$ref` chains —
268
- * which keeping refs intact allows — terminate safely.
298
+ * and circular `$ref` chains — which keeping refs intact allows — terminate
299
+ * safely. A request sample skips `readOnly` fields (a server-generated field
300
+ * has no place in one); a response sample skips `writeOnly` fields (a
301
+ * password the client sends never comes back) and keeps the `readOnly` ones.
269
302
  */
270
303
  export const exampleValue = (
271
304
  schema: SchemaLike | undefined,
272
- schemas: Record<string, SchemaLike>
305
+ schemas: Record<string, SchemaLike>,
306
+ direction: "request" | "response" = "request"
273
307
  ): SpecValue => {
274
308
  if (!schema) {
275
309
  return null;
276
310
  }
311
+ const response = direction === "response";
277
312
  try {
278
313
  // SAFETY: SchemaLike structurally covers the JSONSchema7 fields the
279
314
  // sampler reads, and the sampler only ever assembles JSON values.
280
315
  return sample(
281
316
  schema as Parameters<typeof sample>[0],
282
- { quiet: true, skipReadOnly: true },
317
+ { quiet: true, skipReadOnly: !response, skipWriteOnly: response },
283
318
  { components: { schemas } }
284
319
  ) as SpecValue;
285
320
  } catch {
@@ -289,5 +324,58 @@ export const exampleValue = (
289
324
  }
290
325
  };
291
326
 
327
+ /** Where an author can declare an example: a parameter or a media type. */
328
+ export interface ExampleCarrier {
329
+ example?: SpecValue;
330
+ examples?: SpecValue;
331
+ }
332
+
333
+ const isRecord = (value: SpecValue): value is Record<string, SpecValue> =>
334
+ typeof value === "object" && value !== null && !Array.isArray(value);
335
+
336
+ /**
337
+ * The example a parameter or media type declares: its `example`, else the
338
+ * first `value` in its `examples` map — inline, or behind a `$ref` to
339
+ * `#/components/examples`, resolved against `components`. Scalar's upgrade
340
+ * moves every OpenAPI 3.0 and Swagger 2.0 `example` into
341
+ * `examples.default.value`, and 3.1 authors write that map directly, so
342
+ * reading `example` alone would drop them all. `undefined` when nothing is
343
+ * declared.
344
+ */
345
+ export const declaredExample = (
346
+ carrier: ExampleCarrier,
347
+ components?: ComponentsLike
348
+ ): SpecValue => {
349
+ if (carrier.example !== undefined) {
350
+ return carrier.example;
351
+ }
352
+ const { examples } = carrier;
353
+ if (!isRecord(examples)) {
354
+ return undefined;
355
+ }
356
+ for (const entry of Object.values(examples)) {
357
+ const example = isRecord(entry)
358
+ ? resolveComponentRef(entry, components, "examples")
359
+ : undefined;
360
+ if (example?.value !== undefined) {
361
+ return example.value;
362
+ }
363
+ }
364
+ return undefined;
365
+ };
366
+
367
+ /**
368
+ * A response media type's example for the Response panel: the declared one,
369
+ * else a sample built for the response direction (`readOnly` kept,
370
+ * `writeOnly` skipped).
371
+ */
372
+ export const responseExample = (
373
+ media: ExampleCarrier & { schema?: SchemaLike },
374
+ schemas: Record<string, SchemaLike>,
375
+ components?: ComponentsLike
376
+ ): SpecValue =>
377
+ declaredExample(media, components) ??
378
+ exampleValue(media.schema, schemas, "response");
379
+
292
380
  /** Pretty-print a JSON value for an example/code block. */
293
381
  export const toJson = <T>(value: T): string => JSON.stringify(value, null, 2);
@@ -171,7 +171,12 @@ export const initComposer = (root: HTMLElement): void => {
171
171
  return;
172
172
  }
173
173
  if (state === "error") {
174
- setStatus(ERROR_MESSAGE, ERROR_TEXT);
174
+ // A detail is the browser refusing the URL before dialing; a failed
175
+ // handshake carries none.
176
+ setStatus(
177
+ detail ? `Couldn't connect: ${detail}` : ERROR_MESSAGE,
178
+ ERROR_TEXT
179
+ );
175
180
  return;
176
181
  }
177
182
  setStatus(
@@ -199,6 +204,14 @@ export const initComposer = (root: HTMLElement): void => {
199
204
 
200
205
  const client = createWsClient({ onFrame: renderFrame, onState: renderState });
201
206
 
207
+ // A ClientRouter navigation swaps this panel out of the document without
208
+ // unloading the page, so a live socket would stay open behind the next page
209
+ // — and coming back and connecting again would open a second one. Every
210
+ // swap replaces the panel, so the first one closes the socket for good.
211
+ document.addEventListener("astro:before-swap", () => client.disconnect(), {
212
+ once: true,
213
+ });
214
+
202
215
  connectButton?.addEventListener("click", () => {
203
216
  if (validatePayload().length > 0) {
204
217
  return;
@@ -2,6 +2,7 @@ import type {
2
2
  AsyncApiAction,
3
3
  AsyncApiServerObject,
4
4
  } from "../../openapi/asyncapi.ts";
5
+ import { withServerDefaults } from "../../openapi/model.ts";
5
6
  import type { AsyncApiMessageLike, NamedMessage } from "./async.ts";
6
7
  import { payloadSchema } from "./async.ts";
7
8
  import { exampleValue, toJson } from "./helpers.ts";
@@ -78,9 +79,18 @@ const messagePayload = (
78
79
  /**
79
80
  * A server's base URL for the picker. Falls back to the bare host when the
80
81
  * spec omits `protocol` — a label is a label, and the snippet builders read
81
- * the server object itself rather than this string.
82
+ * the server object itself rather than this string. Server variables in the
83
+ * host and pathname (`{env}.events.example.com`) resolve to their declared
84
+ * defaults, in the label and in the object the samples and connect URL read.
82
85
  */
83
- const serverOption = (server: AsyncApiServerObject): MessageServerOption => {
86
+ const serverOption = (spec: AsyncApiServerObject): MessageServerOption => {
87
+ const server = { ...spec };
88
+ if (spec.host !== undefined) {
89
+ server.host = withServerDefaults(spec.host, spec.variables);
90
+ }
91
+ if (spec.pathname !== undefined) {
92
+ server.pathname = withServerDefaults(spec.pathname, spec.variables);
93
+ }
84
94
  const host = `${server.host ?? ""}${server.pathname ?? ""}`;
85
95
  return {
86
96
  label: server.protocol ? `${server.protocol}://${host}` : host,
@@ -40,7 +40,10 @@ export interface MessagePayload {
40
40
  export interface MessageServerOption {
41
41
  /** `protocol://host+pathname` — what the reader picks between. */
42
42
  label: string;
43
- /** The spec server, verbatim; the snippet builders read host/pathname/protocol. */
43
+ /**
44
+ * The spec server with its host/pathname variables at their defaults; the
45
+ * snippet builders read host/pathname/protocol.
46
+ */
44
47
  server: AsyncApiServerObject;
45
48
  }
46
49
 
@@ -84,6 +87,17 @@ export const defaultMessageValues = (model: MessageModel): MessageValues => ({
84
87
 
85
88
  const PARAM_TEMPLATE = /\{(?<name>[^{}]+)\}/gu;
86
89
 
90
+ /**
91
+ * Protocols whose channel address is a URL path, where a parameter value must
92
+ * be percent-encoded. Everywhere else — a Kafka or MQTT topic, an AMQP routing
93
+ * key — the address is a name the value goes into as written: `sensor 1`,
94
+ * not `sensor%201`.
95
+ */
96
+ const URL_PROTOCOLS = { http: true, https: true, ws: true } satisfies Record<
97
+ string,
98
+ true
99
+ >;
100
+
87
101
  /**
88
102
  * A free-text base URL lowered onto the server shape the snippet builders and
89
103
  * the connect URL read. A full URL contributes its scheme, host, and path.
@@ -111,7 +125,8 @@ const customServer = (url: string): AsyncApiServerObject => {
111
125
  /**
112
126
  * THE one message builder: the composer's samples, its copy buttons, and the
113
127
  * live WebSocket frame all consume its output. Parameter values are
114
- * URL-encoded into the address; a parameter left blank keeps its `{name}`
128
+ * URL-encoded into the address when the protocol addresses channels by URL
129
+ * (see {@link URL_PROTOCOLS}); a parameter left blank keeps its `{name}`
115
130
  * template so the sample still reads as a template rather than a broken
116
131
  * address. Payload text that doesn't parse yields no payload — the editor is
117
132
  * showing the reader a validation error at that moment, and neither a sample
@@ -123,6 +138,9 @@ export const buildMessage = (
123
138
  ): MessageSample => {
124
139
  const custom = values.customUrl.trim();
125
140
  const picked = model.servers[values.server] ?? model.servers[0];
141
+ const encode = Object.hasOwn(URL_PROTOCOLS, model.protocol ?? "")
142
+ ? encodeURIComponent
143
+ : (value: string) => value;
126
144
  let payload: unknown;
127
145
  try {
128
146
  // SAFETY: JSON.parse returns `any`; widening it to `unknown` claims
@@ -135,7 +153,7 @@ export const buildMessage = (
135
153
  action: model.action,
136
154
  address: model.address.replaceAll(PARAM_TEMPLATE, (template, name) => {
137
155
  const value = values.params[String(name)] ?? "";
138
- return value === "" ? template : encodeURIComponent(value);
156
+ return value === "" ? template : encode(value);
139
157
  }),
140
158
  payload,
141
159
  server: custom === "" ? picked?.server : customServer(custom),