blume 2.1.3 → 2.2.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/AGENTS.md +1 -1
  2. package/CHANGELOG.md +134 -0
  3. package/README.md +4 -4
  4. package/dist/cli/{chunk-y4msrwm9.js → chunk-080mfch6.js} +15 -15
  5. package/dist/cli/{chunk-gfc5fqvf.js → chunk-1ch3ct3r.js} +18 -18
  6. package/dist/cli/{chunk-gfc5fqvf.js.map → chunk-1ch3ct3r.js.map} +1 -1
  7. package/dist/cli/{chunk-32khwcb6.js → chunk-2ssh60qh.js} +42 -69
  8. package/dist/cli/{chunk-32khwcb6.js.map → chunk-2ssh60qh.js.map} +9 -10
  9. package/dist/cli/{chunk-9qzgg6mj.js → chunk-34wap3ed.js} +3 -3
  10. package/dist/cli/{chunk-k3gr1nm9.js → chunk-40vk8kgf.js} +13 -16
  11. package/dist/cli/{chunk-k3gr1nm9.js.map → chunk-40vk8kgf.js.map} +3 -3
  12. package/dist/cli/chunk-487b95qy.js +329 -0
  13. package/dist/cli/chunk-487b95qy.js.map +13 -0
  14. package/dist/cli/chunk-4zxh25hc.js +157 -0
  15. package/dist/cli/chunk-4zxh25hc.js.map +10 -0
  16. package/dist/cli/chunk-69rjf786.js +146 -0
  17. package/dist/cli/chunk-69rjf786.js.map +11 -0
  18. package/dist/cli/{chunk-dqhg54mr.js → chunk-9h8mh2tk.js} +3 -3
  19. package/dist/cli/{chunk-dqhg54mr.js.map → chunk-9h8mh2tk.js.map} +2 -2
  20. package/dist/cli/{chunk-bqxaqn5p.js → chunk-9jqmq5hv.js} +8 -8
  21. package/dist/cli/{chunk-bqxaqn5p.js.map → chunk-9jqmq5hv.js.map} +1 -1
  22. package/dist/cli/{chunk-dv2z0rzf.js → chunk-aafhwx74.js} +38 -13
  23. package/dist/cli/{chunk-dv2z0rzf.js.map → chunk-aafhwx74.js.map} +5 -4
  24. package/dist/cli/{chunk-desvm72z.js → chunk-b680sv30.js} +22 -26
  25. package/dist/cli/chunk-b680sv30.js.map +13 -0
  26. package/dist/cli/{chunk-0w6hs479.js → chunk-beb0z983.js} +30 -18
  27. package/dist/cli/chunk-beb0z983.js.map +10 -0
  28. package/dist/cli/{chunk-1f882900.js → chunk-c5bjxq8v.js} +2 -2
  29. package/dist/cli/chunk-e1n41w9m.js +155 -0
  30. package/dist/cli/chunk-e1n41w9m.js.map +11 -0
  31. package/dist/cli/{chunk-sc93apfs.js → chunk-etckvbrh.js} +17 -17
  32. package/dist/cli/{chunk-sc93apfs.js.map → chunk-etckvbrh.js.map} +2 -2
  33. package/dist/cli/{chunk-bxwhtvw8.js → chunk-f260jdrn.js} +5 -5
  34. package/dist/cli/{chunk-74wfhv79.js → chunk-fnxgtjeq.js} +1 -1
  35. package/dist/cli/{chunk-ms9z66nz.js → chunk-gwy55cx3.js} +2 -2
  36. package/dist/cli/{chunk-ms9z66nz.js.map → chunk-gwy55cx3.js.map} +2 -2
  37. package/dist/cli/{chunk-dhwtqnnd.js → chunk-gxhcf2hs.js} +2 -2
  38. package/dist/cli/{chunk-tfycddbt.js → chunk-h0qwdbem.js} +2 -2
  39. package/dist/cli/{chunk-nbyvgnnm.js → chunk-hktq4j5r.js} +109 -49
  40. package/dist/cli/chunk-hktq4j5r.js.map +36 -0
  41. package/dist/cli/{chunk-twy7psdz.js → chunk-hn3g2b89.js} +14 -10
  42. package/dist/cli/chunk-hn3g2b89.js.map +10 -0
  43. package/dist/cli/{chunk-j1x92mx9.js → chunk-j4nfgn2j.js} +1 -1
  44. package/dist/cli/{chunk-dpy8qdjf.js → chunk-k45sq16q.js} +74 -183
  45. package/dist/cli/chunk-k45sq16q.js.map +18 -0
  46. package/dist/cli/{chunk-5cmts6dv.js → chunk-kmswjxj9.js} +7 -7
  47. package/dist/cli/{chunk-5cmts6dv.js.map → chunk-kmswjxj9.js.map} +1 -1
  48. package/dist/cli/{chunk-36bxs9c7.js → chunk-nqna8dzp.js} +27 -23
  49. package/dist/cli/chunk-nqna8dzp.js.map +10 -0
  50. package/dist/cli/{chunk-a57yh0h9.js → chunk-p834rkcn.js} +7 -7
  51. package/dist/cli/{chunk-a57yh0h9.js.map → chunk-p834rkcn.js.map} +1 -1
  52. package/dist/cli/{chunk-60hz265r.js → chunk-ppa6mg4d.js} +24 -11
  53. package/dist/cli/chunk-ppa6mg4d.js.map +10 -0
  54. package/dist/cli/{chunk-s0bdnc7v.js → chunk-q1wwrxzw.js} +5 -4
  55. package/dist/cli/chunk-q1wwrxzw.js.map +10 -0
  56. package/dist/cli/{chunk-ave1wcbr.js → chunk-qcyxkj44.js} +1 -1
  57. package/dist/cli/{chunk-124fvmzq.js → chunk-r5nm9w0c.js} +11183 -8806
  58. package/dist/cli/{chunk-124fvmzq.js.map → chunk-r5nm9w0c.js.map} +82 -66
  59. package/dist/cli/{chunk-ckrcm08h.js → chunk-rtvgmg2j.js} +48 -62
  60. package/dist/cli/{chunk-ckrcm08h.js.map → chunk-rtvgmg2j.js.map} +4 -5
  61. package/dist/cli/{chunk-297ajdcv.js → chunk-t2h8pwy1.js} +6 -6
  62. package/dist/cli/{chunk-297ajdcv.js.map → chunk-t2h8pwy1.js.map} +3 -3
  63. package/dist/cli/{chunk-gxtg6ed2.js → chunk-x60e15st.js} +21 -21
  64. package/dist/cli/{chunk-gxtg6ed2.js.map → chunk-x60e15st.js.map} +3 -3
  65. package/dist/cli/{chunk-58bt3hag.js → chunk-x7bh6d9j.js} +4 -4
  66. package/dist/cli/{chunk-hvcxng5f.js → chunk-ydqzkhjn.js} +6 -6
  67. package/dist/cli/{chunk-kdpzw38a.js → chunk-yg8ckc3g.js} +95 -7
  68. package/dist/cli/chunk-yg8ckc3g.js.map +11 -0
  69. package/dist/cli/{chunk-0pmb4tr4.js → chunk-zxd5jrgx.js} +1205 -222
  70. package/dist/cli/chunk-zxd5jrgx.js.map +44 -0
  71. package/dist/cli/index.js +78 -42
  72. package/dist/cli/index.js.map +7 -6
  73. package/dist/types/ai/changelog-components.d.ts +18 -0
  74. package/dist/types/ai/changelog-markdown.d.ts +12 -0
  75. package/dist/types/ai/openapi-components.d.ts +7 -7
  76. package/dist/types/ai/operation-details.d.ts +39 -0
  77. package/dist/types/ai/relative-links.d.ts +3 -1
  78. package/dist/types/ai/serializers.d.ts +6 -4
  79. package/dist/types/analytics/head.d.ts +4 -2
  80. package/dist/types/analytics/script.d.ts +8 -2
  81. package/dist/types/components/content/youtube.d.ts +20 -0
  82. package/dist/types/components/layout/nav-utils.d.ts +8 -0
  83. package/dist/types/components/openapi/example-panels.d.ts +33 -0
  84. package/dist/types/components/openapi/helpers.d.ts +53 -11
  85. package/dist/types/components/openapi/snippets.d.ts +7 -1
  86. package/dist/types/core/alert-diagnostics.d.ts +10 -0
  87. package/dist/types/core/builtin-tags.d.ts +16 -0
  88. package/dist/types/core/changelog-list.d.ts +48 -0
  89. package/dist/types/core/closest-match.d.ts +6 -0
  90. package/dist/types/core/code-fence-diagnostics.d.ts +18 -0
  91. package/dist/types/core/code-fences.d.ts +8 -1
  92. package/dist/types/core/config-input.d.ts +38 -6
  93. package/dist/types/core/content-assets.d.ts +16 -18
  94. package/dist/types/core/data.d.ts +6 -2
  95. package/dist/types/core/diagnostics.d.ts +14 -0
  96. package/dist/types/core/directive-diagnostics.d.ts +22 -8
  97. package/dist/types/core/former-routes.d.ts +14 -0
  98. package/dist/types/core/github.d.ts +5 -4
  99. package/dist/types/core/heading-markers.d.ts +65 -2
  100. package/dist/types/core/hidden-pages.d.ts +3 -0
  101. package/dist/types/core/includes.d.ts +23 -0
  102. package/dist/types/core/last-modified.d.ts +18 -6
  103. package/dist/types/core/links.d.ts +42 -2
  104. package/dist/types/core/load-module.d.ts +19 -4
  105. package/dist/types/core/manifest.d.ts +14 -1
  106. package/dist/types/core/markdown-mirrors.d.ts +22 -0
  107. package/dist/types/core/mcp-clients.d.ts +47 -0
  108. package/dist/types/core/mdx-elements.d.ts +32 -0
  109. package/dist/types/core/mdx-syntax.d.ts +100 -0
  110. package/dist/types/core/meta-diagnostics.d.ts +7 -0
  111. package/dist/types/core/meta.d.ts +32 -5
  112. package/dist/types/core/nav-diagnostics.d.ts +16 -2
  113. package/dist/types/core/navigation.d.ts +13 -0
  114. package/dist/types/core/ordering-prefix.d.ts +6 -0
  115. package/dist/types/core/pinned-ids.d.ts +23 -0
  116. package/dist/types/core/project-graph.d.ts +9 -1
  117. package/dist/types/core/redirect-patterns.d.ts +18 -0
  118. package/dist/types/core/relative-files.d.ts +31 -0
  119. package/dist/types/core/schema.d.ts +322 -11
  120. package/dist/types/core/sources/normalize.d.ts +101 -9
  121. package/dist/types/core/sources/types.d.ts +16 -0
  122. package/dist/types/core/static-files.d.ts +10 -0
  123. package/dist/types/core/static-host.d.ts +42 -0
  124. package/dist/types/core/svg-images.d.ts +26 -0
  125. package/dist/types/core/syntax-diagnostics.d.ts +14 -0
  126. package/dist/types/core/types.d.ts +42 -1
  127. package/dist/types/deploy/generated-files.d.ts +41 -0
  128. package/dist/types/deploy/redirects.d.ts +21 -7
  129. package/dist/types/markdown/code-title.d.ts +9 -5
  130. package/dist/types/markdown/directives.d.ts +8 -0
  131. package/dist/types/markdown/fence-language.d.ts +51 -0
  132. package/dist/types/markdown/fence-meta.d.ts +5 -0
  133. package/dist/types/markdown/github-alerts.d.ts +35 -0
  134. package/dist/types/openapi/asyncapi.d.ts +6 -5
  135. package/dist/types/openapi/checks.d.ts +10 -5
  136. package/dist/types/openapi/model.d.ts +55 -8
  137. package/dist/types/openapi/parse.d.ts +4 -1
  138. package/dist/types/ratelimit/index.d.ts +2 -0
  139. package/dist/types/ratelimit/memory.d.ts +1 -1
  140. package/dist/types/ratelimit/schema.d.ts +40 -0
  141. package/dist/types/ratelimit/unkey.d.ts +48 -0
  142. package/dist/types/sources/filesystem.d.ts +14 -4
  143. package/dist/types/sources/mdx-remote.d.ts +6 -3
  144. package/dist/types/sources/registry.d.ts +3 -3
  145. package/dist/types/theme/color.d.ts +33 -0
  146. package/dist/types/theme/palette.d.ts +122 -0
  147. package/docs/01-quickstart.mdx +1 -1
  148. package/docs/02-deployment.mdx +24 -8
  149. package/docs/04-migrating.mdx +16 -4
  150. package/docs/advanced/changelog.mdx +27 -1
  151. package/docs/advanced/skills.mdx +1 -1
  152. package/docs/cli/audit.mdx +1 -1
  153. package/docs/cli/doctor.mdx +2 -2
  154. package/docs/cli/evals.mdx +1 -1
  155. package/docs/cli/index.mdx +4 -2
  156. package/docs/cli/validate.mdx +10 -7
  157. package/docs/configuration/analytics.mdx +2 -0
  158. package/docs/configuration/customization.mdx +3 -1
  159. package/docs/configuration/index.mdx +7 -6
  160. package/docs/configuration/rate-limiting.mdx +20 -1
  161. package/docs/configuration/theming.mdx +5 -1
  162. package/docs/content/components.mdx +26 -6
  163. package/docs/content/frontmatter.mdx +1 -1
  164. package/docs/content/i18n.mdx +1 -1
  165. package/docs/content/includes.mdx +6 -2
  166. package/docs/content/index.mdx +11 -1
  167. package/docs/content/islands.mdx +2 -0
  168. package/docs/content/meta.mdx +9 -3
  169. package/docs/content/navigation.mdx +14 -6
  170. package/docs/content/sources/obsidian.mdx +1 -1
  171. package/docs/content/sources/remote-mdx.mdx +3 -1
  172. package/docs/content/syntax.mdx +76 -8
  173. package/docs/content/variables.mdx +3 -1
  174. package/docs/discoverability/agent-discovery.mdx +1 -1
  175. package/docs/discoverability/json-api.mdx +1 -1
  176. package/docs/discoverability/llms-txt.mdx +1 -1
  177. package/docs/discoverability/markdown.mdx +2 -2
  178. package/docs/discoverability/mcp.mdx +40 -8
  179. package/docs/discoverability/open-graph.mdx +1 -1
  180. package/docs/discoverability/sitemap-and-robots.mdx +1 -1
  181. package/docs/references/graphql.mdx +2 -0
  182. package/docs/references/openapi.mdx +45 -7
  183. package/package.json +4 -4
  184. package/skills/blume/SKILL.md +2 -2
  185. package/skills/blume-migrate/SKILL.md +51 -29
  186. package/skills/blume-migrate/references/docsify.md +262 -0
  187. package/skills/blume-migrate/references/docus.md +298 -0
  188. package/skills/blume-migrate/references/docusaurus.md +5 -5
  189. package/skills/blume-migrate/references/fern.md +327 -0
  190. package/skills/blume-migrate/references/fumadocs.md +1 -1
  191. package/skills/blume-migrate/references/gitbook.md +267 -0
  192. package/skills/blume-migrate/references/github-wiki.md +259 -0
  193. package/skills/blume-migrate/references/jekyll.md +253 -0
  194. package/skills/blume-migrate/references/mdbook.md +256 -0
  195. package/skills/blume-migrate/references/mintlify.md +5 -5
  196. package/skills/blume-migrate/references/mkdocs.md +236 -0
  197. package/skills/blume-migrate/references/monorepo.md +20 -8
  198. package/skills/blume-migrate/references/nextra.md +5 -5
  199. package/skills/blume-migrate/references/readme.md +257 -0
  200. package/skills/blume-migrate/references/redocly.md +198 -0
  201. package/skills/blume-migrate/references/starlight.md +3 -3
  202. package/skills/blume-migrate/references/vitepress.md +204 -0
  203. package/skills/blume-migrate/references/vuepress.md +271 -0
  204. package/skills/blume-migrate/scripts/docsify-codemod.mjs +2387 -0
  205. package/skills/blume-migrate/scripts/docus-codemod.mjs +2542 -0
  206. package/skills/blume-migrate/scripts/fern-codemod.mjs +2633 -0
  207. package/skills/blume-migrate/scripts/github-wiki-codemod.mjs +2808 -0
  208. package/skills/blume-migrate/scripts/include-excerpts.mjs +649 -0
  209. package/skills/blume-migrate/scripts/jekyll-codemod.mjs +3649 -0
  210. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +17 -13
  211. package/skills/blume-migrate/scripts/mkdocs-codemod.mjs +2526 -0
  212. package/skills/blume-migrate/scripts/operation-routes.mjs +508 -0
  213. package/skills/blume-migrate/scripts/pin-heading-ids.mjs +1049 -0
  214. package/skills/blume-migrate/scripts/readme-codemod.mjs +4139 -0
  215. package/skills/blume-migrate/scripts/vitepress-codemod.mjs +1511 -0
  216. package/src/ai/changelog-components.ts +24 -0
  217. package/src/ai/changelog-markdown.ts +45 -41
  218. package/src/ai/component-markdown.ts +22 -9
  219. package/src/ai/llms.ts +36 -5
  220. package/src/ai/markdown.ts +2 -2
  221. package/src/ai/openapi-components.ts +25 -9
  222. package/src/ai/operation-details.ts +208 -0
  223. package/src/ai/relative-links.ts +48 -8
  224. package/src/ai/serializers.ts +7 -6
  225. package/src/ai/site-skill.ts +6 -2
  226. package/src/analytics/head.ts +11 -5
  227. package/src/analytics/script.ts +13 -3
  228. package/src/astro/generate.ts +47 -11
  229. package/src/astro/index.ts +1 -0
  230. package/src/astro/integration.ts +27 -1
  231. package/src/astro/mdx-source-errors.ts +46 -0
  232. package/src/astro/templates.ts +93 -189
  233. package/src/audit/checks/redirects.ts +5 -1
  234. package/src/audit/redirects.ts +36 -19
  235. package/src/audit/report.ts +22 -9
  236. package/src/audit/run.ts +12 -28
  237. package/src/audit/terms.ts +23 -0
  238. package/src/audit/url.ts +2 -2
  239. package/src/cli/build-failure.ts +256 -7
  240. package/src/cli/command-meta.ts +1 -1
  241. package/src/cli/commands/audit.ts +1 -1
  242. package/src/cli/commands/build.ts +12 -3
  243. package/src/cli/commands/check.ts +13 -2
  244. package/src/cli/commands/dev.ts +1 -1
  245. package/src/cli/commands/doctor.ts +4 -2
  246. package/src/cli/commands/init.ts +3 -3
  247. package/src/cli/commands/preview.ts +17 -1
  248. package/src/cli/commands/validate.ts +22 -10
  249. package/src/cli/prepare.ts +1 -1
  250. package/src/cli/preview-pages.ts +161 -0
  251. package/src/cli/required-secrets.ts +0 -1
  252. package/src/cli/unknown-flags.ts +1 -42
  253. package/src/components/code-copy.ts +51 -0
  254. package/src/components/code-language.ts +75 -0
  255. package/src/components/content/AccordionItem.astro +16 -1
  256. package/src/components/content/Callout.astro +11 -1
  257. package/src/components/content/Changelog.astro +189 -0
  258. package/src/components/content/CodeBlock.astro +8 -11
  259. package/src/components/content/Tabs.astro +16 -2
  260. package/src/components/content/YouTube.astro +6 -4
  261. package/src/components/content/code-block.ts +33 -0
  262. package/src/components/content/content-strings.ts +5 -1
  263. package/src/components/content/inline-markdown.ts +35 -8
  264. package/src/components/content/youtube.ts +49 -7
  265. package/src/components/layout/Analytics.astro +5 -1
  266. package/src/components/layout/NavTree.astro +8 -3
  267. package/src/components/layout/PageActions.astro +81 -23
  268. package/src/components/layout/RootLayout.astro +35 -32
  269. package/src/components/layout/SiteFooter.astro +31 -8
  270. package/src/components/layout/nav-utils.ts +14 -0
  271. package/src/components/layout/search/pagefind.ts +2 -1
  272. package/src/components/openapi/Operation.astro +4 -0
  273. package/src/components/openapi/PanelTabs.astro +9 -3
  274. package/src/components/openapi/RequestBody.astro +42 -8
  275. package/src/components/openapi/RequestPanel.astro +34 -53
  276. package/src/components/openapi/example-panels.ts +110 -0
  277. package/src/components/openapi/helpers.ts +195 -20
  278. package/src/components/openapi/operation-model.ts +63 -26
  279. package/src/components/openapi/request.ts +13 -0
  280. package/src/components/openapi/snippets.ts +14 -2
  281. package/src/core/alert-diagnostics.ts +89 -0
  282. package/src/core/builtin-tags.ts +76 -0
  283. package/src/core/changelog-list.ts +87 -0
  284. package/src/core/closest-match.ts +41 -0
  285. package/src/core/code-fence-diagnostics.ts +267 -0
  286. package/src/core/code-fences.ts +43 -7
  287. package/src/core/component-diagnostics.ts +65 -12
  288. package/src/core/config-input.ts +39 -5
  289. package/src/core/config.ts +46 -1
  290. package/src/core/content-assets.ts +64 -144
  291. package/src/core/data.ts +10 -3
  292. package/src/core/diagnostics.ts +36 -3
  293. package/src/core/directive-diagnostics.ts +265 -47
  294. package/src/core/former-routes.ts +46 -0
  295. package/src/core/git-ignored.ts +53 -0
  296. package/src/core/github.ts +5 -4
  297. package/src/core/heading-markers.ts +156 -2
  298. package/src/core/hidden-pages.ts +64 -0
  299. package/src/core/includes.ts +181 -41
  300. package/src/core/last-modified.ts +47 -10
  301. package/src/core/links.ts +438 -83
  302. package/src/core/load-module.ts +98 -9
  303. package/src/core/manifest.ts +12 -9
  304. package/src/core/markdown-mirrors.ts +52 -0
  305. package/src/core/mcp-clients.ts +87 -0
  306. package/src/core/mdx-elements.ts +153 -0
  307. package/src/core/mdx-syntax.ts +377 -0
  308. package/src/core/meta-diagnostics.ts +134 -0
  309. package/src/core/meta.ts +154 -55
  310. package/src/core/nav-diagnostics.ts +41 -4
  311. package/src/core/navigation.ts +70 -10
  312. package/src/core/ordering-prefix.ts +22 -2
  313. package/src/core/pinned-ids.ts +141 -0
  314. package/src/core/project-graph.ts +221 -29
  315. package/src/core/redirect-patterns.ts +41 -0
  316. package/src/core/relative-files.ts +145 -0
  317. package/src/core/schema.ts +110 -6
  318. package/src/core/sources/mdx-remote.ts +75 -14
  319. package/src/core/sources/normalize.ts +885 -179
  320. package/src/core/sources/notion.ts +5 -4
  321. package/src/core/sources/obsidian.ts +2 -5
  322. package/src/core/sources/types.ts +17 -0
  323. package/src/core/static-files.ts +40 -0
  324. package/src/core/static-host.ts +125 -0
  325. package/src/core/svg-images.ts +98 -0
  326. package/src/core/syntax-diagnostics.ts +491 -0
  327. package/src/core/types.ts +43 -1
  328. package/src/deploy/artifacts.ts +2 -28
  329. package/src/deploy/generated-files.ts +128 -0
  330. package/src/deploy/platforms/vercel.ts +25 -1
  331. package/src/deploy/redirects.ts +43 -16
  332. package/src/deploy/sitemap.ts +2 -1
  333. package/src/markdown/base-links.ts +87 -6
  334. package/src/markdown/code-title.ts +29 -13
  335. package/src/markdown/content-assets.ts +210 -0
  336. package/src/markdown/directives.ts +69 -5
  337. package/src/markdown/fence-language.ts +106 -0
  338. package/src/markdown/fence-meta.ts +42 -0
  339. package/src/markdown/github-alerts.ts +172 -0
  340. package/src/markdown/heading-anchors.ts +265 -56
  341. package/src/markdown/include.ts +30 -3
  342. package/src/markdown/index.ts +145 -40
  343. package/src/markdown/prompt-text.ts +95 -0
  344. package/src/markdown/relative-links.ts +37 -2
  345. package/src/markdown/route-snapshot.ts +22 -12
  346. package/src/markdown/svg-fallback.ts +51 -0
  347. package/src/markdown/title-heading.ts +134 -0
  348. package/src/migrate/migrate.ts +127 -2
  349. package/src/og/card.ts +14 -4
  350. package/src/openapi/asyncapi.ts +14 -6
  351. package/src/openapi/checks.ts +160 -15
  352. package/src/openapi/model.ts +172 -33
  353. package/src/openapi/parse.ts +13 -4
  354. package/src/openapi/render-mdx.ts +55 -9
  355. package/src/openapi/source.ts +87 -6
  356. package/src/ratelimit/index.ts +2 -0
  357. package/src/ratelimit/memory.ts +1 -1
  358. package/src/ratelimit/runtime.ts +81 -0
  359. package/src/ratelimit/schema.ts +2 -0
  360. package/src/ratelimit/unkey.ts +61 -0
  361. package/src/registry/eject.ts +0 -1
  362. package/src/registry/registry.ts +1 -1
  363. package/src/search/documents.ts +10 -2
  364. package/src/sources/filesystem.ts +28 -3
  365. package/src/sources/mdx-remote.ts +7 -15
  366. package/src/theme/color.ts +14 -0
  367. package/src/theme/entry.ts +22 -1
  368. package/src/theme/palette.ts +74 -1
  369. package/dist/cli/chunk-0pmb4tr4.js.map +0 -35
  370. package/dist/cli/chunk-0w6hs479.js.map +0 -10
  371. package/dist/cli/chunk-150jk7km.js +0 -52
  372. package/dist/cli/chunk-150jk7km.js.map +0 -10
  373. package/dist/cli/chunk-36bxs9c7.js.map +0 -10
  374. package/dist/cli/chunk-53jqw8z0.js +0 -89
  375. package/dist/cli/chunk-53jqw8z0.js.map +0 -10
  376. package/dist/cli/chunk-60hz265r.js.map +0 -10
  377. package/dist/cli/chunk-desvm72z.js.map +0 -14
  378. package/dist/cli/chunk-dpy8qdjf.js.map +0 -17
  379. package/dist/cli/chunk-es8h0v3j.js +0 -441
  380. package/dist/cli/chunk-es8h0v3j.js.map +0 -11
  381. package/dist/cli/chunk-kdpzw38a.js.map +0 -11
  382. package/dist/cli/chunk-nbyvgnnm.js.map +0 -36
  383. package/dist/cli/chunk-s0bdnc7v.js.map +0 -10
  384. package/dist/cli/chunk-twy7psdz.js.map +0 -10
  385. package/dist/cli/chunk-ydp3065p.js +0 -64
  386. package/dist/cli/chunk-ydp3065p.js.map +0 -10
  387. /package/dist/cli/{chunk-y4msrwm9.js.map → chunk-080mfch6.js.map} +0 -0
  388. /package/dist/cli/{chunk-9qzgg6mj.js.map → chunk-34wap3ed.js.map} +0 -0
  389. /package/dist/cli/{chunk-1f882900.js.map → chunk-c5bjxq8v.js.map} +0 -0
  390. /package/dist/cli/{chunk-bxwhtvw8.js.map → chunk-f260jdrn.js.map} +0 -0
  391. /package/dist/cli/{chunk-74wfhv79.js.map → chunk-fnxgtjeq.js.map} +0 -0
  392. /package/dist/cli/{chunk-dhwtqnnd.js.map → chunk-gxhcf2hs.js.map} +0 -0
  393. /package/dist/cli/{chunk-tfycddbt.js.map → chunk-h0qwdbem.js.map} +0 -0
  394. /package/dist/cli/{chunk-j1x92mx9.js.map → chunk-j4nfgn2j.js.map} +0 -0
  395. /package/dist/cli/{chunk-ave1wcbr.js.map → chunk-qcyxkj44.js.map} +0 -0
  396. /package/dist/cli/{chunk-58bt3hag.js.map → chunk-x7bh6d9j.js.map} +0 -0
  397. /package/dist/cli/{chunk-hvcxng5f.js.map → chunk-ydqzkhjn.js.map} +0 -0
