blume 1.7.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (677) hide show
  1. package/AGENTS.md +19 -0
  2. package/CHANGELOG.md +227 -0
  3. package/README.md +34 -21
  4. package/dist/cli/chunk-11j0384y.js +148 -0
  5. package/dist/cli/chunk-11j0384y.js.map +10 -0
  6. package/dist/cli/{chunk-xhtpx3ff.js → chunk-1w8dp3qb.js} +17 -16
  7. package/dist/cli/{chunk-xhtpx3ff.js.map → chunk-1w8dp3qb.js.map} +3 -3
  8. package/dist/cli/chunk-2q1dwty4.js +75 -0
  9. package/dist/cli/chunk-2q1dwty4.js.map +11 -0
  10. package/dist/cli/chunk-41za066z.js +122 -0
  11. package/dist/cli/chunk-41za066z.js.map +11 -0
  12. package/dist/cli/chunk-5a2z0198.js +133 -0
  13. package/dist/cli/chunk-5a2z0198.js.map +10 -0
  14. package/dist/cli/{chunk-9he6crym.js → chunk-6k8vp3ta.js} +25 -13
  15. package/dist/cli/{chunk-9he6crym.js.map → chunk-6k8vp3ta.js.map} +4 -4
  16. package/dist/cli/{chunk-mt76t7dj.js → chunk-79njf86q.js} +133 -54
  17. package/dist/cli/chunk-79njf86q.js.map +11 -0
  18. package/dist/cli/{chunk-3w7b2vcx.js → chunk-7ez8ny0t.js} +2 -2
  19. package/dist/cli/{chunk-688e0dde.js → chunk-88cpgt6h.js} +1 -1
  20. package/dist/cli/chunk-a9kptbw5.js +361 -0
  21. package/dist/cli/chunk-a9kptbw5.js.map +14 -0
  22. package/dist/cli/chunk-abh8yjkn.js +31 -0
  23. package/dist/cli/chunk-abh8yjkn.js.map +10 -0
  24. package/dist/cli/chunk-b5aj94ah.js +91 -0
  25. package/dist/cli/chunk-b5aj94ah.js.map +10 -0
  26. package/dist/cli/{chunk-hs3gbh8p.js → chunk-bctazmbk.js} +9 -5
  27. package/dist/cli/chunk-bctazmbk.js.map +10 -0
  28. package/dist/cli/chunk-beat36xx.js +279 -0
  29. package/dist/cli/chunk-beat36xx.js.map +10 -0
  30. package/dist/cli/chunk-bnbmcwfb.js +145 -0
  31. package/dist/cli/chunk-bnbmcwfb.js.map +11 -0
  32. package/dist/cli/{chunk-9bkjd11x.js → chunk-bw22s759.js} +15 -5
  33. package/dist/cli/{chunk-9bkjd11x.js.map → chunk-bw22s759.js.map} +4 -4
  34. package/dist/cli/chunk-by2290sx.js +39 -0
  35. package/dist/cli/chunk-by2290sx.js.map +10 -0
  36. package/dist/cli/chunk-d1tadaw7.js +79 -0
  37. package/dist/cli/chunk-d1tadaw7.js.map +10 -0
  38. package/dist/cli/{chunk-t3tj0dgr.js → chunk-d80hr03s.js} +24 -19
  39. package/dist/cli/chunk-d80hr03s.js.map +15 -0
  40. package/dist/cli/chunk-ernrthtr.js +97 -0
  41. package/dist/cli/chunk-ernrthtr.js.map +10 -0
  42. package/dist/cli/chunk-f2972sbt.js +374 -0
  43. package/dist/cli/chunk-f2972sbt.js.map +10 -0
  44. package/dist/cli/{chunk-exeeb35e.js → chunk-f7t03s3g.js} +2 -2
  45. package/dist/cli/{chunk-2z47ypj8.js → chunk-fa25z98p.js} +16 -3
  46. package/dist/cli/chunk-fa25z98p.js.map +11 -0
  47. package/dist/cli/{chunk-12dxjqk7.js → chunk-fh5hj5jt.js} +44 -21
  48. package/dist/cli/chunk-fh5hj5jt.js.map +10 -0
  49. package/dist/cli/{chunk-8cd8tj54.js → chunk-j8mw0za6.js} +86 -57
  50. package/dist/cli/chunk-j8mw0za6.js.map +35 -0
  51. package/dist/cli/chunk-jts8mvcz.js +106 -0
  52. package/dist/cli/{chunk-2mzebbbz.js.map → chunk-jts8mvcz.js.map} +6 -4
  53. package/dist/cli/{chunk-ejjx8znq.js → chunk-mnqj32sj.js} +505 -536
  54. package/dist/cli/chunk-mnqj32sj.js.map +12 -0
  55. package/dist/cli/{chunk-196vjxp9.js → chunk-mwt1k8n7.js} +100 -372
  56. package/dist/cli/chunk-mwt1k8n7.js.map +10 -0
  57. package/dist/cli/chunk-nk3ts2xk.js +51 -0
  58. package/dist/cli/chunk-nk3ts2xk.js.map +10 -0
  59. package/dist/cli/{chunk-n9sra6sy.js → chunk-pat2zzwc.js} +10 -14
  60. package/dist/cli/{chunk-n9sra6sy.js.map → chunk-pat2zzwc.js.map} +2 -2
  61. package/dist/cli/chunk-pnnvybbk.js +176 -0
  62. package/dist/cli/chunk-pnnvybbk.js.map +11 -0
  63. package/dist/cli/{chunk-cvky9gb2.js → chunk-sqn5t4q0.js} +81 -87
  64. package/dist/cli/chunk-sqn5t4q0.js.map +10 -0
  65. package/dist/cli/{chunk-eevwt1sc.js → chunk-tzne8qfq.js} +15 -15
  66. package/dist/cli/{chunk-eevwt1sc.js.map → chunk-tzne8qfq.js.map} +1 -1
  67. package/dist/cli/chunk-xaz13gwg.js +12449 -0
  68. package/dist/cli/chunk-xaz13gwg.js.map +182 -0
  69. package/dist/cli/chunk-y3e45rc8.js +102 -0
  70. package/dist/cli/chunk-y3e45rc8.js.map +10 -0
  71. package/dist/cli/chunk-z01ze5c1.js +261 -0
  72. package/dist/cli/chunk-z01ze5c1.js.map +10 -0
  73. package/dist/cli/{chunk-5n7t497w.js → chunk-z1f5arsg.js} +247 -755
  74. package/dist/cli/chunk-z1f5arsg.js.map +36 -0
  75. package/dist/cli/{chunk-hdm2dkd2.js → chunk-zg2gtj10.js} +1086 -2596
  76. package/dist/cli/chunk-zg2gtj10.js.map +35 -0
  77. package/dist/cli/{chunk-ppfvdcd4.js → chunk-zxccj738.js} +1 -1
  78. package/dist/cli/index.js +214 -57
  79. package/dist/cli/index.js.map +8 -7
  80. package/dist/types/ai/agent-readability.d.ts +52 -0
  81. package/dist/types/ai/ai-catalog.d.ts +42 -0
  82. package/dist/types/ai/api/paths.d.ts +17 -0
  83. package/dist/types/ai/api-catalog.d.ts +18 -0
  84. package/dist/types/ai/ask.d.ts +368 -0
  85. package/dist/types/ai/changelog-markdown.d.ts +2 -0
  86. package/dist/types/ai/component-markdown.d.ts +2 -2
  87. package/dist/types/ai/index.d.ts +24 -0
  88. package/dist/types/ai/link-headers.d.ts +24 -0
  89. package/dist/types/ai/llms.d.ts +25 -0
  90. package/dist/types/ai/markdown.d.ts +45 -0
  91. package/dist/types/ai/mcp/discovery.d.ts +68 -0
  92. package/dist/types/ai/mcp/tools.d.ts +16 -0
  93. package/dist/types/ai/openapi-components.d.ts +43 -0
  94. package/dist/types/ai/relative-links.d.ts +26 -0
  95. package/dist/types/ai/serializers.d.ts +15 -0
  96. package/dist/types/ai/skills.d.ts +42 -0
  97. package/dist/types/ai/tar.d.ts +25 -0
  98. package/dist/types/ai/visibility.d.ts +17 -0
  99. package/dist/types/ai/web-bot-auth.d.ts +16 -0
  100. package/dist/types/analytics/adobe.d.ts +35 -0
  101. package/dist/types/analytics/amplitude.d.ts +50 -0
  102. package/dist/types/analytics/clarity.d.ts +31 -0
  103. package/dist/types/analytics/clearbit.d.ts +29 -0
  104. package/dist/types/analytics/cloudflare.d.ts +41 -0
  105. package/dist/types/analytics/fathom.d.ts +41 -0
  106. package/dist/types/analytics/google-analytics.d.ts +44 -0
  107. package/dist/types/analytics/google-tag-manager.d.ts +40 -0
  108. package/dist/types/analytics/head.d.ts +30 -0
  109. package/dist/types/analytics/heap.d.ts +40 -0
  110. package/dist/types/analytics/hightouch.d.ts +44 -0
  111. package/dist/types/analytics/hotjar.d.ts +33 -0
  112. package/dist/types/analytics/index.d.ts +61 -0
  113. package/dist/types/analytics/inline.d.ts +17 -0
  114. package/dist/types/analytics/logrocket.d.ts +44 -0
  115. package/dist/types/analytics/mixpanel.d.ts +67 -0
  116. package/dist/types/analytics/pirsch.d.ts +42 -0
  117. package/dist/types/analytics/plausible.d.ts +56 -0
  118. package/dist/types/analytics/posthog.d.ts +45 -0
  119. package/dist/types/analytics/schema.d.ts +320 -0
  120. package/dist/types/analytics/script.d.ts +46 -0
  121. package/dist/types/analytics/segment.d.ts +50 -0
  122. package/dist/types/analytics/vercel.d.ts +48 -0
  123. package/dist/types/astro/integration.d.ts +76 -0
  124. package/dist/types/astro/markdown-negotiation.d.ts +23 -0
  125. package/dist/types/astro/module-types.d.ts +14 -0
  126. package/dist/types/astro/pages.d.ts +44 -0
  127. package/dist/types/cli/env.d.ts +12 -0
  128. package/dist/types/cli/init/scaffold.d.ts +154 -0
  129. package/dist/types/components/layout/nav-utils.d.ts +11 -0
  130. package/dist/types/core/adapter.d.ts +47 -0
  131. package/dist/types/core/api-name.d.ts +7 -0
  132. package/dist/types/core/changelog-index.d.ts +13 -0
  133. package/dist/types/core/config-input.d.ts +209 -505
  134. package/dist/types/core/config.d.ts +60 -34
  135. package/dist/types/core/content-assets.d.ts +76 -0
  136. package/dist/types/core/custom-pages.d.ts +33 -0
  137. package/dist/types/core/data.d.ts +28 -11
  138. package/dist/types/core/define-components.d.ts +12 -9
  139. package/dist/types/core/deployment-env.d.ts +6 -11
  140. package/dist/types/core/frontmatter.d.ts +10 -0
  141. package/dist/types/core/graph.d.ts +18 -0
  142. package/dist/types/core/heading-markers.d.ts +54 -0
  143. package/dist/types/core/i18n-ui.d.ts +6 -2
  144. package/dist/types/core/i18n.d.ts +87 -0
  145. package/dist/types/core/includes.d.ts +138 -0
  146. package/dist/types/core/last-modified.d.ts +47 -0
  147. package/dist/types/core/links.d.ts +95 -0
  148. package/dist/types/core/locale-links.d.ts +60 -0
  149. package/dist/types/core/manifest.d.ts +17 -0
  150. package/dist/types/core/meta.d.ts +38 -0
  151. package/dist/types/core/nav-diagnostics.d.ts +26 -0
  152. package/dist/types/core/navigation.d.ts +6 -0
  153. package/dist/types/core/node-require.d.ts +19 -0
  154. package/dist/types/core/package-json.d.ts +13 -0
  155. package/dist/types/core/probe.d.ts +42 -0
  156. package/dist/types/core/project-graph.d.ts +51 -0
  157. package/dist/types/core/project.d.ts +2 -0
  158. package/dist/types/core/safe-href.d.ts +2 -0
  159. package/dist/types/core/safe-links.d.ts +26 -0
  160. package/dist/types/core/schema.d.ts +2291 -441
  161. package/dist/types/core/site-url.d.ts +16 -0
  162. package/dist/types/core/sources/assets.d.ts +36 -0
  163. package/dist/types/core/sources/cache.d.ts +37 -0
  164. package/dist/types/core/sources/collection.d.ts +28 -0
  165. package/dist/types/core/sources/contentful-rich-text.d.ts +31 -0
  166. package/dist/types/core/sources/contentful.d.ts +40 -0
  167. package/dist/types/core/sources/filesystem.d.ts +24 -0
  168. package/dist/types/core/sources/github-releases.d.ts +31 -0
  169. package/dist/types/core/sources/json.d.ts +30 -0
  170. package/dist/types/core/sources/lexical.d.ts +19 -0
  171. package/dist/types/core/sources/lower.d.ts +75 -0
  172. package/dist/types/core/sources/mdx-remote.d.ts +28 -0
  173. package/dist/types/core/sources/normalize.d.ts +147 -0
  174. package/dist/types/core/sources/notion.d.ts +131 -0
  175. package/dist/types/core/sources/obsidian.d.ts +46 -0
  176. package/dist/types/core/sources/payload.d.ts +39 -0
  177. package/dist/types/core/sources/portable-text.d.ts +42 -0
  178. package/dist/types/core/sources/read.d.ts +23 -0
  179. package/dist/types/core/sources/remote.d.ts +74 -0
  180. package/dist/types/core/sources/resolve.d.ts +19 -0
  181. package/dist/types/core/sources/sanity.d.ts +43 -0
  182. package/dist/types/core/sources/strapi-blocks.d.ts +12 -0
  183. package/dist/types/core/sources/strapi.d.ts +33 -0
  184. package/dist/types/core/sources/types.d.ts +7 -0
  185. package/dist/types/core/sources/watch.d.ts +45 -0
  186. package/dist/types/core/text-width.d.ts +11 -0
  187. package/dist/types/core/types.d.ts +20 -1
  188. package/dist/types/core/unrecognized-keys.d.ts +7 -0
  189. package/dist/types/core/versions.d.ts +72 -0
  190. package/dist/types/core/yaml.d.ts +9 -0
  191. package/dist/types/deploy/adapter-output.d.ts +45 -0
  192. package/dist/types/deploy/adapters/cloudflare.d.ts +40 -0
  193. package/dist/types/deploy/adapters/index.d.ts +29 -0
  194. package/dist/types/deploy/adapters/netlify.d.ts +37 -0
  195. package/dist/types/deploy/adapters/node.d.ts +37 -0
  196. package/dist/types/deploy/adapters/registry.d.ts +133 -0
  197. package/dist/types/deploy/adapters/types.d.ts +71 -0
  198. package/dist/types/deploy/adapters/vercel.d.ts +38 -0
  199. package/dist/types/deploy/artifacts.d.ts +65 -0
  200. package/dist/types/deploy/cloudflare-negotiation.d.ts +196 -0
  201. package/dist/types/deploy/function-bundle.d.ts +80 -0
  202. package/dist/types/deploy/headers.d.ts +50 -0
  203. package/dist/types/deploy/node-headers.d.ts +42 -0
  204. package/dist/types/deploy/platforms/cloudflare.d.ts +40 -0
  205. package/dist/types/deploy/platforms/index.d.ts +18 -0
  206. package/dist/types/deploy/platforms/netlify.d.ts +13 -0
  207. package/dist/types/deploy/platforms/node.d.ts +11 -0
  208. package/dist/types/deploy/platforms/paths.d.ts +27 -0
  209. package/dist/types/deploy/platforms/static.d.ts +10 -0
  210. package/dist/types/deploy/platforms/types.d.ts +104 -0
  211. package/dist/types/deploy/platforms/vercel.d.ts +32 -0
  212. package/dist/types/deploy/redirects.d.ts +53 -0
  213. package/dist/types/deploy/robots.d.ts +8 -0
  214. package/dist/types/deploy/rss.d.ts +31 -0
  215. package/dist/types/deploy/sitemap.d.ts +21 -0
  216. package/dist/types/deploy/vercel-negotiation.d.ts +109 -0
  217. package/dist/types/markdown/code-title.d.ts +32 -0
  218. package/dist/types/markdown/fence-meta.d.ts +23 -0
  219. package/dist/types/markdown/themes.d.ts +3 -3
  220. package/dist/types/openapi/asyncapi.d.ts +129 -0
  221. package/dist/types/openapi/graphql-build.d.ts +8 -0
  222. package/dist/types/openapi/graphql.d.ts +122 -0
  223. package/dist/types/openapi/model.d.ts +158 -0
  224. package/dist/types/openapi/parse.d.ts +57 -0
  225. package/dist/types/openapi/references.d.ts +37 -25
  226. package/dist/types/openapi/render-mdx.d.ts +33 -0
  227. package/dist/types/openapi/sentence.d.ts +7 -0
  228. package/dist/types/openapi/signature.d.ts +10 -0
  229. package/dist/types/openapi/source.d.ts +22 -0
  230. package/dist/types/openapi/spec-dependency-error.d.ts +10 -0
  231. package/dist/types/reference/asyncapi.d.ts +166 -0
  232. package/dist/types/reference/graphql.d.ts +181 -0
  233. package/dist/types/reference/index.d.ts +32 -0
  234. package/dist/types/reference/openapi.d.ts +165 -0
  235. package/dist/types/reference/options.d.ts +157 -0
  236. package/dist/types/reference/scalar.d.ts +136 -0
  237. package/dist/types/reference/schema.d.ts +630 -0
  238. package/dist/types/search/adapters/algolia.d.ts +32 -0
  239. package/dist/types/search/adapters/flexsearch.d.ts +12 -0
  240. package/dist/types/search/adapters/index.d.ts +31 -0
  241. package/dist/types/search/adapters/mixedbread.d.ts +22 -0
  242. package/dist/types/search/adapters/orama-cloud.d.ts +33 -0
  243. package/dist/types/search/adapters/orama.d.ts +13 -0
  244. package/dist/types/search/adapters/pagefind.d.ts +12 -0
  245. package/dist/types/search/adapters/registry.d.ts +228 -0
  246. package/dist/types/search/adapters/types.d.ts +34 -0
  247. package/dist/types/search/adapters/typesense.d.ts +42 -0
  248. package/dist/types/search/build.d.ts +23 -0
  249. package/dist/types/search/documents.d.ts +90 -0
  250. package/dist/types/search/facets.d.ts +3 -0
  251. package/dist/types/search/sync/algolia.d.ts +14 -0
  252. package/dist/types/search/sync/index.d.ts +14 -0
  253. package/dist/types/search/sync/orama-cloud.d.ts +10 -0
  254. package/dist/types/search/sync/typesense.d.ts +14 -0
  255. package/dist/types/sources/contentful.d.ts +68 -0
  256. package/dist/types/sources/custom.d.ts +20 -0
  257. package/dist/types/sources/filesystem.d.ts +42 -0
  258. package/dist/types/sources/github-releases.d.ts +46 -0
  259. package/dist/types/sources/index.d.ts +48 -0
  260. package/dist/types/sources/mdx-remote.d.ts +63 -0
  261. package/dist/types/sources/notion.d.ts +65 -0
  262. package/dist/types/sources/obsidian.d.ts +34 -0
  263. package/dist/types/sources/payload.d.ts +68 -0
  264. package/dist/types/sources/registry.d.ts +1414 -0
  265. package/dist/types/sources/sanity.d.ts +69 -0
  266. package/dist/types/sources/shared.d.ts +46 -0
  267. package/dist/types/sources/strapi.d.ts +66 -0
  268. package/dist/types/theme/icon-kind.d.ts +11 -0
  269. package/dist/types/theme/icons.d.ts +20 -0
  270. package/docs/01-quickstart.mdx +18 -18
  271. package/docs/02-deployment.mdx +50 -26
  272. package/docs/03-upgrading.mdx +351 -0
  273. package/docs/04-migrating.mdx +58 -0
  274. package/docs/08-faq.mdx +3 -3
  275. package/docs/advanced/blog.mdx +13 -6
  276. package/docs/advanced/changelog.mdx +23 -35
  277. package/docs/advanced/custom-pages.mdx +20 -8
  278. package/docs/advanced/meta.ts +1 -8
  279. package/docs/advanced/skills.mdx +8 -0
  280. package/docs/cli/audit.mdx +646 -0
  281. package/docs/cli/doctor.mdx +29 -0
  282. package/docs/{reference/eval.mdx → cli/evals.mdx} +9 -8
  283. package/docs/cli/index.mdx +105 -0
  284. package/docs/cli/meta.ts +7 -0
  285. package/docs/{reference → cli}/translate.mdx +1 -1
  286. package/docs/cli/validate.mdx +41 -0
  287. package/docs/cli/version.mdx +40 -0
  288. package/docs/configuration/analytics.mdx +350 -59
  289. package/docs/configuration/ask-ai.mdx +176 -61
  290. package/docs/configuration/customization.mdx +15 -9
  291. package/docs/configuration/index.mdx +52 -31
  292. package/docs/configuration/search.mdx +75 -54
  293. package/docs/configuration/theming.mdx +24 -15
  294. package/docs/content/components.mdx +21 -5
  295. package/docs/{reference → content}/frontmatter.mdx +37 -1
  296. package/docs/content/i18n.mdx +8 -6
  297. package/docs/content/includes.mdx +2 -4
  298. package/docs/content/index.mdx +1 -1
  299. package/docs/content/islands.mdx +10 -5
  300. package/docs/content/meta.mdx +1 -1
  301. package/docs/content/meta.ts +1 -0
  302. package/docs/content/navigation.mdx +12 -7
  303. package/docs/content/sources.mdx +145 -50
  304. package/docs/content/syntax.mdx +26 -12
  305. package/docs/content/versioning.mdx +3 -3
  306. package/docs/discoverability/agent-discovery.mdx +91 -10
  307. package/docs/discoverability/index.mdx +5 -5
  308. package/docs/discoverability/json-api.mdx +4 -4
  309. package/docs/discoverability/llms-txt.mdx +6 -6
  310. package/docs/discoverability/markdown.mdx +4 -4
  311. package/docs/discoverability/mcp.mdx +11 -11
  312. package/docs/discoverability/sitemap-and-robots.mdx +3 -3
  313. package/docs/index.mdx +2 -2
  314. package/docs/references/asyncapi.mdx +59 -0
  315. package/docs/{advanced → references}/graphql.mdx +45 -32
  316. package/docs/{reference → references}/meta.ts +2 -2
  317. package/docs/references/openapi.mdx +171 -0
  318. package/docs/references/scalar.mdx +64 -0
  319. package/package.json +42 -8
  320. package/skills/blume/SKILL.md +21 -8
  321. package/skills/blume-migrate/SKILL.md +22 -21
  322. package/skills/blume-migrate/assets/oxfmt@0.67.0.patch +49 -0
  323. package/skills/blume-migrate/references/docusaurus.md +5 -4
  324. package/skills/blume-migrate/references/fumadocs.md +4 -4
  325. package/skills/blume-migrate/references/mintlify.md +23 -8
  326. package/skills/blume-migrate/references/monorepo.md +6 -6
  327. package/skills/blume-migrate/references/starlight.md +4 -4
  328. package/src/ai/agent-readability.ts +26 -22
  329. package/src/ai/ai-catalog.ts +259 -0
  330. package/src/ai/api/handlers.ts +46 -11
  331. package/src/ai/api-catalog.ts +8 -8
  332. package/src/ai/ask-data.ts +1 -1
  333. package/src/ai/ask.ts +624 -100
  334. package/src/ai/changelog-markdown.ts +91 -0
  335. package/src/ai/component-markdown.ts +328 -12
  336. package/src/ai/index.ts +45 -0
  337. package/src/ai/link-headers.ts +19 -6
  338. package/src/ai/llms.ts +26 -15
  339. package/src/ai/markdown.ts +35 -5
  340. package/src/ai/mcp/data.ts +9 -5
  341. package/src/ai/mcp/discovery.ts +1 -1
  342. package/src/ai/openapi-components.ts +4 -1
  343. package/src/ai/relative-links.ts +170 -0
  344. package/src/ai/serializers.ts +2 -2
  345. package/src/ai/skills.ts +1 -1
  346. package/src/ai/web-bot-auth.ts +2 -2
  347. package/src/analytics/adobe.ts +46 -0
  348. package/src/analytics/amplitude.ts +79 -0
  349. package/src/analytics/clarity.ts +46 -0
  350. package/src/analytics/clearbit.ts +47 -0
  351. package/src/analytics/cloudflare.ts +67 -0
  352. package/src/analytics/fathom.ts +64 -0
  353. package/src/analytics/google-analytics.ts +84 -0
  354. package/src/analytics/google-tag-manager.ts +61 -0
  355. package/src/analytics/head.ts +130 -0
  356. package/src/analytics/heap.ts +65 -0
  357. package/src/analytics/hightouch.ts +77 -0
  358. package/src/analytics/hotjar.ts +47 -0
  359. package/src/analytics/index.ts +71 -0
  360. package/src/analytics/inline.ts +21 -0
  361. package/src/analytics/logrocket.ts +71 -0
  362. package/src/analytics/mixpanel.ts +92 -0
  363. package/src/analytics/pirsch.ts +66 -0
  364. package/src/analytics/plausible.ts +83 -0
  365. package/src/analytics/posthog.ts +78 -0
  366. package/src/analytics/schema.ts +60 -0
  367. package/src/analytics/script.ts +60 -0
  368. package/src/analytics/segment.ts +85 -0
  369. package/src/analytics/vercel.ts +50 -0
  370. package/src/astro/adapter-root.ts +7 -9
  371. package/src/astro/component-slots.ts +131 -91
  372. package/src/astro/generate.ts +114 -345
  373. package/src/astro/integration.ts +2 -6
  374. package/src/astro/pages.ts +13 -101
  375. package/src/astro/render-deps.ts +379 -0
  376. package/src/astro/runtime-deps.ts +201 -0
  377. package/src/astro/templates.ts +554 -541
  378. package/src/audit/agent.ts +24 -0
  379. package/src/audit/catalog.ts +2 -2
  380. package/src/audit/checks/assets.ts +2 -2
  381. package/src/audit/checks/dns-aid.ts +1 -1
  382. package/src/audit/checks/duplicates.ts +3 -1
  383. package/src/audit/checks/i18n.ts +1 -1
  384. package/src/audit/checks/indexability.ts +7 -7
  385. package/src/audit/checks/links.ts +2 -2
  386. package/src/audit/checks/llms.ts +6 -6
  387. package/src/audit/checks/network.ts +3 -3
  388. package/src/audit/checks/og-image.ts +2 -2
  389. package/src/audit/checks/robots.ts +1 -1
  390. package/src/audit/checks/sitemap.ts +2 -2
  391. package/src/audit/checks/social.ts +1 -1
  392. package/src/audit/run.ts +4 -3
  393. package/src/audit/terms.ts +31 -0
  394. package/src/audit/url.ts +13 -13
  395. package/src/cli/command-meta.ts +10 -0
  396. package/src/cli/commands/audit.ts +39 -20
  397. package/src/cli/commands/build.ts +71 -314
  398. package/src/cli/commands/check.ts +1 -0
  399. package/src/cli/commands/dev.ts +40 -1
  400. package/src/cli/commands/doctor.ts +90 -14
  401. package/src/cli/commands/eject.ts +44 -7
  402. package/src/cli/commands/eval.ts +2 -2
  403. package/src/cli/commands/init.ts +161 -41
  404. package/src/cli/commands/migrate.ts +121 -0
  405. package/src/cli/commands/preview.ts +7 -1
  406. package/src/cli/commands/translate.ts +2 -2
  407. package/src/cli/commands/upgrade.ts +141 -0
  408. package/src/cli/commands/version.ts +57 -44
  409. package/src/cli/eject-scripts.ts +121 -6
  410. package/src/cli/index.ts +11 -1
  411. package/src/cli/init/install.ts +70 -0
  412. package/src/cli/init/questions.ts +7 -0
  413. package/src/cli/init/scaffold.ts +459 -75
  414. package/src/cli/lazy-command.ts +37 -1
  415. package/src/cli/prepare.ts +40 -6
  416. package/src/cli/required-secrets.ts +38 -11
  417. package/src/cli/unknown-flags.ts +266 -0
  418. package/src/cli/yarn-pnp.ts +52 -0
  419. package/src/components/content/AccordionItem.astro +7 -1
  420. package/src/components/content/Card.astro +4 -3
  421. package/src/components/content/ColorItem.astro +22 -4
  422. package/src/components/content/GithubInfo.astro +2 -2
  423. package/src/components/content/Prompt.astro +25 -25
  424. package/src/components/content/Tabs.astro +3 -1
  425. package/src/components/content/Tile.astro +2 -3
  426. package/src/components/content/Tooltip.astro +57 -9
  427. package/src/components/content/content-strings.ts +34 -0
  428. package/src/components/content/diff.ts +1 -1
  429. package/src/components/content/mermaid-element.ts +13 -2
  430. package/src/components/content/prompt-markdown.ts +292 -0
  431. package/src/components/content/tooltip-id.ts +41 -0
  432. package/src/components/islands/hooks.ts +75 -3
  433. package/src/components/layout/Analytics.astro +21 -79
  434. package/src/components/layout/Banner.astro +3 -1
  435. package/src/components/layout/DiscoveryLinks.astro +69 -0
  436. package/src/components/layout/Header.astro +83 -20
  437. package/src/components/layout/LanguageSwitcher.astro +4 -1
  438. package/src/components/layout/Logo.astro +23 -2
  439. package/src/components/layout/NavSelector.astro +13 -2
  440. package/src/components/layout/NavTree.astro +12 -3
  441. package/src/components/layout/NavTreeScript.astro +17 -3
  442. package/src/components/layout/PageActions.astro +3 -3
  443. package/src/components/layout/PageFeedback.astro +11 -1
  444. package/src/components/layout/PageLayout.astro +52 -5
  445. package/src/components/layout/ReferenceLayout.astro +21 -12
  446. package/src/components/layout/RootLayout.astro +69 -43
  447. package/src/components/layout/Search.astro +30 -6
  448. package/src/components/layout/WebMcp.astro +1 -1
  449. package/src/components/layout/analytics-client.ts +101 -15
  450. package/src/components/layout/drawer-inert.ts +113 -15
  451. package/src/components/layout/dropdown-clamp.ts +105 -0
  452. package/src/components/layout/head-scripts.ts +15 -6
  453. package/src/components/layout/nav-utils.ts +17 -0
  454. package/src/components/layout/search/algolia.ts +8 -8
  455. package/src/components/layout/search/orama-cloud.ts +9 -7
  456. package/src/components/layout/search/typesense.ts +11 -17
  457. package/src/components/openapi/MessageComposer.astro +2 -2
  458. package/src/components/openapi/Playground.astro +2 -2
  459. package/src/components/openapi/playground-client.ts +79 -10
  460. package/src/core/changelog-index.ts +24 -0
  461. package/src/core/component-overrides.ts +399 -154
  462. package/src/core/config-input.ts +212 -543
  463. package/src/core/config.ts +130 -41
  464. package/src/core/custom-pages.ts +105 -0
  465. package/src/core/data.ts +32 -11
  466. package/src/core/define-components.ts +12 -9
  467. package/src/core/deployment-env.ts +18 -74
  468. package/src/core/diagnostics.ts +14 -7
  469. package/src/core/graph.ts +69 -25
  470. package/src/core/i18n-ui.ts +6 -2
  471. package/src/core/i18n.ts +17 -0
  472. package/src/core/includes.ts +156 -38
  473. package/src/core/last-modified.ts +6 -11
  474. package/src/core/links.ts +166 -2
  475. package/src/core/manifest.ts +10 -3
  476. package/src/core/navigation.ts +137 -19
  477. package/src/core/new-tab.ts +35 -0
  478. package/src/core/node-require.ts +21 -0
  479. package/src/core/project-graph.ts +42 -26
  480. package/src/core/project.ts +9 -4
  481. package/src/core/request-body.ts +61 -0
  482. package/src/core/safe-href.ts +28 -0
  483. package/src/core/safe-links.ts +68 -0
  484. package/src/core/schema.ts +531 -721
  485. package/src/core/server-features.ts +8 -9
  486. package/src/core/sources/assets.ts +47 -11
  487. package/src/core/sources/collection.ts +67 -0
  488. package/src/core/sources/contentful-rich-text.ts +285 -0
  489. package/src/core/sources/contentful.ts +173 -0
  490. package/src/core/sources/github-releases.ts +51 -1
  491. package/src/core/sources/json.ts +71 -0
  492. package/src/core/sources/lexical.ts +195 -0
  493. package/src/core/sources/lower.ts +226 -0
  494. package/src/core/sources/normalize.ts +52 -2
  495. package/src/core/sources/notion.ts +39 -28
  496. package/src/core/sources/payload.ts +135 -0
  497. package/src/core/sources/portable-text.ts +11 -16
  498. package/src/core/sources/remote.ts +226 -0
  499. package/src/core/sources/resolve.ts +104 -166
  500. package/src/core/sources/sanity.ts +16 -49
  501. package/src/core/sources/strapi-blocks.ts +124 -0
  502. package/src/core/sources/strapi.ts +191 -0
  503. package/src/core/sources/types.ts +12 -1
  504. package/src/core/types.ts +20 -1
  505. package/src/core/ui-packs/ar.ts +6 -2
  506. package/src/core/ui-packs/bg.ts +6 -2
  507. package/src/core/ui-packs/bn.ts +6 -2
  508. package/src/core/ui-packs/ca.ts +3 -1
  509. package/src/core/ui-packs/cs.ts +6 -2
  510. package/src/core/ui-packs/da.ts +6 -2
  511. package/src/core/ui-packs/de.ts +6 -2
  512. package/src/core/ui-packs/el.ts +3 -1
  513. package/src/core/ui-packs/es.ts +3 -1
  514. package/src/core/ui-packs/fa.ts +6 -2
  515. package/src/core/ui-packs/fi.ts +6 -2
  516. package/src/core/ui-packs/fr.ts +3 -1
  517. package/src/core/ui-packs/he.ts +6 -2
  518. package/src/core/ui-packs/hi.ts +6 -2
  519. package/src/core/ui-packs/hr.ts +6 -2
  520. package/src/core/ui-packs/hu.ts +6 -2
  521. package/src/core/ui-packs/id.ts +6 -2
  522. package/src/core/ui-packs/it.ts +3 -1
  523. package/src/core/ui-packs/ja.ts +3 -1
  524. package/src/core/ui-packs/ko.ts +3 -1
  525. package/src/core/ui-packs/nl.ts +6 -2
  526. package/src/core/ui-packs/no.ts +6 -2
  527. package/src/core/ui-packs/pl.ts +6 -2
  528. package/src/core/ui-packs/pt-br.ts +3 -1
  529. package/src/core/ui-packs/pt.ts +3 -1
  530. package/src/core/ui-packs/ro.ts +6 -2
  531. package/src/core/ui-packs/ru.ts +6 -2
  532. package/src/core/ui-packs/sk.ts +6 -2
  533. package/src/core/ui-packs/sr.ts +6 -2
  534. package/src/core/ui-packs/sv.ts +6 -2
  535. package/src/core/ui-packs/th.ts +3 -1
  536. package/src/core/ui-packs/tr.ts +6 -2
  537. package/src/core/ui-packs/uk.ts +6 -2
  538. package/src/core/ui-packs/vi.ts +3 -1
  539. package/src/core/ui-packs/zh-tw.ts +3 -1
  540. package/src/core/ui-packs/zh.ts +3 -1
  541. package/src/core/unrecognized-keys.ts +10 -0
  542. package/src/core/version-cut.ts +116 -8
  543. package/src/deploy/adapter-output.ts +57 -97
  544. package/src/deploy/adapters/cloudflare.ts +39 -0
  545. package/src/deploy/adapters/index.ts +41 -0
  546. package/src/deploy/adapters/netlify.ts +34 -0
  547. package/src/deploy/adapters/node.ts +34 -0
  548. package/src/deploy/adapters/registry.ts +127 -0
  549. package/src/deploy/adapters/types.ts +92 -0
  550. package/src/deploy/adapters/vercel.ts +35 -0
  551. package/src/deploy/artifacts.ts +67 -28
  552. package/src/deploy/cloudflare-negotiation.ts +179 -100
  553. package/src/deploy/function-bundle.ts +18 -3
  554. package/src/deploy/headers.ts +129 -22
  555. package/src/deploy/node-headers.ts +198 -0
  556. package/src/deploy/platforms/cloudflare.ts +312 -0
  557. package/src/deploy/platforms/index.ts +67 -0
  558. package/src/deploy/platforms/netlify.ts +52 -0
  559. package/src/deploy/platforms/node.ts +40 -0
  560. package/src/deploy/platforms/paths.ts +42 -0
  561. package/src/deploy/platforms/static.ts +29 -0
  562. package/src/deploy/platforms/types.ts +112 -0
  563. package/src/deploy/platforms/vercel.ts +193 -0
  564. package/src/deploy/redirects.ts +30 -18
  565. package/src/deploy/robots.ts +3 -3
  566. package/src/deploy/rss.ts +2 -2
  567. package/src/deploy/sitemap.ts +2 -2
  568. package/src/deploy/vercel-negotiation.ts +27 -4
  569. package/src/eval/agents.ts +32 -1
  570. package/src/eval/findings.ts +19 -11
  571. package/src/eval/report.ts +10 -2
  572. package/src/markdown/external-links.ts +65 -0
  573. package/src/markdown/include.ts +45 -27
  574. package/src/markdown/index.ts +34 -9
  575. package/src/markdown/inline-code.ts +12 -6
  576. package/src/markdown/relative-links.ts +324 -0
  577. package/src/markdown/themes.ts +3 -3
  578. package/src/migrate/migrate.ts +149 -0
  579. package/src/openapi/parse.ts +64 -16
  580. package/src/openapi/proxy.ts +62 -10
  581. package/src/openapi/references.ts +147 -147
  582. package/src/openapi/render-mdx.ts +32 -10
  583. package/src/openapi/scalar.ts +15 -13
  584. package/src/openapi/sentence.ts +14 -0
  585. package/src/openapi/source.ts +37 -21
  586. package/src/openapi/spec-dependency-error.ts +15 -0
  587. package/src/reference/asyncapi.ts +83 -0
  588. package/src/reference/graphql.ts +89 -0
  589. package/src/reference/index.ts +40 -0
  590. package/src/reference/openapi.ts +83 -0
  591. package/src/reference/options.ts +201 -0
  592. package/src/reference/scalar.ts +136 -0
  593. package/src/reference/schema.ts +88 -0
  594. package/src/registry/eject.ts +97 -42
  595. package/src/search/adapters/algolia.ts +46 -0
  596. package/src/search/adapters/flexsearch.ts +29 -0
  597. package/src/search/adapters/index.ts +39 -0
  598. package/src/search/adapters/mixedbread.ts +39 -0
  599. package/src/search/adapters/orama-cloud.ts +51 -0
  600. package/src/search/adapters/orama.ts +24 -0
  601. package/src/search/adapters/pagefind.ts +27 -0
  602. package/src/search/adapters/registry.ts +131 -0
  603. package/src/search/adapters/types.ts +46 -0
  604. package/src/search/adapters/typesense.ts +57 -0
  605. package/src/search/build.ts +33 -7
  606. package/src/search/documents.ts +6 -0
  607. package/src/search/sync/algolia.ts +12 -11
  608. package/src/search/sync/index.ts +35 -20
  609. package/src/search/sync/orama-cloud.ts +12 -9
  610. package/src/search/sync/typesense.ts +15 -13
  611. package/src/sources/contentful.ts +63 -0
  612. package/src/sources/custom.ts +38 -0
  613. package/src/sources/filesystem.ts +51 -0
  614. package/src/sources/github-releases.ts +52 -0
  615. package/src/sources/index.ts +60 -0
  616. package/src/sources/mdx-remote.ts +76 -0
  617. package/src/sources/notion.ts +63 -0
  618. package/src/sources/obsidian.ts +38 -0
  619. package/src/sources/payload.ts +60 -0
  620. package/src/sources/registry.ts +182 -0
  621. package/src/sources/sanity.ts +66 -0
  622. package/src/sources/shared.ts +52 -0
  623. package/src/sources/strapi.ts +58 -0
  624. package/src/theme/entry.ts +47 -2
  625. package/src/translate/report.ts +40 -7
  626. package/src/upgrade/upgrade.ts +499 -0
  627. package/dist/cli/chunk-12dxjqk7.js.map +0 -10
  628. package/dist/cli/chunk-196vjxp9.js.map +0 -13
  629. package/dist/cli/chunk-2mzebbbz.js +0 -69
  630. package/dist/cli/chunk-2z47ypj8.js.map +0 -11
  631. package/dist/cli/chunk-30e87n55.js +0 -108
  632. package/dist/cli/chunk-30e87n55.js.map +0 -10
  633. package/dist/cli/chunk-450a7rcr.js +0 -185
  634. package/dist/cli/chunk-450a7rcr.js.map +0 -11
  635. package/dist/cli/chunk-5n7t497w.js.map +0 -40
  636. package/dist/cli/chunk-61j18dwk.js +0 -5342
  637. package/dist/cli/chunk-61j18dwk.js.map +0 -58
  638. package/dist/cli/chunk-88by27n5.js +0 -17
  639. package/dist/cli/chunk-88by27n5.js.map +0 -10
  640. package/dist/cli/chunk-8cd8tj54.js.map +0 -34
  641. package/dist/cli/chunk-aztttvb3.js +0 -381
  642. package/dist/cli/chunk-aztttvb3.js.map +0 -12
  643. package/dist/cli/chunk-cvky9gb2.js.map +0 -11
  644. package/dist/cli/chunk-ejjx8znq.js.map +0 -15
  645. package/dist/cli/chunk-fmceyezb.js +0 -1007
  646. package/dist/cli/chunk-fmceyezb.js.map +0 -13
  647. package/dist/cli/chunk-hdm2dkd2.js.map +0 -48
  648. package/dist/cli/chunk-hs3gbh8p.js.map +0 -10
  649. package/dist/cli/chunk-jbj4qhfw.js +0 -30
  650. package/dist/cli/chunk-jbj4qhfw.js.map +0 -10
  651. package/dist/cli/chunk-mqb2ka8m.js +0 -68
  652. package/dist/cli/chunk-mqb2ka8m.js.map +0 -10
  653. package/dist/cli/chunk-mt76t7dj.js.map +0 -11
  654. package/dist/cli/chunk-q4rae3bg.js +0 -60
  655. package/dist/cli/chunk-q4rae3bg.js.map +0 -10
  656. package/dist/cli/chunk-ra1v2nc2.js +0 -35
  657. package/dist/cli/chunk-ra1v2nc2.js.map +0 -10
  658. package/dist/cli/chunk-t3tj0dgr.js.map +0 -15
  659. package/dist/cli/chunk-tqa1s0k8.js +0 -69
  660. package/dist/cli/chunk-tqa1s0k8.js.map +0 -11
  661. package/dist/cli/chunk-vh9w1sgp.js +0 -73
  662. package/dist/cli/chunk-vh9w1sgp.js.map +0 -10
  663. package/dist/cli/chunk-vkrsvbr5.js +0 -107
  664. package/dist/cli/chunk-vkrsvbr5.js.map +0 -11
  665. package/dist/cli/chunk-vrfp10qk.js +0 -81
  666. package/dist/cli/chunk-vrfp10qk.js.map +0 -10
  667. package/dist/cli/chunk-wjt80jps.js +0 -1049
  668. package/dist/cli/chunk-wjt80jps.js.map +0 -24
  669. package/docs/advanced/api-reference.mdx +0 -240
  670. package/docs/reference/cli.mdx +0 -197
  671. package/skills/blume-migrate/assets/oxfmt@0.55.0.patch +0 -20
  672. package/src/components/content/changelog-element.ts +0 -69
  673. package/src/search/providers.ts +0 -91
  674. /package/dist/cli/{chunk-3w7b2vcx.js.map → chunk-7ez8ny0t.js.map} +0 -0
  675. /package/dist/cli/{chunk-688e0dde.js.map → chunk-88cpgt6h.js.map} +0 -0
  676. /package/dist/cli/{chunk-exeeb35e.js.map → chunk-f7t03s3g.js.map} +0 -0
  677. /package/dist/cli/{chunk-ppfvdcd4.js.map → chunk-zxccj738.js.map} +0 -0
