blume 2.0.1 → 2.0.2

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 (410) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/dist/cli/{chunk-vtk4a6dg.js → chunk-00gs3wqs.js} +1 -1
  3. package/dist/cli/{chunk-fa25z98p.js → chunk-273ygyr4.js} +4 -3
  4. package/dist/cli/chunk-273ygyr4.js.map +11 -0
  5. package/dist/cli/{chunk-yw7dm696.js → chunk-3yce002v.js} +21 -8
  6. package/dist/cli/{chunk-yw7dm696.js.map → chunk-3yce002v.js.map} +3 -3
  7. package/dist/cli/{chunk-yt5n7ppj.js → chunk-4e9b9ra6.js} +17 -7
  8. package/dist/cli/chunk-4e9b9ra6.js.map +10 -0
  9. package/dist/cli/{chunk-fs23ddbb.js → chunk-5r8g91qn.js} +352 -676
  10. package/dist/cli/chunk-5r8g91qn.js.map +34 -0
  11. package/dist/cli/{chunk-6vm74dry.js → chunk-6dtt0zfn.js} +8 -8
  12. package/dist/cli/{chunk-qwsrynx5.js → chunk-6k4ftwze.js} +38 -19
  13. package/dist/cli/{chunk-qwsrynx5.js.map → chunk-6k4ftwze.js.map} +4 -4
  14. package/dist/cli/{chunk-qs4q5p4e.js → chunk-7mbqtmgb.js} +16 -7
  15. package/dist/cli/chunk-7mbqtmgb.js.map +10 -0
  16. package/dist/cli/{chunk-q5163e60.js → chunk-7vtckvaw.js} +21 -19
  17. package/dist/cli/chunk-7vtckvaw.js.map +11 -0
  18. package/dist/cli/{chunk-kdp5q7ke.js → chunk-8g8ytmgx.js} +17 -18
  19. package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-8g8ytmgx.js.map} +2 -2
  20. package/dist/cli/{chunk-epjnccmv.js → chunk-91ws1n6j.js} +18 -15
  21. package/dist/cli/chunk-91ws1n6j.js.map +10 -0
  22. package/dist/cli/{chunk-fxypxtvm.js → chunk-bbnwccaz.js} +2 -2
  23. package/dist/cli/{chunk-m3vmjgmq.js → chunk-bfwp9vp6.js} +16 -8
  24. package/dist/cli/chunk-bfwp9vp6.js.map +10 -0
  25. package/dist/cli/{chunk-f2z5v128.js → chunk-d1v5rhy0.js} +14 -15
  26. package/dist/cli/{chunk-f2z5v128.js.map → chunk-d1v5rhy0.js.map} +2 -2
  27. package/dist/cli/{chunk-6crbhc3x.js → chunk-ddndchfr.js} +21 -6
  28. package/dist/cli/chunk-ddndchfr.js.map +14 -0
  29. package/dist/cli/{chunk-ce574jw2.js → chunk-esh98wmb.js} +1 -1
  30. package/dist/cli/{chunk-zxcczpyx.js → chunk-fsmrqk8a.js} +1 -1
  31. package/dist/cli/{chunk-hdpx1tax.js → chunk-g698a744.js} +5 -5
  32. package/dist/cli/{chunk-jts8mvcz.js → chunk-gs7r695n.js} +9 -3
  33. package/dist/cli/{chunk-jts8mvcz.js.map → chunk-gs7r695n.js.map} +3 -3
  34. package/dist/cli/{chunk-zxh4d9vy.js → chunk-h2ez8dzb.js} +4 -4
  35. package/dist/cli/{chunk-5shv93fd.js → chunk-h7k3nq3v.js} +2 -2
  36. package/dist/cli/{chunk-79jhk4py.js → chunk-hqp2ajnh.js} +251 -122
  37. package/dist/cli/chunk-hqp2ajnh.js.map +35 -0
  38. package/dist/cli/{chunk-2hn4b8z7.js → chunk-hr8ne106.js} +109 -40
  39. package/dist/cli/chunk-hr8ne106.js.map +13 -0
  40. package/dist/cli/{chunk-6hsn950k.js → chunk-j85scx15.js} +62 -18
  41. package/dist/cli/chunk-j85scx15.js.map +10 -0
  42. package/dist/cli/{chunk-s1p84fyh.js → chunk-k7pj68a8.js} +63 -22
  43. package/dist/cli/chunk-k7pj68a8.js.map +11 -0
  44. package/dist/cli/{chunk-ah61y8py.js → chunk-mqc662a6.js} +2 -2
  45. package/dist/cli/{chunk-ch6g3ar0.js → chunk-n1yg3tj3.js} +4 -4
  46. package/dist/cli/{chunk-mb2919y2.js → chunk-nfcyttvj.js} +17 -6
  47. package/dist/cli/chunk-nfcyttvj.js.map +10 -0
  48. package/dist/cli/{chunk-kpf8rrjc.js → chunk-pbg5a4s3.js} +56 -24
  49. package/dist/cli/chunk-pbg5a4s3.js.map +19 -0
  50. package/dist/cli/{chunk-jwyddg7y.js → chunk-ppzjqwx2.js} +21 -14
  51. package/dist/cli/{chunk-jwyddg7y.js.map → chunk-ppzjqwx2.js.map} +4 -4
  52. package/dist/cli/{chunk-dh8cwk36.js → chunk-qkb5a8sa.js} +24 -9
  53. package/dist/cli/chunk-qkb5a8sa.js.map +10 -0
  54. package/dist/cli/{chunk-wm7js3j9.js → chunk-sqw4ekg1.js} +2 -2
  55. package/dist/cli/{chunk-qkqwkpte.js → chunk-v6ya5kcb.js} +3083 -953
  56. package/dist/cli/chunk-v6ya5kcb.js.map +189 -0
  57. package/dist/cli/{chunk-fz5wtpmh.js → chunk-w4bxdvsa.js} +18 -15
  58. package/dist/cli/chunk-w4bxdvsa.js.map +10 -0
  59. package/dist/cli/{chunk-27g6wdth.js → chunk-wdrt2k2v.js} +2 -2
  60. package/dist/cli/{chunk-wgm7m9qk.js → chunk-xh43dwgw.js} +158 -43
  61. package/dist/cli/chunk-xh43dwgw.js.map +36 -0
  62. package/dist/cli/{chunk-s6jhgk0q.js → chunk-zp79m0ts.js} +2 -2
  63. package/dist/cli/index.js +160 -35
  64. package/dist/cli/index.js.map +4 -4
  65. package/dist/types/ai/agent-surface.d.ts +32 -0
  66. package/dist/types/ai/api-catalog.d.ts +7 -1
  67. package/dist/types/ai/ask-context.d.ts +7 -0
  68. package/dist/types/ai/component-markdown.d.ts +4 -4
  69. package/dist/types/ai/relative-links.d.ts +9 -4
  70. package/dist/types/ai/static-expression.d.ts +28 -0
  71. package/dist/types/analytics/databuddy.d.ts +43 -0
  72. package/dist/types/analytics/index.d.ts +2 -0
  73. package/dist/types/analytics/schema.d.ts +14 -0
  74. package/dist/types/cli/env.d.ts +5 -0
  75. package/dist/types/cli/init/scaffold.d.ts +19 -3
  76. package/dist/types/cli/init/starter-spec.d.ts +11 -0
  77. package/dist/types/core/base-path.d.ts +9 -0
  78. package/dist/types/core/config-input.d.ts +4 -4
  79. package/dist/types/core/config.d.ts +2 -2
  80. package/dist/types/core/graph.d.ts +2 -0
  81. package/dist/types/core/i18n-ui.d.ts +31 -0
  82. package/dist/types/core/i18n.d.ts +7 -1
  83. package/dist/types/core/links.d.ts +3 -1
  84. package/dist/types/core/load-module.d.ts +10 -0
  85. package/dist/types/core/locale-links.d.ts +12 -2
  86. package/dist/types/core/meta.d.ts +5 -1
  87. package/dist/types/core/nav-diagnostics.d.ts +10 -0
  88. package/dist/types/core/navigation.d.ts +38 -0
  89. package/dist/types/core/ordering-prefix.d.ts +4 -0
  90. package/dist/types/core/safe-links.d.ts +3 -1
  91. package/dist/types/core/schema.d.ts +52 -13
  92. package/dist/types/core/sources/github-releases.d.ts +5 -0
  93. package/dist/types/core/sources/lower.d.ts +14 -2
  94. package/dist/types/core/sources/normalize.d.ts +10 -1
  95. package/dist/types/core/sources/remote.d.ts +11 -1
  96. package/dist/types/core/sources/resolve.d.ts +12 -0
  97. package/dist/types/core/sources/types.d.ts +31 -0
  98. package/dist/types/core/types.d.ts +9 -0
  99. package/dist/types/deploy/adapters/node.d.ts +5 -2
  100. package/dist/types/deploy/adapters/types.d.ts +7 -0
  101. package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
  102. package/dist/types/deploy/headers.d.ts +31 -7
  103. package/dist/types/deploy/node-headers.d.ts +43 -8
  104. package/dist/types/deploy/platforms/netlify.d.ts +27 -2
  105. package/dist/types/deploy/platforms/node.d.ts +6 -5
  106. package/dist/types/deploy/platforms/types.d.ts +7 -0
  107. package/dist/types/deploy/platforms/vercel.d.ts +3 -2
  108. package/dist/types/deploy/redirects.d.ts +7 -2
  109. package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
  110. package/dist/types/openapi/model.d.ts +20 -6
  111. package/dist/types/search/sync/algolia.d.ts +3 -1
  112. package/docs/01-quickstart.mdx +3 -2
  113. package/docs/02-deployment.mdx +17 -8
  114. package/docs/08-faq.mdx +9 -2
  115. package/docs/advanced/changelog.mdx +1 -1
  116. package/docs/advanced/custom-pages.mdx +4 -2
  117. package/docs/cli/audit.mdx +2 -2
  118. package/docs/cli/doctor.mdx +2 -2
  119. package/docs/cli/evals.mdx +2 -2
  120. package/docs/cli/index.mdx +4 -1
  121. package/docs/cli/translate.mdx +1 -1
  122. package/docs/configuration/analytics.mdx +23 -2
  123. package/docs/configuration/assistant.mdx +1 -1
  124. package/docs/configuration/customization.mdx +4 -3
  125. package/docs/configuration/index.mdx +5 -3
  126. package/docs/configuration/search.mdx +1 -1
  127. package/docs/content/components.mdx +1 -1
  128. package/docs/content/frontmatter.mdx +5 -1
  129. package/docs/content/i18n.mdx +1 -1
  130. package/docs/content/index.mdx +4 -2
  131. package/docs/content/meta.mdx +5 -3
  132. package/docs/content/navigation.mdx +29 -4
  133. package/docs/content/sources.mdx +18 -12
  134. package/docs/content/versioning.mdx +1 -0
  135. package/docs/discoverability/agent-discovery.mdx +21 -7
  136. package/docs/discoverability/index.mdx +2 -2
  137. package/docs/discoverability/llms-txt.mdx +2 -5
  138. package/docs/discoverability/markdown.mdx +5 -3
  139. package/docs/discoverability/mcp.mdx +4 -0
  140. package/docs/discoverability/metadata.mdx +3 -2
  141. package/docs/discoverability/open-graph.mdx +6 -4
  142. package/docs/discoverability/rss.mdx +3 -1
  143. package/docs/references/asyncapi.mdx +1 -1
  144. package/docs/references/graphql.mdx +2 -2
  145. package/docs/references/openapi.mdx +3 -3
  146. package/package.json +1 -1
  147. package/skills/blume-migrate/SKILL.md +6 -6
  148. package/skills/blume-migrate/references/docusaurus.md +6 -6
  149. package/skills/blume-migrate/references/mintlify.md +3 -3
  150. package/skills/blume-migrate/references/monorepo.md +1 -1
  151. package/skills/blume-migrate/references/nextra.md +1 -1
  152. package/skills/blume-migrate/references/starlight.md +5 -5
  153. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +2 -2
  154. package/skills/blume-update-docs/references/audit-checklist.md +1 -1
  155. package/src/ai/agent-surface.ts +56 -0
  156. package/src/ai/api/spec.ts +15 -2
  157. package/src/ai/api-catalog.ts +7 -1
  158. package/src/ai/ask-context.ts +14 -2
  159. package/src/ai/ask-data.ts +26 -12
  160. package/src/ai/component-markdown.ts +43 -37
  161. package/src/ai/link-headers.ts +8 -3
  162. package/src/ai/llms.ts +4 -3
  163. package/src/ai/markdown.ts +23 -11
  164. package/src/ai/mcp/server.ts +78 -7
  165. package/src/ai/relative-links.ts +78 -10
  166. package/src/ai/static-expression.ts +416 -0
  167. package/src/ai/visibility.ts +45 -14
  168. package/src/analytics/databuddy.ts +67 -0
  169. package/src/analytics/head.ts +4 -0
  170. package/src/analytics/index.ts +2 -0
  171. package/src/analytics/posthog.ts +21 -3
  172. package/src/analytics/schema.ts +2 -0
  173. package/src/astro/generate.ts +71 -27
  174. package/src/astro/templates.ts +61 -23
  175. package/src/audit/catalog.ts +2 -2
  176. package/src/audit/checks/assets.ts +25 -5
  177. package/src/audit/checks/content.ts +20 -2
  178. package/src/audit/checks/i18n.ts +46 -8
  179. package/src/audit/checks/indexability.ts +39 -19
  180. package/src/audit/checks/links.ts +14 -0
  181. package/src/audit/checks/llms.ts +6 -3
  182. package/src/audit/checks/network.ts +3 -1
  183. package/src/audit/checks/og-image.ts +10 -0
  184. package/src/audit/checks/robots.ts +6 -1
  185. package/src/audit/checks/sitemap.ts +56 -31
  186. package/src/audit/checks/social.ts +21 -2
  187. package/src/audit/crawl.ts +88 -15
  188. package/src/audit/report.ts +54 -17
  189. package/src/audit/run.ts +1 -0
  190. package/src/audit/types.ts +18 -0
  191. package/src/audit/url.ts +37 -6
  192. package/src/cli/build-failure.ts +50 -0
  193. package/src/cli/commands/audit.ts +7 -0
  194. package/src/cli/commands/build.ts +19 -5
  195. package/src/cli/commands/check.ts +2 -0
  196. package/src/cli/commands/eval.ts +1 -7
  197. package/src/cli/commands/init.ts +15 -5
  198. package/src/cli/commands/preview.ts +15 -0
  199. package/src/cli/commands/sync.ts +2 -0
  200. package/src/cli/commands/translate.ts +9 -6
  201. package/src/cli/commands/upgrade.ts +11 -0
  202. package/src/cli/eject-scripts.ts +32 -7
  203. package/src/cli/env.ts +12 -1
  204. package/src/cli/init/scaffold.ts +117 -11
  205. package/src/cli/init/starter-spec.ts +235 -0
  206. package/src/components/content/AccordionItem.astro +26 -22
  207. package/src/components/content/Badge.astro +2 -9
  208. package/src/components/content/Card.astro +2 -2
  209. package/src/components/content/Component.astro +9 -3
  210. package/src/components/content/Expandable.astro +5 -1
  211. package/src/components/content/Frame.astro +2 -7
  212. package/src/components/content/GithubInfo.astro +12 -2
  213. package/src/components/content/Prompt.astro +2 -7
  214. package/src/components/content/Tabs.astro +54 -5
  215. package/src/components/content/Tile.astro +1 -1
  216. package/src/components/content/Tooltip.astro +69 -7
  217. package/src/components/content/Tree.astro +7 -2
  218. package/src/components/content/TypeTable.astro +10 -5
  219. package/src/components/content/Update.astro +8 -2
  220. package/src/components/content/auto-type-table.ts +4 -1
  221. package/src/components/content/badge-color.ts +17 -0
  222. package/src/components/content/base-href.ts +18 -3
  223. package/src/components/content/inline-markdown.ts +27 -7
  224. package/src/components/copy-feedback.ts +35 -8
  225. package/src/components/islands/assistant.tsx +16 -2
  226. package/src/components/islands/hooks.ts +7 -2
  227. package/src/components/islands/webmcp.ts +12 -8
  228. package/src/components/layout/Banner.astro +23 -4
  229. package/src/components/layout/Header.astro +22 -9
  230. package/src/components/layout/Logo.astro +5 -0
  231. package/src/components/layout/NavSelector.astro +6 -1
  232. package/src/components/layout/NavTabMenu.astro +133 -0
  233. package/src/components/layout/NavTree.astro +15 -6
  234. package/src/components/layout/NavTreeCache.astro +5 -2
  235. package/src/components/layout/NavTreeScript.astro +45 -5
  236. package/src/components/layout/PageLayout.astro +22 -8
  237. package/src/components/layout/ReferenceLayout.astro +4 -1
  238. package/src/components/layout/RootLayout.astro +21 -8
  239. package/src/components/layout/Search.astro +5 -1
  240. package/src/components/layout/analytics-client.ts +2 -0
  241. package/src/components/openapi/GraphqlType.astro +11 -3
  242. package/src/components/openapi/MessageComposer.astro +1 -1
  243. package/src/components/openapi/Operation.astro +21 -5
  244. package/src/components/openapi/PanelTabs.astro +4 -1
  245. package/src/components/openapi/Playground.astro +8 -2
  246. package/src/components/openapi/RequestPanel.astro +9 -5
  247. package/src/components/openapi/SchemaProperty.astro +11 -33
  248. package/src/components/openapi/SchemaTable.astro +27 -52
  249. package/src/components/openapi/helpers.ts +90 -12
  250. package/src/components/openapi/message-composer.ts +8 -0
  251. package/src/components/openapi/message-model.ts +12 -2
  252. package/src/components/openapi/message.ts +4 -1
  253. package/src/components/openapi/operation-model.ts +40 -8
  254. package/src/components/openapi/panel.ts +29 -5
  255. package/src/components/openapi/playground-client.ts +37 -7
  256. package/src/components/openapi/playground-schema.ts +25 -6
  257. package/src/components/openapi/request.ts +2 -0
  258. package/src/components/openapi/schema-tree.ts +203 -0
  259. package/src/components/openapi/snippets.ts +30 -15
  260. package/src/components/openapi/validate-json.ts +1 -1
  261. package/src/core/base-path.ts +15 -0
  262. package/src/core/config-input.ts +4 -4
  263. package/src/core/config.ts +18 -4
  264. package/src/core/diagnostics.ts +217 -30
  265. package/src/core/graph.ts +120 -11
  266. package/src/core/i18n-ui.ts +39 -2
  267. package/src/core/i18n.ts +13 -2
  268. package/src/core/links.ts +7 -4
  269. package/src/core/load-module.ts +20 -0
  270. package/src/core/locale-links.ts +17 -17
  271. package/src/core/manifest.ts +3 -2
  272. package/src/core/meta.ts +69 -6
  273. package/src/core/nav-diagnostics.ts +56 -1
  274. package/src/core/navigation.ts +245 -76
  275. package/src/core/ordering-prefix.ts +27 -0
  276. package/src/core/project-graph.ts +23 -1
  277. package/src/core/safe-href.ts +53 -1
  278. package/src/core/safe-links.ts +11 -2
  279. package/src/core/schema.ts +70 -14
  280. package/src/core/sources/assets.ts +83 -41
  281. package/src/core/sources/contentful-rich-text.ts +3 -2
  282. package/src/core/sources/contentful.ts +25 -12
  283. package/src/core/sources/filesystem.ts +5 -1
  284. package/src/core/sources/github-releases.ts +106 -5
  285. package/src/core/sources/lexical.ts +9 -4
  286. package/src/core/sources/lower.ts +79 -26
  287. package/src/core/sources/mdx-remote.ts +1 -0
  288. package/src/core/sources/normalize.ts +132 -30
  289. package/src/core/sources/notion.ts +26 -10
  290. package/src/core/sources/obsidian.ts +17 -3
  291. package/src/core/sources/payload.ts +1 -0
  292. package/src/core/sources/portable-text.ts +63 -44
  293. package/src/core/sources/remote.ts +18 -2
  294. package/src/core/sources/resolve.ts +52 -33
  295. package/src/core/sources/sanity.ts +1 -0
  296. package/src/core/sources/strapi-blocks.ts +9 -4
  297. package/src/core/sources/strapi.ts +1 -0
  298. package/src/core/sources/types.ts +31 -0
  299. package/src/core/types.ts +9 -0
  300. package/src/core/ui-packs/ar.ts +13 -0
  301. package/src/core/ui-packs/bg.ts +13 -0
  302. package/src/core/ui-packs/bn.ts +13 -0
  303. package/src/core/ui-packs/ca.ts +13 -0
  304. package/src/core/ui-packs/cs.ts +13 -0
  305. package/src/core/ui-packs/da.ts +13 -0
  306. package/src/core/ui-packs/de.ts +13 -0
  307. package/src/core/ui-packs/el.ts +13 -0
  308. package/src/core/ui-packs/es.ts +13 -0
  309. package/src/core/ui-packs/fa.ts +13 -0
  310. package/src/core/ui-packs/fi.ts +13 -0
  311. package/src/core/ui-packs/fr.ts +13 -0
  312. package/src/core/ui-packs/he.ts +13 -0
  313. package/src/core/ui-packs/hi.ts +13 -0
  314. package/src/core/ui-packs/hr.ts +13 -0
  315. package/src/core/ui-packs/hu.ts +13 -0
  316. package/src/core/ui-packs/id.ts +13 -0
  317. package/src/core/ui-packs/it.ts +13 -0
  318. package/src/core/ui-packs/ja.ts +13 -0
  319. package/src/core/ui-packs/ko.ts +13 -0
  320. package/src/core/ui-packs/nl.ts +13 -0
  321. package/src/core/ui-packs/no.ts +13 -0
  322. package/src/core/ui-packs/pl.ts +13 -0
  323. package/src/core/ui-packs/pt-br.ts +13 -0
  324. package/src/core/ui-packs/pt.ts +13 -0
  325. package/src/core/ui-packs/ro.ts +13 -0
  326. package/src/core/ui-packs/ru.ts +13 -0
  327. package/src/core/ui-packs/sk.ts +13 -0
  328. package/src/core/ui-packs/sr.ts +13 -0
  329. package/src/core/ui-packs/sv.ts +13 -0
  330. package/src/core/ui-packs/th.ts +13 -0
  331. package/src/core/ui-packs/tr.ts +13 -0
  332. package/src/core/ui-packs/uk.ts +13 -0
  333. package/src/core/ui-packs/vi.ts +13 -0
  334. package/src/core/ui-packs/zh-tw.ts +13 -0
  335. package/src/core/ui-packs/zh.ts +13 -0
  336. package/src/core/version-cut.ts +17 -2
  337. package/src/core/versions.ts +4 -1
  338. package/src/deploy/adapters/node.ts +5 -2
  339. package/src/deploy/adapters/registry.ts +2 -1
  340. package/src/deploy/adapters/types.ts +13 -1
  341. package/src/deploy/artifacts.ts +25 -5
  342. package/src/deploy/cloudflare-negotiation.ts +23 -4
  343. package/src/deploy/headers.ts +67 -51
  344. package/src/deploy/node-headers.ts +148 -27
  345. package/src/deploy/platforms/cloudflare.ts +1 -0
  346. package/src/deploy/platforms/netlify.ts +82 -5
  347. package/src/deploy/platforms/node.ts +7 -5
  348. package/src/deploy/platforms/static.ts +1 -0
  349. package/src/deploy/platforms/types.ts +7 -0
  350. package/src/deploy/platforms/vercel.ts +9 -3
  351. package/src/deploy/redirects.ts +14 -3
  352. package/src/deploy/vercel-negotiation.ts +35 -3
  353. package/src/eval/agents.ts +10 -2
  354. package/src/eval/run.ts +25 -0
  355. package/src/markdown/base-links.ts +55 -8
  356. package/src/markdown/index.ts +6 -3
  357. package/src/markdown/relative-links.ts +3 -23
  358. package/src/markdown/route-snapshot.ts +37 -0
  359. package/src/og/card.ts +20 -4
  360. package/src/og/derive.ts +145 -4
  361. package/src/openapi/graphql-build.ts +28 -2
  362. package/src/openapi/model.ts +77 -13
  363. package/src/openapi/render-mdx.ts +10 -1
  364. package/src/registry/eject.ts +119 -22
  365. package/src/search/documents.ts +22 -1
  366. package/src/search/sync/algolia.ts +36 -2
  367. package/src/sources/registry.ts +5 -0
  368. package/src/theme/entry.ts +11 -4
  369. package/src/translate/agents.ts +6 -1
  370. package/src/translate/ledger.ts +26 -3
  371. package/src/translate/meta.ts +11 -3
  372. package/src/translate/run.ts +11 -5
  373. package/src/translate/validate.ts +10 -1
  374. package/src/translate/work-list.ts +36 -3
  375. package/src/upgrade/upgrade.ts +36 -4
  376. package/dist/cli/chunk-2hn4b8z7.js.map +0 -12
  377. package/dist/cli/chunk-6crbhc3x.js.map +0 -14
  378. package/dist/cli/chunk-6hsn950k.js.map +0 -10
  379. package/dist/cli/chunk-79jhk4py.js.map +0 -35
  380. package/dist/cli/chunk-82bbrxdn.js +0 -51
  381. package/dist/cli/chunk-82bbrxdn.js.map +0 -10
  382. package/dist/cli/chunk-abh8yjkn.js +0 -31
  383. package/dist/cli/chunk-abh8yjkn.js.map +0 -10
  384. package/dist/cli/chunk-dh8cwk36.js.map +0 -10
  385. package/dist/cli/chunk-epjnccmv.js.map +0 -10
  386. package/dist/cli/chunk-fa25z98p.js.map +0 -11
  387. package/dist/cli/chunk-fs23ddbb.js.map +0 -35
  388. package/dist/cli/chunk-fz5wtpmh.js.map +0 -10
  389. package/dist/cli/chunk-kpf8rrjc.js.map +0 -19
  390. package/dist/cli/chunk-m3vmjgmq.js.map +0 -10
  391. package/dist/cli/chunk-mb2919y2.js.map +0 -10
  392. package/dist/cli/chunk-q5163e60.js.map +0 -11
  393. package/dist/cli/chunk-qkqwkpte.js.map +0 -182
  394. package/dist/cli/chunk-qs4q5p4e.js.map +0 -10
  395. package/dist/cli/chunk-s1p84fyh.js.map +0 -10
  396. package/dist/cli/chunk-wgm7m9qk.js.map +0 -36
  397. package/dist/cli/chunk-yt5n7ppj.js.map +0 -10
  398. /package/dist/cli/{chunk-vtk4a6dg.js.map → chunk-00gs3wqs.js.map} +0 -0
  399. /package/dist/cli/{chunk-6vm74dry.js.map → chunk-6dtt0zfn.js.map} +0 -0
  400. /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-bbnwccaz.js.map} +0 -0
  401. /package/dist/cli/{chunk-ce574jw2.js.map → chunk-esh98wmb.js.map} +0 -0
  402. /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-fsmrqk8a.js.map} +0 -0
  403. /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-g698a744.js.map} +0 -0
  404. /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-h2ez8dzb.js.map} +0 -0
  405. /package/dist/cli/{chunk-5shv93fd.js.map → chunk-h7k3nq3v.js.map} +0 -0
  406. /package/dist/cli/{chunk-ah61y8py.js.map → chunk-mqc662a6.js.map} +0 -0
  407. /package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-n1yg3tj3.js.map} +0 -0
  408. /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-sqw4ekg1.js.map} +0 -0
  409. /package/dist/cli/{chunk-27g6wdth.js.map → chunk-wdrt2k2v.js.map} +0 -0
  410. /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-zp79m0ts.js.map} +0 -0