@@ -3,7 +3,7 @@ import { setTimeout as sleep } from "node:timers/promises";
3
3
  import pLimit from "p-limit";
4
4
  import { join } from "pathe";
5
5
 
6
- import { parseYouTubeId } from "../../components/content/youtube.ts";
6
+ import { youtubeEmbedSrc } from "../../components/content/youtube.ts";
7
7
  import { BlumeError } from "../diagnostics.ts";
8
8
  import matter from "../frontmatter.ts";
9
9
  import { nodeRequire } from "../node-require.ts";
@@ -316,12 +316,13 @@ const FRAME_ESCAPED = /\\(?=[<>])/gu;
316
316
 
317
317
  const YOUTUBE_HOST = /(?:^|\.)(?:youtube(?:-nocookie)?\.com|youtu\.be)$/u;
318
318
 
319
- // `parseYouTubeId` is host-agnostic on purpose (the component accepts bare
319
+ // `youtubeEmbedSrc` is host-agnostic on purpose (the component accepts bare
320
320
  // ids), so gate on the hostname first: `https://cdn.example.com/live/promo.mp4`
321
- // matches its `/live/<11 chars>` shape but is a media file, not an embed.
321
+ // matches its `/live/<11 chars>` shape but is a media file, not an embed. A
322
+ // playlist URL embeds too.
322
323
  const isYouTubeUrl = (url: string): boolean => {
323
324
  const host = URL.parse(url)?.hostname ?? "";
324
- return YOUTUBE_HOST.test(host) && parseYouTubeId(url) !== null;
325
+ return YOUTUBE_HOST.test(host) && youtubeEmbedSrc(url) !== null;
325
326
  };