package/src/core/links.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { existsSync } from "node:fs";
2
2
 
3
- import { basename, dirname, join, relative, resolve } from "pathe";
3
+ import { basename, dirname, join, normalize, relative, resolve } from "pathe";
4
4
 
5
5
  import { stripBasePath, withBasePath } from "./base-path.ts";
6
6
  import {
@@ -80,6 +80,8 @@ interface LinkContext {
80
80
  /** Servable routes outside the graph (custom pages, generated routes); their
81
81
  * headings are unknown, so anchors there are accepted unchecked. */
82
82
  extraRoutes: Set<string>;
83
+ /** Where content files publish, for file links (`./setup.mdx`). */
84
+ fileRoutes: FileRouteIndex;
83
85
  /** Locale routing, when the site is multi-locale; drives served-route resolution. */
84
86
  i18n: LocaleRouting | null;
85
87
  publicDir: string | null;
@@ -156,6 +158,81 @@ const toRoute = (path: string): string => {
156
158
  return route === "" ? "/" : route;
157
159
  };
158
160
 
161
+ /** The page a relative link is written on, as the resolver sees it. */
162
+ export interface RelativeLinkBase {
163
+ /** Whether the page is its folder's index (its route is its directory). */
164
+ isIndex: boolean;
165
+ /** The page's own route, base path included. */
166
+ route: string;
167
+ }
168
+
169
+ /** A root-relative path, a bare `#fragment` or `?query`, or any scheme. */
170
+ const NOT_RELATIVE = /^(?:[#?/]|[a-z][a-z0-9+.-]*:)/iu;
171
+
172
+ /**
173
+ * Where a relative page link written on `from` lands: a root-relative route
174
+ * with the authored `?query#hash` kept — or `undefined` when `href` isn't a
175
+ * relative page link (a root-relative path, a bare `#fragment` or `?query`,
176
+ * an external URL or other scheme, or a relative asset like `./diagram.png`).
177
+ *
178
+ * The one reading `blume validate` checks links against and the Markdown
179
+ * pipeline rewrites them to, so the built `href`, the link check, and the
180
+ * browser agree. Relative paths resolve file-style: a leaf page's links
181
+ * resolve against its parent directory, while an index page's route already is
182
+ * its directory — `./install` on `guides/index.mdx` (`/guides`) lands on
183
+ * `/guides/install`, where a browser reading the slashless URL would go to
184
+ * `/install`. A `.md`/`.mdx` target is a file link: `resolveFile` maps its
185
+ * decoded path, relative to the linking file, to the route that file
186
+ * publishes at, so a target with its own `slug` or an ordering prefix still
187
+ * lands on its page instead of on its raw Markdown source. Without
188
+ * `resolveFile`, or for a file it doesn't know, the target resolves
189
+ * route-relative with the extension dropped.
190
+ *
191
+ * Any other extension (`./diagram.png`) marks an asset, except where a page
192
+ * publishes at the resolved path: `hasRoute` answers that, so a dotted page
193
+ * name (`./node.js` for `node.js.mdx`, `./v1.2`) is still a page link.
194
+ */
195
+ export const resolveRelativeHref = (
196
+ href: string,
197
+ from: RelativeLinkBase,
198
+ resolveFile?: (path: string) => string | undefined,
199
+ hasRoute?: (route: string) => boolean
200
+ ): string | undefined => {
201
+ if (href === "" || NOT_RELATIVE.test(href)) {
202
+ return undefined;
203
+ }
204
+ const suffixAt = href.search(/[?#]/u);
205
+ const path = suffixAt === -1 ? href : href.slice(0, suffixAt);
206
+ const suffix = suffixAt === -1 ? "" : href.slice(suffixAt);
207
+ if (FILE_EXT.test(path) && !DOC_EXT.test(path)) {
208
+ const route = toRoute(resolveRelative(from.route, path, from.isIndex));
209
+ return hasRoute?.(decodePercent(route)) ? `${route}${suffix}` : undefined;
210
+ }
211
+ const fileRoute = DOC_EXT.test(path)
212
+ ? resolveFile?.(decodePercent(path))
213
+ : undefined;
214
+ return `${fileRoute ?? toRoute(resolveRelative(from.route, path, from.isIndex))}${suffix}`;
215
+ };
216
+
217
+ /**
218
+ * Whether a content file is its folder's index, from its name as written on
219
+ * disk: `index.md(x)` after an ordering prefix, optionally carrying one of
220
+ * `localeTokens` before the extension (`index.fr.mdx` under the `dot` locale
221
+ * parser, `index.$.mdx` for a file shared by every locale).
222
+ */
223
+ export const isIndexFileName = (
224
+ name: string,
225
+ localeTokens: readonly string[] = []
226
+ ): boolean => {
227
+ const stem = basename(name).replace(NUMERIC_PREFIX, "");
228
+ const match = /^index(?:\.(?<token>[^./]+))?\.(?:md|mdx)$/iu.exec(stem);
229
+ if (!match) {
230
+ return false;
231
+ }
232
+ const token = match.groups?.token;
233
+ return token === undefined || localeTokens.includes(token);
234
+ };
235
+
159
236
  /** Build a map of route -> set of heading anchor slugs. */
160
237
  const buildAnchorIndex = (pages: PageRecord[]): Map<string, Set<string>> => {
161
238
  const anchors = new Map<string, Set<string>>();
@@ -329,6 +406,92 @@ const checkExternalLinks = async (
329
406
  return diagnostics;
330
407
  };
331
408
 
409
+ /** Where content files publish, for resolving file links (`./setup.mdx`). */
410
+ export interface FileRouteIndex {
411
+ /**
412
+ * Absolute source path → the route that file publishes at. A file shared by
413
+ * every locale publishes once per locale; the default locale's route stands
414
+ * for it (a link from a localized page moves into that locale afterwards,
415
+ * exactly as the rendered link does). Fallback copies render another
416
+ * locale's file, so they never stand for it.
417
+ */
418
+ bySource: Map<string, string>;
419
+ /**
420
+ * A default-locale page's locale-stripped path (`navPath`) → its route. A
421
+ * page in a locale folder that links a sibling not translated yet
422
+ * (`fr/guides/setup.mdx` missing) means the default tree's file
423
+ * (`guides/setup.mdx`), whose route — its own `slug` included — then moves
424
+ * into the reader's locale onto the fallback copy.
425
+ */
426
+ byDefaultNavPath: Map<string, string>;
427
+ }
428
+
429
+ /** The linking side of a file link: where the page's source lives. */
430
+ export interface FileLinkBase {
431
+ navPath: string;
432
+ sourcePath: string;
433
+ }
434
+
435
+ export const buildFileRouteIndex = (
436
+ pages: readonly PageRecord[],
437
+ i18n: LocaleRouting | null
438
+ ): FileRouteIndex => {
439
+ const bySource = new Map<string, string>();
440
+ const byDefaultNavPath = new Map<string, string>();
441
+ for (const page of pages) {
442
+ const { sourcePath } = page;
443
+ if (!sourcePath || page.fallback) {
444
+ continue;
445
+ }
446
+ const isDefault = page.locale === i18n?.defaultLocale;
447
+ if (!bySource.has(sourcePath) || isDefault) {
448
+ bySource.set(sourcePath, page.route);
449
+ }
450
+ if (isDefault) {
451
+ byDefaultNavPath.set(normalize(page.navPath), page.route);
452
+ }
453
+ }
454
+ return { byDefaultNavPath, bySource };
455
+ };
456
+
457
+ /**
458
+ * The route a file link written on `from` lands on: the linked file's own
459
+ * route, or — when a locale folder doesn't have that file yet — the default
460
+ * tree's file at the same place.
461
+ */
462
+ export const routeOfLinkedFile = (
463
+ index: FileRouteIndex,
464
+ from: FileLinkBase,
465
+ path: string
466
+ ): string | undefined =>
467
+ index.bySource.get(resolve(dirname(from.sourcePath), path)) ??
468
+ index.byDefaultNavPath.get(normalize(join(dirname(from.navPath), path)));
469
+
470
+ /**
471
+ * The path a relative link on `page` resolves to — the same reading the
472
+ * Markdown pipeline rewrites the rendered `href` to (see
473
+ * {@link resolveRelativeHref}), so what's checked is what ships. A relative
474
+ * asset (`./diagram.png`) isn't a page link; it resolves against the route's
475
+ * directory for the public-dir probe.
476
+ */
477
+ const relativeTarget = (
478
+ page: PageRecord,
479
+ rawPath: string,
480
+ ctx: LinkContext
481
+ ): string => {
482
+ const base = { isIndex: isIndexPage(page), route: page.route };
483
+ const { navPath, sourcePath } = page;
484
+ const resolveFile = sourcePath
485
+ ? (path: string) =>
486
+ routeOfLinkedFile(ctx.fileRoutes, { navPath, sourcePath }, path)
487
+ : undefined;
488
+ return (
489
+ resolveRelativeHref(rawPath, base, resolveFile, (route) =>
490
+ ctx.routes.has(route)
491
+ ) ?? resolveRelative(page.route, rawPath, base.isIndex)
492
+ );
493
+ };
494
+
332
495
  /** Classify a single link, queueing external refs via `onExternal`. */
333
496
  const classifyLink = (
334
497
  page: PageRecord,
@@ -382,7 +545,7 @@ const classifyLink = (
382
545
 
383
546
  const resolved = rawPath.startsWith("/")
384
547
  ? rawPath
385
- : resolveRelative(page.route, rawPath, isIndexPage(page));
548
+ : relativeTarget(page, rawPath, ctx);
386
549
  return checkPathLink(resolved, fragment, page, link, site, ctx, via);
387
550
  };
388
551
 
@@ -416,6 +579,7 @@ export const validateLinks = async (
416
579
  anchors: buildAnchorIndex(graph.pages),
417
580
  basePath,
418
581
  extraRoutes: new Set((options.extraRoutes ?? []).map(toRoute)),
582
+ fileRoutes: buildFileRouteIndex(graph.pages, options.i18n ?? null),
419
583
  i18n: options.i18n ?? null,
420
584
  publicDir: options.publicDir,
421
585
  redirects: new Set(
@@ -82,9 +82,14 @@ const buildFallbackRoutes = (
82
82
  if (!fallback) {
83
83
  return [];
84
84
  }
85
+ // A monolingual page (a GitHub release) publishes in one language only, so it
86
+ // gets no copy at every other locale's URL: those would be duplicates of the
87
+ // same text under a translated chrome.
85
88
  const fallbackPages = new Map(
86
89
  graph.pages.flatMap((page) =>
87
- page.locale === fallback ? [[page.translationKey, page] as const] : []
90
+ page.locale === fallback && !page.monolingual
91
+ ? [[page.translationKey, page] as const]
92
+ : []
88
93
  )
89
94
  );
90
95
  const routes: RouteManifestEntry[] = [];
@@ -126,6 +131,7 @@ const buildFallbackRoutes = (
126
131
  indexable: false,
127
132
  lastModified: source.lastModified,
128
133
  locale: code,
134
+ monolingual: source.monolingual,
129
135
  path,
130
136
  source: source.source,
131
137
  sourcePath: source.sourcePath,
@@ -145,7 +151,7 @@ export const buildManifest = (options: {
145
151
  graph: ContentGraph;
146
152
  }): BlumeManifest => {
147
153
  const { context, config, graph } = options;
148
- const searchEnabled = config.search.provider !== "none";
154
+ const searchEnabled = config.search.provider.mode !== "none";
149
155
  const { i18n } = config;
150
156
 
151
157
  // Real translations per logical page, for `hreflang` and the switcher. Built
@@ -189,6 +195,7 @@ export const buildManifest = (options: {
189
195
  indexable: searchEnabled && contentIndexable(page, config),
190
196
  lastModified: page.lastModified,
191
197
  locale: page.locale,
198
+ monolingual: page.monolingual,
192
199
  path: page.route,
193
200
  source: page.source,
194
201
  sourcePath: page.sourcePath,
@@ -234,7 +241,7 @@ export const buildManifest = (options: {
234
241
  return {
235
242
  blumeVersion: getBlumeVersion(),
236
243
  contentRoot: context.contentRoot,
237
- output: config.deployment.output,
244
+ output: config.deployment.options.output,
238
245
  projectRoot: context.root,
239
246
  routes,
240
247
  version: MANIFEST_VERSION,
@@ -43,12 +43,66 @@ export const isUnderPath = (route: string, base: string): boolean =>
43
43
  export const isRootTab = (tab: NavTab, root: string): boolean =>
44
44
  isUnderPath(root, tab.path);
45
45
 
46
+ /**
47
+ * A page's sidebar icon: `sidebar.icon`, or the top-level `icon` shorthand
48
+ * (the Mintlify-style spelling) when the nested key is unset.
49
+ */
50
+ const sidebarIcon = (page: PageRecord): string | undefined =>
51
+ page.meta.sidebar.icon ?? page.meta.icon;
52
+
53
+ /**
54
+ * Words a folder name spells in lowercase that read wrong capitalized: the
55
+ * acronyms and brand casings docs folders are named after (`api-reference`
56
+ * is "API Reference", not "Api Reference").
57
+ */
58
+ const WORD_FORMS = new Map([
59
+ ["ai", "AI"],
60
+ ["api", "API"],
61
+ ["apis", "APIs"],
62
+ ["asyncapi", "AsyncAPI"],
63
+ ["cli", "CLI"],
64
+ ["css", "CSS"],
65
+ ["faq", "FAQ"],
66
+ ["faqs", "FAQs"],
67
+ ["graphql", "GraphQL"],
68
+ ["html", "HTML"],
69
+ ["http", "HTTP"],
70
+ ["https", "HTTPS"],
71
+ ["id", "ID"],
72
+ ["ids", "IDs"],
73
+ ["ios", "iOS"],
74
+ ["js", "JS"],
75
+ ["json", "JSON"],
76
+ ["jwt", "JWT"],
77
+ ["llm", "LLM"],
78
+ ["llms", "LLMs"],
79
+ ["macos", "macOS"],
80
+ ["mcp", "MCP"],
81
+ ["oauth", "OAuth"],
82
+ ["openapi", "OpenAPI"],
83
+ ["rss", "RSS"],
84
+ ["sdk", "SDK"],
85
+ ["sdks", "SDKs"],
86
+ ["seo", "SEO"],
87
+ ["sql", "SQL"],
88
+ ["sso", "SSO"],
89
+ ["ts", "TS"],
90
+ ["ui", "UI"],
91
+ ["url", "URL"],
92
+ ["urls", "URLs"],
93
+ ["xml", "XML"],
94
+ ["yaml", "YAML"],
95
+ ]);
96
+
46
97
  const humanize = (segment: string): string =>
47
98
  segment
48
99
  .replace(NUMERIC_PREFIX, "")
49
100
  .split(WORD_SPLIT)
50
101
  .filter(Boolean)
51
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
102
+ .map(
103
+ (word) =>
104
+ WORD_FORMS.get(word) ?? word.charAt(0).toUpperCase() + word.slice(1)
105
+ )
52
106
  .join(" ");
53
107
 
54
108
  const numericOrder = (segment: string): number => {
@@ -112,6 +166,8 @@ interface MutableGroup {
112
166
  path: string;
113
167
  /** The group's URL path (folder route prefix); set as pages are inserted. */
114
168
  routePath?: string;
169
+ /** The folder's index page route, when it has one; the group row's link. */
170
+ route?: string;
115
171
  label: string;
116
172
  icon?: string;
117
173
  collapsed?: boolean;
@@ -214,8 +270,14 @@ const applyFolderMeta = (
214
270
  sharedMeta: Map<string, FolderMeta>,
215
271
  metaPrefix: string,
216
272
  sharedMetaPrefix: string,
217
- indexDisplay: Map<string, SidebarDisplay>
273
+ indexDisplay: Map<string, SidebarDisplay>,
274
+ indexRoute: Map<string, string>
218
275
  ): void => {
276
+ // A folder with an index page links its group row to it — the same shape
277
+ // as an explicit-config group's `root`, and the only sidebar link to the
278
+ // section's own page once the index row is hidden. Index-less folders keep
279
+ // no link: their row would 404.
280
+ group.route = indexRoute.get(group.path);
219
281
  // Locale-specific meta wins; a shared `meta.$.*` (keyed by the locale-stripped
220
282
  // group path — version-prefixed inside a snapshot) applies to every locale
221
283
  // otherwise.
@@ -254,7 +316,8 @@ const applyFolderMeta = (
254
316
  sharedMeta,
255
317
  metaPrefix,
256
318
  sharedMetaPrefix,
257
- indexDisplay
319
+ indexDisplay,
320
+ indexRoute
258
321
  );
259
322
  }
260
323
  }
@@ -267,6 +330,12 @@ const applyFolderMeta = (
267
330
  * update the folder's `meta.ts` and forget the index page's own frontmatter
268
331
  * (or vice versa), and a correct-looking sidebar hides the mismatch.
269
332
  *
333
+ * Only fires when the index page's own sidebar row is hidden
334
+ * (`sidebar.hidden`), so the linked group header is the only sidebar label the
335
+ * page has. A visible index row shows the page's own label beneath the header,
336
+ * so the sidebar already carries both titles and a divergence there is a
337
+ * deliberate pairing ("CLI" over "Overview"), not drift.
338
+ *
270
339
  * Only fires when the page has an explicit frontmatter `title` of its own:
271
340
  * when it's absent, `page.title` is derived from the first heading or the
272
341
  * filename, so it almost never coincidentally matches a custom folder title —
@@ -289,7 +358,11 @@ const indexTitleMismatchDiagnostic = (
289
358
  metaPrefix: string,
290
359
  sharedMetaPrefix: string
291
360
  ): Diagnostic | undefined => {
292
- if (!page.meta.title || page.fallback || folderPath === "") {
361
+ if (
362
+ !(page.meta.title && page.meta.sidebar.hidden) ||
363
+ page.fallback ||
364
+ folderPath === ""
365
+ ) {
293
366
  return undefined;
294
367
  }
295
368
  const meta =
@@ -510,6 +583,7 @@ const toNavNode = (node: MutableNode, display: SidebarDisplay): NavNode => {
510
583
  kind: "group",
511
584
  label: node.label,
512
585
  path: node.routePath,
586
+ route: node.route,
513
587
  };
514
588
  };
515
589
 
@@ -529,6 +603,11 @@ const buildFileSystemSidebar = (
529
603
  // Collected before the hidden filter (like the title check): hiding the index
530
604
  // row from the panel shouldn't stop it configuring its group.
531
605
  const indexDisplay = new Map<string, SidebarDisplay>();
606
+ // Folder path -> that folder's index page route, for the group row's link.
607
+ // Also collected before the hidden filter: hiding the index row is how a
608
+ // site drops the duplicate label under a linked header, so the link must
609
+ // survive it. The content root is not a group, so its index is skipped.
610
+ const indexRoute = new Map<string, string>();
532
611
 
533
612
  for (const page of pages) {
534
613
  // Group by the locale-stripped path so the locale dir is not a nav group.
@@ -537,8 +616,9 @@ const buildFileSystemSidebar = (
537
616
  const stem = stemOf(filename);
538
617
  const dirs = parts.slice(0, -1);
539
618
 
540
- // Checked before the hidden filter: a sidebar-hidden index page still
541
- // renders with its own <title>, so title drift matters there just the same.
619
+ // Checked before the hidden filter: the title check fires only for a
620
+ // sidebar-hidden index page, whose own <title> the header label stands in
621
+ // for, so it must see the pages the filter drops.
542
622
  if (isIndexStem(stem)) {
543
623
  const diagnostic = indexTitleMismatchDiagnostic(
544
624
  page,
@@ -558,6 +638,9 @@ const buildFileSystemSidebar = (
558
638
  if (page.meta.sidebar.display && !page.fallback) {
559
639
  indexDisplay.set(dirs.join("/"), page.meta.sidebar.display);
560
640
  }
641
+ if (dirs.length > 0) {
642
+ indexRoute.set(dirs.join("/"), page.route);
643
+ }
561
644
  }
562
645
 
563
646
  if (page.meta.sidebar.hidden) {
@@ -594,7 +677,7 @@ const buildFileSystemSidebar = (
594
677
  deprecated: page.meta.deprecated || undefined,
595
678
  description: page.description,
596
679
  file: page.sourcePath,
597
- icon: page.meta.sidebar.icon,
680
+ icon: sidebarIcon(page),
598
681
  key: segmentKey(stem),
599
682
  kind: "page",
600
683
  label: page.meta.sidebar.label ?? page.title,
@@ -611,7 +694,8 @@ const buildFileSystemSidebar = (
611
694
  sharedMeta,
612
695
  metaPrefix,
613
696
  sharedMetaPrefix,
614
- indexDisplay
697
+ indexDisplay,
698
+ indexRoute
615
699
  );
616
700
  sortNodes(root.children, diagnostics);
617
701
  hoistPages(root.children, display, true);
@@ -672,7 +756,7 @@ const configItemToNode = (
672
756
  badge: page.meta.sidebar.badge,
673
757
  deprecated: page.meta.deprecated || undefined,
674
758
  description: page.description,
675
- icon: page.meta.sidebar.icon,
759
+ icon: sidebarIcon(page),
676
760
  kind: "page",
677
761
  label: page.meta.sidebar.label ?? page.title,
678
762
  pageId: page.id,
@@ -741,10 +825,26 @@ const buildConfigSidebar = (
741
825
  /**
742
826
  * Resolve a tab's clickable target. A tab's `path` scopes its sidebar section
743
827
  * but need not be a real route — a section with no index page would 404 if the
744
- * tab linked straight to it. Prefer an exact page/group at the path; otherwise
745
- * fall back to the first linkable route in the section (sidebar order).
828
+ * tab linked straight to it. Prefer the path itself when it's served outside
829
+ * the content tree (the generated changelog index) or is a page/group in the
830
+ * tree; otherwise fall back to the first linkable route in the section
831
+ * (sidebar order).
832
+ *
833
+ * Routes outside the content tree are served at their own path, not under
834
+ * `basePath` (`pages/changelog.astro` answers `/changelog` on a `/docs`-based
835
+ * site), while tab paths arrive based (`/docs/changelog`). So when the based
836
+ * path is neither an outside route nor a tree node, the base-less path is
837
+ * checked against the outside routes before the section's first page wins.
746
838
  */
747
- const resolveTabHref = (sidebar: NavNode[], path: string): string => {
839
+ const resolveTabHref = (
840
+ sidebar: NavNode[],
841
+ path: string,
842
+ extraRoutes: ReadonlySet<string>,
843
+ basePath: string
844
+ ): string => {
845
+ if (extraRoutes.has(path)) {
846
+ return path;
847
+ }
748
848
  let first: string | undefined;
749
849
  const walk = (nodes: NavNode[]): boolean => {
750
850
  for (const node of nodes) {
@@ -765,19 +865,30 @@ const resolveTabHref = (sidebar: NavNode[], path: string): string => {
765
865
  }
766
866
  return false;
767
867
  };
768
- return walk(sidebar) ? path : (first ?? path);
868
+ if (walk(sidebar)) {
869
+ return path;
870
+ }
871
+ const bare = stripBasePath(basePath, path);
872
+ return extraRoutes.has(bare) ? bare : (first ?? path);
769
873
  };
770
874
 
771
875
  /**
772
876
  * Attach a resolved `href` to each tab whose section has no index page. An
773
877
  * author-declared `href` is the tab's stated target, so it's kept as-is —
774
878
  * resolution only fills in the tabs that didn't declare one. That's what lets a
775
- * tab point at a route outside the content tree (a generated `/changelog`
776
- * index, a custom `.astro` page), which resolution can't see.
879
+ * tab point at a route outside the content tree that resolution can't see (a
880
+ * custom `.astro` page); the generated changelog index arrives in
881
+ * `extraRoutes`, so a `/changelog` tab needs no `href`.
777
882
  */
778
- const withTabHrefs = (tabs: NavTab[], sidebar: NavNode[]): NavTab[] =>
883
+ const withTabHrefs = (
884
+ tabs: NavTab[],
885
+ sidebar: NavNode[],
886
+ extraRoutes: ReadonlySet<string>,
887
+ basePath: string
888
+ ): NavTab[] =>
779
889
  tabs.map((tab) => {
780
- const href = tab.href ?? resolveTabHref(sidebar, tab.path);
890
+ const href =
891
+ tab.href ?? resolveTabHref(sidebar, tab.path, extraRoutes, basePath);
781
892
  return href === tab.path ? tab : { ...tab, href };
782
893
  });
783
894
 
@@ -894,6 +1005,12 @@ export const buildNavigation = (
894
1005
  * into in place; omit to discard.
895
1006
  */
896
1007
  diagnostics?: Diagnostic[];
1008
+ /**
1009
+ * Routes served outside the content tree that a tab `path` may name
1010
+ * directly (the generated changelog index), so the tab links there instead
1011
+ * of falling back to its section's first page.
1012
+ */
1013
+ extraRoutes?: ReadonlySet<string>;
897
1014
  }
898
1015
  ): Navigation => {
899
1016
  const basePath = options.basePath ?? "";
@@ -901,6 +1018,7 @@ export const buildNavigation = (
901
1018
  const metaPrefix = options.metaPrefix ?? "";
902
1019
  const sharedMetaPrefix = options.sharedMetaPrefix ?? "";
903
1020
  const sharedFolderMeta = options.sharedFolderMeta ?? new Map();
1021
+ const extraRoutes = options.extraRoutes ?? new Set<string>();
904
1022
 
905
1023
  // Content-derived sidebar routes are already based via `page.route`; the
906
1024
  // based tab paths also feed tab-scoping below, so they must agree with the
@@ -962,7 +1080,7 @@ export const buildNavigation = (
962
1080
  root: rootTabPath,
963
1081
  selectors,
964
1082
  sidebar,
965
- tabs: withTabHrefs(tabs, sidebar),
1083
+ tabs: withTabHrefs(tabs, sidebar, extraRoutes, basePath),
966
1084
  };
967
1085
  }
968
1086
 
@@ -985,6 +1103,6 @@ export const buildNavigation = (
985
1103
  root: rootTabPath,
986
1104
  selectors,
987
1105
  sidebar,
988
- tabs: withTabHrefs(tabs, sidebar),
1106
+ tabs: withTabHrefs(tabs, sidebar, extraRoutes, basePath),
989
1107
  };
990
1108
  };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Links that open in a new tab. Every such link Blume renders — chrome (header
3
+ * actions, featured sidebar links, page actions), content components (Card,
4
+ * Tile, Tooltip), and Markdown links under `markdown.externalLinks` — points
5
+ * `aria-describedby` at one hidden, localized "Opens in a new tab" element each
6
+ * layout renders once per page, so screen-reader users hear the same warning
7
+ * sighted readers get from the arrow icon or the new tab itself.
8
+ */
9
+
10
+ import { isExternalUrl } from "./base-path.ts";
11
+
12
+ /** The id of the layout's hidden "Opens in a new tab" description. */
13
+ export const NEW_TAB_HINT_ID = "blume-new-tab-hint";
14
+
15
+ /** The attributes a new-tab link carries (spread onto an `<a>`). */
16
+ export interface NewTabAttrs {
17
+ "aria-describedby"?: string;
18
+ rel?: string;
19
+ target?: string;
20
+ }
21
+
22
+ /** A link that always opens in a new tab (a repo link, an edit link). */
23
+ export const NEW_TAB_ATTRS: NewTabAttrs = {
24
+ "aria-describedby": NEW_TAB_HINT_ID,
25
+ rel: "noreferrer",
26
+ target: "_blank",
27
+ };
28
+
29
+ /**
30
+ * {@link NEW_TAB_ATTRS} for an external href (the shared `isExternalUrl`
31
+ * predicate), and nothing for a site route, fragment, or `mailto:` link, which
32
+ * stay in the current tab.
33
+ */
34
+ export const newTabAttrs = (href?: string): NewTabAttrs =>
35
+ href !== undefined && isExternalUrl(href) ? NEW_TAB_ATTRS : {};
@@ -0,0 +1,21 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ /**
4
+ * Node's own `require`, for the SDKs and heavy modules Blume loads only when a
5
+ * feature needs them. Resolution starts from this file, inside the installed
6
+ * package, exactly like the `import()` it stands in for, and Node 22.12+ loads
7
+ * ES modules through it too.
8
+ *
9
+ * Never `import()` in their place. When Node can't import the generated Astro
10
+ * config itself — it refuses to strip types from TypeScript under
11
+ * `node_modules`, which is where an installed Blume's runtime source lives —
12
+ * Astro evaluates the config, and every Blume module it reaches, in a Vite
13
+ * module runner that it closes as soon as the config has loaded. A dynamic
14
+ * `import()` in one of those modules resolves through that runner, so a call
15
+ * made any later (an `astro:build:done` hook, a Markdown plugin) throws "Vite
16
+ * module runner has been closed". `require` is Node's, so it works however the
17
+ * calling module was evaluated. The repo itself never sees the failure: its
18
+ * workspace link puts Blume outside `node_modules`, so Node imports the config
19
+ * natively.
20
+ */
21
+ export const nodeRequire = createRequire(import.meta.url);