package/src/core/links.ts CHANGED
@@ -109,10 +109,11 @@ const NUMERIC_PREFIX = /^\d+[-_.]/u;
109
109
  * falsely flagged as broken. Tested against `navPath` — the locale-stripped
110
110
  * path — so a dot-parser localized index (`index.fr.mdx`) and a shared
111
111
  * locale-agnostic one (`index.$.mdx`) count too, matching how route mapping
112
- * recognizes them.
112
+ * recognizes them. Only a lowercase `index` counts, as in route mapping:
113
+ * `Index.md` publishes at `…/Index`, a page of its own.
113
114
  */
114
115
  const isIndexPage = (page: PageRecord): boolean =>
115
- /^index\.(?:md|mdx)$/iu.test(
116
+ /^index\.[Mm][Dd][Xx]?$/u.test(
116
117
  basename(page.navPath).replace(NUMERIC_PREFIX, "")
117
118
  );
118
119
 
@@ -218,14 +219,16 @@ export const resolveRelativeHref = (
218
219
  * Whether a content file is its folder's index, from its name as written on
219
220
  * disk: `index.md(x)` after an ordering prefix, optionally carrying one of
220
221
  * `localeTokens` before the extension (`index.fr.mdx` under the `dot` locale
221
- * parser, `index.$.mdx` for a file shared by every locale).
222
+ * parser, `index.$.mdx` for a file shared by every locale). The `index` itself
223
+ * is case-sensitive, as route mapping reads it: `Index.md` is a page named
224
+ * `Index`, not its folder's index.
222
225
  */
223
226
  export const isIndexFileName = (
224
227
  name: string,
225
228
  localeTokens: readonly string[] = []
226
229
  ): boolean => {
227
230
  const stem = basename(name).replace(NUMERIC_PREFIX, "");
228
- const match = /^index(?:\.(?<token>[^./]+))?\.(?:md|mdx)$/iu.exec(stem);
231
+ const match = /^index(?:\.(?<token>[^./]+))?\.[Mm][Dd][Xx]?$/u.exec(stem);
229
232
  if (!match) {
230
233
  return false;
231
234
  }
@@ -14,3 +14,23 @@ export const createModuleLoader = (): ((file: string) => Promise<unknown>) => {
14
14
  return loaded?.default ?? loaded;
15
15
  };
16
16
  };
17
+
18
+ /**
19
+ * Create a loader for a module whose default export is its whole value
20
+ * (`blume.config.ts`). Unlike {@link createModuleLoader}, it never falls back
21
+ * to the module's namespace: a module with no default export, or one that
22
+ * exports `null`/`undefined`, resolves to `undefined` so the caller can say
23
+ * so, instead of validating `{}` (a bare `defineConfig({…})` call) or
24
+ * `{ config }` (a named export). jiti's default interop is off because it
25
+ * throws on `export default null`.
26
+ */
27
+ export const createDefaultExportLoader: typeof createModuleLoader = () => {
28
+ const jiti = createJiti(import.meta.url, {
29
+ interopDefault: false,
30
+ moduleCache: false,
31
+ });
32
+ return async (file: string) => {
33
+ const loaded = await jiti.import<{ default?: unknown }>(file);
34
+ return loaded.default ?? undefined;
35
+ };
36
+ };
@@ -44,13 +44,6 @@ export interface LocalizeLinkOptions {
44
44
  routes: RouteSet;
45
45
  }
46
46
 
47
- /**
48
- * Mirrors the asset heuristic in `markdown/base-links.ts`: a path whose final
49
- * segment carries a file extension is a `public/` asset (or a raw `.md` twin),
50
- * served at the site root and never localized.
51
- */
52
- const ASSET_PATH = /\.[a-z0-9]+$/iu;
53
-
54
47
  /** Decode a percent-encoded path for a route lookup; leave junk as-is. */
55
48
  const decodePercent = (value: string): string => {
56
49
  try {
@@ -60,6 +53,13 @@ const decodePercent = (value: string): string => {
60
53
  }
61
54
  };
62
55
 
56
+ /**
57
+ * Whether `routes` serves `route` (base-prefixed, fragment-less). Routes are
58
+ * stored decoded, so a browser-copied `/caf%C3%A9` still finds its page.
59
+ */
60
+ export const servesRoute = (routes: RouteSet, route: string): boolean =>
61
+ routes.has(route) || routes.has(decodePercent(route));
62
+
63
63
  /** Whether `path` (base-stripped) already sits under some locale's prefix. */
64
64
  const hasLocalePrefix = (path: string, i18n: LocaleRouting): boolean =>
65
65
  i18n.locales.some((locale) => {
@@ -85,11 +85,9 @@ export const localizeLinkPath = (
85
85
  return path;
86
86
  }
87
87
  const localized = withBasePath(basePath, localizeRoute(rest, locale, i18n));
88
- // Routes are stored decoded; a browser-copied `/caf%C3%A9` must still find
89
- // its translation, but the emitted href keeps the author's encoding.
90
- return routes.has(localized) || routes.has(decodePercent(localized))
91
- ? localized
92
- : path;
88
+ // A browser-copied `/caf%C3%A9` must still find its translation, but the
89
+ // emitted href keeps the author's encoding.
90
+ return servesRoute(routes, localized) ? localized : path;
93
91
  };
94
92
 
95
93
  export interface LocalizeHrefOptions extends LocalizeLinkOptions {
@@ -98,9 +96,14 @@ export interface LocalizeHrefOptions extends LocalizeLinkOptions {
98
96
  }
99
97
 
100
98
  /**
101
- * Localize a rendered `href`: external URLs, relative paths, bare fragments, and
102
- * asset links pass through; a root-relative page link keeps its `?query` and
99
+ * Localize a rendered `href`: external URLs, relative paths, and bare
100
+ * fragments pass through; a root-relative page link keeps its `?query` and
103
101
  * `#fragment` and its `deployment.base` layer around the localized path.
102
+ *
103
+ * Asset links (`/logo.png`, a raw `.md` twin) pass through too, because no
104
+ * page is served at their localized path — the same served-route test the
105
+ * link checker applies. A file extension alone doesn't mark an asset: a
106
+ * dotted page route (`/releases/v1.2`) is localized like any other page.
104
107
  */
105
108
  export const localizeHref = (
106
109
  href: string,
@@ -112,9 +115,6 @@ export const localizeHref = (
112
115
  const suffixAt = href.search(/[#?]/u);
113
116
  const path = suffixAt === -1 ? href : href.slice(0, suffixAt);
114
117
  const suffix = suffixAt === -1 ? "" : href.slice(suffixAt);
115
- if (ASSET_PATH.test(path)) {
116
- return href;
117
- }
118
118
  const based = stripBasePath(options.deployBase, path);
119
119
  const localized = localizeLinkPath(based, options);
120
120
  if (localized === based) {
@@ -1,4 +1,4 @@
1
- import { withBasePath } from "./base-path.ts";
1
+ import { mountBasePath } from "./base-path.ts";
2
2
  import { localizeRoute, resolveFallbackLocale } from "./i18n.ts";
3
3
  import type { ResolvedConfig } from "./schema.ts";
4
4
  import type {
@@ -106,7 +106,7 @@ const buildFallbackRoutes = (
106
106
  if (present.has(key)) {
107
107
  continue;
108
108
  }
109
- const path = withBasePath(basePath, localizeRoute(key, code, i18n));
109
+ const path = mountBasePath(basePath, localizeRoute(key, code, i18n));
110
110
  // A fallback route is a real prerendered page, so it registers as a
111
111
  // version alternate too — the switcher on a sibling version's page
112
112
  // lands here instead of bouncing to the version root. Its own path is
@@ -183,6 +183,7 @@ export const buildManifest = (options: {
183
183
  }
184
184
 
185
185
  const routes: RouteManifestEntry[] = graph.pages.map((page) => ({
186
+ aiExclude: page.meta.ai.exclude,
186
187
  alternates: alternatesByKey.get(page.translationKey) ?? [],
187
188
  collection: page.collection ?? "docs",
188
189
  contentType: page.contentType,
package/src/core/meta.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { basename, dirname, relative } from "pathe";
2
- import { glob } from "tinyglobby";
2
+ import { glob, isDynamicPattern } from "tinyglobby";
3
3
 
4
4
  import { diagnosticsFromZod } from "./diagnostics.ts";
5
5
  import { createModuleLoader } from "./load-module.ts";
@@ -38,12 +38,57 @@ const resolveMeta = async (mod: MetaModuleExport) =>
38
38
 
39
39
  /** A filesystem content source to scan for folder meta: its on-disk root and
40
40
  * optional route prefix. The prefix is folded into every key so meta lines up
41
- * with the sidebar group path, which carries the same prefix. */
41
+ * with the sidebar group path, which carries the same prefix. `include` and
42
+ * `exclude` are the source's content globs, which scope the scan to the
43
+ * folders the source reads. */
42
44
  export interface FolderMetaSource {
43
45
  root: string;
44
46
  prefix?: string;
47
+ include?: readonly string[];
48
+ exclude?: readonly string[];
45
49
  }
46
50
 
51
+ /**
52
+ * The literal directory a glob starts from (`docs/**\/*.md` → `docs`, `""`
53
+ * when it matches from the root): its leading segments up to the first one
54
+ * with glob syntax, the file-name segment excluded.
55
+ */
56
+ const globBase = (pattern: string): string => {
57
+ const literal: string[] = [];
58
+ for (const segment of pattern.split("/").slice(0, -1)) {
59
+ if (isDynamicPattern(segment)) {
60
+ break;
61
+ }
62
+ if (segment !== "" && segment !== ".") {
63
+ literal.push(segment);
64
+ }
65
+ }
66
+ return literal.join("/");
67
+ };
68
+
69
+ /** Whether `dir` is `base`, or nested beneath or above it (`""` is the root). */
70
+ const onPathOf = (dir: string, base: string): boolean =>
71
+ dir === base ||
72
+ base === "" ||
73
+ dir === "" ||
74
+ dir.startsWith(`${base}/`) ||
75
+ base.startsWith(`${dir}/`);
76
+
77
+ /**
78
+ * Whether a meta file's directory can configure a sidebar group of the
79
+ * source: it lies on the path of some `include` glob's base — the folders
80
+ * that glob reads, or the ancestors whose groups hold them. Negated globs
81
+ * only narrow what a source reads, so they never qualify a folder.
82
+ */
83
+ const withinInclude = (
84
+ dir: string,
85
+ include: readonly string[] | undefined
86
+ ): boolean =>
87
+ include === undefined ||
88
+ include.some(
89
+ (pattern) => !pattern.startsWith("!") && onPathOf(dir, globBase(pattern))
90
+ );
91
+
47
92
  /**
48
93
  * The folder-meta key for a directory. Mirrors the sidebar group path: the
49
94
  * source's route prefix (`docs`) followed by the directory relative to the
@@ -93,7 +138,12 @@ export const discoverFolderMeta = async (
93
138
  const list: FolderMetaSource[] = Array.isArray(sources)
94
139
  ? sources
95
140
  : [{ root: sources }];
96
- const localeDirs = new Set(options.localeDirs);
141
+ // Locale folders match case-insensitively, like content does (`pt-br/` for
142
+ // a configured `pt-BR`), and key under the configured casing, which is what
143
+ // navigation looks meta up by.
144
+ const localeDirs = new Map(
145
+ (options.localeDirs ?? []).map((code) => [code.toLowerCase(), code])
146
+ );
97
147
  const versionDirs = new Set(options.versionDirs);
98
148
 
99
149
  const load = createModuleLoader();
@@ -105,14 +155,25 @@ export const discoverFolderMeta = async (
105
155
  // `content.root` still contributes its folder meta.
106
156
  const perSource = await Promise.all(
107
157
  list.map(async (source) => {
108
- const files = await glob(META_FILES, {
158
+ const found = await glob(META_FILES, {
109
159
  absolute: true,
110
160
  cwd: source.root,
111
161
  // Never descend into dependencies or build output — relevant when the
112
162
  // root is the project root (e.g. a `.`-rooted or all-staged project).
113
- ignore: ["**/node_modules/**", "**/.blume/**", "**/dist/**"],
163
+ // The source's own `exclude` applies too: a `meta.ts` under an
164
+ // excluded folder (`src/lib/meta.ts` beside `exclude: ["src/**"]`)
165
+ // is application code, not folder meta, and importing it would fail.
166
+ ignore: [
167
+ ...(source.exclude ?? []),
168
+ "**/node_modules/**",
169
+ "**/.blume/**",
170
+ "**/dist/**",
171
+ ],
114
172
  onlyFiles: true,
115
173
  });
174
+ const files = found.filter((file) =>
175
+ withinInclude(relative(source.root, dirname(file)), source.include)
176
+ );
116
177
  const loaded = await Promise.all(
117
178
  files.map(
118
179
  async (
@@ -149,7 +210,9 @@ export const discoverFolderMeta = async (
149
210
  const version = head && versionDirs.has(head) ? head : "";
150
211
  const afterVersion = version ? tail : [head ?? "", ...tail];
151
212
  const [localeHead, ...localeTail] = afterVersion;
152
- const locale = localeHead && localeDirs.has(localeHead) ? localeHead : "";
213
+ const locale = localeHead
214
+ ? (localeDirs.get(localeHead.toLowerCase()) ?? "")
215
+ : "";
153
216
  const rest = (locale ? localeTail : afterVersion)
154
217
  .filter(Boolean)
155
218
  .join("/");
@@ -1,6 +1,8 @@
1
1
  import { isAssetIcon } from "../theme/icon-kind.ts";
2
2
  import { hasIcon } from "../theme/icons.ts";
3
3
  import { isInternalPath } from "./base-path.ts";
4
+ import { isPageRef, normalizeRef } from "./navigation.ts";
5
+ import type { SidebarItemConfig } from "./schema.ts";
4
6
  import type { Diagnostic, NavNode, Navigation, PageRecord } from "./types.ts";
5
7
 
6
8
  /**
@@ -137,7 +139,9 @@ export const validateNavTargets = (
137
139
  if (!isInternalPath(path) || path.startsWith("/#") || seen.has(path)) {
138
140
  continue;
139
141
  }
140
- if (!resolvesToPages(routes, path.split("#")[0] ?? path)) {
142
+ // A query or fragment (`/guides?tab=cli`) rides on the route; only the
143
+ // path names a page.
144
+ if (!resolvesToPages(routes, path.split(/[?#]/u)[0] ?? path)) {
141
145
  seen.add(path);
142
146
  diagnostics.push({
143
147
  code: "BLUME_NAV_MISSING_PAGE",
@@ -150,6 +154,57 @@ export const validateNavTargets = (
150
154
  return diagnostics;
151
155
  };
152
156
 
157
+ /**
158
+ * Warn about explicit `navigation.sidebar` items that can't render as written,
159
+ * instead of dropping them without a word: a page ref that matches no page
160
+ * (left out of the sidebar), a `root` that matches no page (its link leads
161
+ * nowhere), and an item with no page, `href`, `root`, or `items` (left out).
162
+ * `resolves` answers whether a normalized ref (`/guides`) names a page — in
163
+ * any locale — or a route served outside the content tree.
164
+ */
165
+ export const validateSidebarItems = (
166
+ items: SidebarItemConfig[],
167
+ resolves: (route: string) => boolean
168
+ ): Diagnostic[] => {
169
+ const diagnostics: Diagnostic[] = [];
170
+ const walk = (list: SidebarItemConfig[]): void => {
171
+ for (const item of list) {
172
+ if (isPageRef(item)) {
173
+ if (!resolves(normalizeRef(item))) {
174
+ diagnostics.push({
175
+ code: "BLUME_NAV_MISSING_PAGE",
176
+ message: `Sidebar entry "${item}" matches no page, so it's left out of the sidebar.`,
177
+ severity: "warning",
178
+ suggestion: "Fix the route, or add a page at it.",
179
+ });
180
+ }
181
+ continue;
182
+ }
183
+ if (item.root && !resolves(normalizeRef(item.root))) {
184
+ diagnostics.push({
185
+ code: "BLUME_NAV_MISSING_PAGE",
186
+ message: `Sidebar entry "${item.label}" has root "${item.root}", but no page matches it, so its link leads nowhere.`,
187
+ severity: "warning",
188
+ suggestion: "Fix the root, or add a page at that route.",
189
+ });
190
+ }
191
+ if (item.items) {
192
+ walk(item.items);
193
+ } else if (!(item.root || item.href)) {
194
+ diagnostics.push({
195
+ code: "BLUME_NAV_EMPTY_ITEM",
196
+ message: `Sidebar entry "${item.label}" has no page, href, root, or items, so it's left out of the sidebar.`,
197
+ severity: "warning",
198
+ suggestion:
199
+ "Give it an href or a root to link somewhere, or items to make it a group.",
200
+ });
201
+ }
202
+ }
203
+ };
204
+ walk(items);
205
+ return diagnostics;
206
+ };
207
+
153
208
  /** Warn about two nav items sharing a label at the same sidebar level. */
154
209
  const duplicateLabelDiagnostics = (navigation: Navigation): Diagnostic[] => {
155
210
  const diagnostics: Diagnostic[] = [];