326
327
 
327
328
  /**
@@ -9,7 +9,7 @@ import { nextFenceState } from "../code-fences.ts";
9
9
  import type { FenceState } from "../code-fences.ts";
10
10
  import { BlumeError } from "../diagnostics.ts";
11
11
  import matter from "../frontmatter.ts";
12
- import { pageMetaSchema } from "../schema.ts";
12
+ import { BUILT_IN_PAGE_META_KEYS } from "../schema.ts";
13
13
  import type { ResolvedI18nConfig, ResolvedVersionsConfig } from "../schema.ts";
14
14
  import type { Diagnostic } from "../types.ts";
15
15
  import { hashText } from "./cache.ts";
@@ -139,9 +139,6 @@ const OBSIDIAN_NATIVE_KEYS = new Set([
139
139
  "tags",
140
140
  ]);
141
141
 
142
- /** Every key Blume's page meta schema accepts. */
143
- const PAGE_META_KEYS = new Set<string>(pageMetaSchema.keyof().options);
144
-
145
142
  /**
146
143
  * A note's route input: its locale- and version-stripped path, slugged. Vault
147
144
  * filenames are prose (`Getting Started.md`) and the route mapper does not
@@ -759,7 +756,7 @@ const noteToEntry = (
759
756
  Object.entries(note.data).filter(
760
757
  ([key]) =>
761
758
  !OBSIDIAN_NATIVE_KEYS.has(key) &&
762
- (PAGE_META_KEYS.has(key) || keep.has(key))
759
+ (BUILT_IN_PAGE_META_KEYS.has(key) || keep.has(key))
763
760
  )
764
761
  );
765
762
  const merged = title === undefined ? data : { ...data, title };
@@ -67,6 +67,16 @@ export interface SourceEntry {
67
67
  };
68
68
  }
69
69
 
70
+ /**
71
+ * A redirect a source asks for: from a route one of its pages used to have
72
+ * to the route it has now, both locale-stripped and without `basePath`, as
73
+ * the page routes its entries map to.
74
+ */
75
+ export interface SourceRedirect {
76
+ from: string;
77
+ to: string;
78
+ }
79
+
70
80
  /** The result of a single `ContentSource.load()` call. */
71
81
  export interface SourceLoadResult {
72
82
  entries: SourceEntry[];
@@ -80,6 +90,13 @@ export interface SourceLoadResult {
80
90
  * beneath user-authored meta files, which always win.
81
91
  */
82
92
  folderMeta?: Record<string, FolderMeta>;
93
+ /**
94
+ * Redirects from routes the source's pages moved off: the OpenAPI source
95
+ * keeps the URLs earlier releases gave operation pages working. Added to
96
+ * the config's `redirects` after them, skipping any whose `from` a page or
97
+ * a configured redirect already owns.
98
+ */
99
+ redirects?: SourceRedirect[];
83
100
  }
84
101
 
85
102
  /**
@@ -0,0 +1,40 @@
1
+ import { statSync } from "node:fs";
2
+
3
+ import { join } from "pathe";
4
+
5
+ /**
6
+ * Whether a root-relative path names a file the site serves outside its pages,
7
+ * as a static host answers it: a file in `public/`, a `public/` folder's
8
+ * `index.html` (`/demo` and `/demo/` for `public/demo/index.html`), or one of
9
+ * the files Blume generates (`generated`, base-less paths like `/llms.txt`;
10
+ * see `deploy/generated-files.ts`). `publicDir` is `null` when the project has
11
+ * no `public/` folder, which ships no files then. Paths come decoded, without
12
+ * `deployment.base`, which a host mounts `public/` under.
13
+ */
14
+ export const staticFileResolver = (
15
+ publicDir: string | null,
16
+ generated: Iterable<string> = []
17
+ ): ((path: string) => boolean) => {
18
+ const files = new Set(generated);
19
+ return (path) => {
20
+ const folder = path.endsWith("/");
21
+ const trimmed = folder ? path.slice(0, -1) : path;
22
+ if (files.has(trimmed)) {
23
+ return true;
24
+ }
25
+ if (publicDir === null) {
26
+ return false;
27
+ }
28
+ const target = join(publicDir, trimmed);
29
+ const stat = statSync(target, { throwIfNoEntry: false });
30
+ if (stat?.isDirectory()) {
31
+ return (
32
+ statSync(join(target, "index.html"), {
33
+ throwIfNoEntry: false,
34
+ })?.isFile() === true
35
+ );
36
+ }
37
+ // A host answers `/spec.pdf/` with a 404: only a folder takes the slash.
38
+ return !folder && stat?.isFile() === true;
39
+ };
40
+ };
@@ -0,0 +1,125 @@
1
+ /**
2
+ * What a static host does with the URLs `blume dev` and `blume preview`
3
+ * would otherwise answer on their own terms. Astro's `trailingSlash: "never"`
4
+ * has both 404 a slashed URL (`/guide/`), which every host answers: Vercel
5
+ * redirects it to `/guide`, and the others serve `guide/index.html`. And a
6
+ * folder of HTML shipped in `public/` (`public/demo/index.html`) is served at
7
+ * `/demo/`, `/demo` redirecting there, so the relative links inside it
8
+ * resolve against the folder; the dev server 404s both spellings, and Vite's
9
+ * preview serves only the slashless one.
10
+ */
11
+
12
+ import { statSync } from "node:fs";
13
+ import type { IncomingMessage, Server, ServerResponse } from "node:http";
14
+
15
+ import { join, resolve } from "pathe";
16
+
17
+ import { stripBasePath } from "./base-path.ts";
18
+ import { trimEnd } from "./trim.ts";
19
+
20
+ /** How to answer a request ahead of the server's own handlers. */
21
+ export type HostAnswer =
22
+ | { kind: "redirect"; location: string; status: number }
23
+ | { kind: "rewrite"; url: string };
24
+
25
+ /**
26
+ * The paths Astro keeps out of its trailing-slash handling (`/_astro/`,
27
+ * `/@vite/`, `/.well-known/`, `//`), and the root.
28
+ */
29
+ const UNHANDLED_PATH = /^\/(?:[_@./]|$)/u;
30
+
31
+ /** A request URL's path and its query string, `?` included. */
32
+ const splitUrl = (url: string): { pathname: string; search: string } => {
33
+ const queryAt = url.search(/[?#]/u);
34
+ return queryAt === -1
35
+ ? { pathname: url, search: "" }
36
+ : { pathname: url.slice(0, queryAt), search: url.slice(queryAt) };
37
+ };
38
+
39
+ /**
40
+ * Whether `public/<path>/index.html` exists: a folder of HTML the site ships
41
+ * as is. `path` is the decoded request path with `deployment.base` stripped.
42
+ */
43
+ export const publicFolder = (publicDir: string) => {
44
+ const root = resolve(publicDir);
45
+ return (path: string): boolean => {
46
+ const index = join(root, path, "index.html");
47
+ if (!index.startsWith(`${root}/`)) {
48
+ return false;
49
+ }
50
+ try {
51
+ return statSync(index).isFile();
52
+ } catch {
53
+ return false;
54
+ }
55
+ };
56
+ };
57
+
58
+ /**
59
+ * How a static host answers a URL's trailing slash, or null to leave the
60
+ * request alone. A slashed URL redirects to its slashless page, its query
61
+ * kept, unless it names a public folder, which serves its `index.html`; a
62
+ * slashless public folder redirects to its slashed URL. `base` is the
63
+ * normalized `deployment.base`, which the URL carries and `public/` doesn't.
64
+ * The redirect is a `301`, a `308` for a method a `301` would turn into a
65
+ * `GET`, as Astro answers on a server-rendered route.
66
+ */
67
+ export const trailingSlashAnswer = (
68
+ request: Pick<IncomingMessage, "method" | "url">,
69
+ base: string,
70
+ isPublicFolder: (path: string) => boolean
71
+ ): HostAnswer | null => {
72
+ const { pathname, search } = splitUrl(request.url ?? "/");
73
+ if (UNHANDLED_PATH.test(pathname)) {
74
+ return null;
75
+ }
76
+ let path: string;
77
+ try {
78
+ path = decodeURIComponent(stripBasePath(base, pathname));
79
+ } catch {
80
+ return null;
81
+ }
82
+ const status =
83
+ request.method === "GET" || request.method === "HEAD" ? 301 : 308;
84
+ if (!pathname.endsWith("/")) {
85
+ return isPublicFolder(path)
86
+ ? { kind: "redirect", location: `${pathname}/${search}`, status }
87
+ : null;
88
+ }
89
+ const slashless = trimEnd(pathname, "/");
90
+ return isPublicFolder(trimEnd(path, "/"))
91
+ ? { kind: "rewrite", url: `${slashless}/index.html${search}` }
92
+ : { kind: "redirect", location: `${slashless}${search}`, status };
93
+ };
94
+
95
+ /**
96
+ * Answer every request on `server` with `answer` first: a redirect is sent
97
+ * then and there, and a rewrite changes the URL the server's own handlers
98
+ * (Vite's middleware) then see. They're the request listeners the server
99
+ * already has, so this goes ahead of every middleware, Astro's included.
100
+ */
101
+ export const answerRequestsFirst = (
102
+ server: Server,
103
+ answer: (request: IncomingMessage) => HostAnswer | null,
104
+ headers: Record<string, string> = {}
105
+ ): void => {
106
+ const handlers = server.listeners("request");
107
+ server.removeAllListeners("request");
108
+ server.on("request", (request: IncomingMessage, response: ServerResponse) => {
109
+ const answered = answer(request);
110
+ if (answered?.kind === "redirect") {
111
+ response.writeHead(answered.status, {
112
+ ...headers,
113
+ Location: answered.location,
114
+ });
115
+ response.end();
116
+ return;
117
+ }
118
+ if (answered) {
119
+ request.url = answered.url;
120
+ }
121
+ for (const handler of handlers) {
122
+ handler.call(server, request, response);
123
+ }
124
+ });
125
+ };
@@ -0,0 +1,98 @@
1
+ import { readFile } from "node:fs/promises";
2
+
3
+ import { imageMetadata } from "astro/assets/utils";
4
+ import { dirname, extname } from "pathe";
5
+
6
+ import { contentAssetParam, contentAssetUrl } from "./content-assets.ts";
7
+ import { resolveRelativeImage } from "./relative-files.ts";
8
+ import type { Diagnostic, PageRecord } from "./types.ts";
9
+
10
+ /**
11
+ * Colocated SVGs Astro's image pipeline can't measure. Astro reads an image's
12
+ * size before it optimizes it, and for an SVG it looks for the `<svg>` tag in
13
+ * the file's first 1,000 bytes only, then needs a width and height or a
14
+ * viewBox on that tag. A draw.io export carries its whole diagram in a
15
+ * `content` attribute on the tag, which pushes the tag's end past that
16
+ * window, so one diagram fails the build (`NoImageMetadata`). Blume serves
17
+ * such an SVG as it is instead, from the endpoint that already serves content
18
+ * images to agents (`/blume-assets/content/…`), and warns about it
19
+ * (`BLUME_SVG_UNOPTIMIZED`). A browser draws an SVG at any size, so the
20
+ * only loss is the intrinsic `width`/`height` the optimized `<img>` carries.
21
+ */
22
+
23
+ /** Whether the file at `path` is an SVG Astro can't read the size of. */
24
+ export const isUnmeasurableSvg = async (path: string): Promise<boolean> => {
25
+ if (extname(path).toLowerCase() !== ".svg") {
26
+ return false;
27
+ }
28
+ let data: Buffer;
29
+ try {
30
+ data = await readFile(path);
31
+ } catch {
32
+ return false;
33
+ }
34
+ try {
35
+ await imageMetadata(data, path);
36
+ return false;
37
+ } catch {
38
+ return true;
39
+ }
40
+ };
41
+
42
+ /**
43
+ * The URL an unmeasurable SVG is served at, unbased (the base links plugin
44
+ * mounts `deployment.base`), or null when `target` isn't a colocated image
45
+ * Astro can measure no size for.
46
+ */
47
+ export const unmeasurableSvgUrl = async (
48
+ sourceDir: string,
49
+ target: string,
50
+ projectRoot: string
51
+ ): Promise<string | null> => {
52
+ const abs = resolveRelativeImage(sourceDir, target);
53
+ if (!(abs && (await isUnmeasurableSvg(abs)))) {
54
+ return null;
55
+ }
56
+ return contentAssetUrl(contentAssetParam(projectRoot, abs));
57
+ };
58
+
59
+ /**
60
+ * A warning for each image embed of a colocated SVG Astro can't measure, at
61
+ * the line that embeds it (in a partial, when an `<include>` brought it in).
62
+ */
63
+ export const unmeasurableSvgDiagnostics = async (
64
+ pages: readonly PageRecord[]
65
+ ): Promise<Diagnostic[]> => {
66
+ const seen = new Set<string>();
67
+ const embeds = pages.flatMap((page) => {
68
+ const { sourcePath } = page;
69
+ if (!sourcePath) {
70
+ return [];
71
+ }
72
+ return page.links.flatMap((link) => {
73
+ const file = link.file ?? sourcePath;
74
+ const key = `${file}:${link.line}:${link.column}`;
75
+ if (!link.image || seen.has(key)) {
76
+ return [];
77
+ }
78
+ seen.add(key);
79
+ const abs = resolveRelativeImage(dirname(sourcePath), link.target);
80
+ return abs ? [{ abs, file, link }] : [];
81
+ });
82
+ });
83
+ const found = await Promise.all(
84
+ embeds.map(async (embed) =>
85
+ (await isUnmeasurableSvg(embed.abs)) ? [embed] : []
86
+ )
87
+ );
88
+ return found.flat().map(({ file, link }) => ({
89
+ code: "BLUME_SVG_UNOPTIMIZED",
90
+ column: link.column,
91
+ file,
92
+ line: link.line,
93
+ message: `\`${link.target}\` is served as it is, not optimized: Astro can't read its size, which takes the whole \`<svg>\` tag within the file's first 1,000 bytes, with a width and height or a viewBox.`,
94
+ severity: "warning",
95
+ suggestion:
96
+ "The image still shows. To have it optimized, put the `<svg>` tag's width and height (or viewBox) near the start of the file. In a draw.io export, the `content` attribute pushes them out: export without a copy of the diagram, or remove that attribute.",
97
+ }));
98
+ };