blume 2.1.0 → 2.1.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 (450) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
  3. package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
  4. package/dist/cli/{chunk-43zcf4gz.js → chunk-0pmb4tr4.js} +541 -368
  5. package/dist/cli/chunk-0pmb4tr4.js.map +35 -0
  6. package/dist/cli/{chunk-9geymqns.js → chunk-0w6hs479.js} +15 -15
  7. package/dist/cli/{chunk-xkz5xbtv.js → chunk-124fvmzq.js} +2802 -1422
  8. package/dist/cli/chunk-124fvmzq.js.map +220 -0
  9. package/dist/cli/chunk-150jk7km.js +52 -0
  10. package/dist/cli/chunk-150jk7km.js.map +10 -0
  11. package/dist/cli/{chunk-y4ykbark.js → chunk-1f882900.js} +2 -2
  12. package/dist/cli/{chunk-5ffywsmb.js → chunk-297ajdcv.js} +8 -6
  13. package/dist/cli/{chunk-5ffywsmb.js.map → chunk-297ajdcv.js.map} +3 -3
  14. package/dist/cli/{chunk-h2a48yhd.js → chunk-32khwcb6.js} +120 -16
  15. package/dist/cli/{chunk-h2a48yhd.js.map → chunk-32khwcb6.js.map} +10 -10
  16. package/dist/cli/{chunk-5cg2rzgf.js → chunk-36bxs9c7.js} +20 -49
  17. package/dist/cli/{chunk-5cg2rzgf.js.map → chunk-36bxs9c7.js.map} +4 -5
  18. package/dist/cli/{chunk-py62fewh.js → chunk-53jqw8z0.js} +3 -3
  19. package/dist/cli/{chunk-5wj2qwn2.js → chunk-58bt3hag.js} +4 -4
  20. package/dist/cli/{chunk-e7vvk5ya.js → chunk-5cmts6dv.js} +3 -3
  21. package/dist/cli/{chunk-y5h4r2y0.js → chunk-60hz265r.js} +15 -5
  22. package/dist/cli/chunk-60hz265r.js.map +10 -0
  23. package/dist/cli/chunk-74wfhv79.js +65 -0
  24. package/dist/cli/chunk-74wfhv79.js.map +10 -0
  25. package/dist/cli/{chunk-g2z9x01v.js → chunk-9qzgg6mj.js} +3 -3
  26. package/dist/cli/{chunk-q3wxxq39.js → chunk-a57yh0h9.js} +5 -5
  27. package/dist/cli/{chunk-713mngdq.js → chunk-ave1wcbr.js} +76 -10
  28. package/dist/cli/chunk-ave1wcbr.js.map +14 -0
  29. package/dist/cli/{chunk-2n4ps1b3.js → chunk-bqxaqn5p.js} +40 -22
  30. package/dist/cli/chunk-bqxaqn5p.js.map +15 -0
  31. package/dist/cli/{chunk-jnwj5kjj.js → chunk-bxwhtvw8.js} +20 -7
  32. package/dist/cli/{chunk-jnwj5kjj.js.map → chunk-bxwhtvw8.js.map} +3 -3
  33. package/dist/cli/chunk-ckrcm08h.js +324 -0
  34. package/dist/cli/chunk-ckrcm08h.js.map +14 -0
  35. package/dist/cli/{chunk-2f3ndkpw.js → chunk-desvm72z.js} +3 -3
  36. package/dist/cli/{chunk-gp84za0h.js → chunk-dhwtqnnd.js} +2 -2
  37. package/dist/cli/{chunk-4h8z9vv5.js → chunk-dpy8qdjf.js} +93 -47
  38. package/dist/cli/chunk-dpy8qdjf.js.map +17 -0
  39. package/dist/cli/{chunk-2f7n4qzt.js → chunk-dqhg54mr.js} +1 -1
  40. package/dist/cli/{chunk-0gz36akr.js → chunk-dv2z0rzf.js} +21 -5
  41. package/dist/cli/chunk-dv2z0rzf.js.map +12 -0
  42. package/dist/cli/{chunk-cm89scdv.js → chunk-es8h0v3j.js} +9 -11
  43. package/dist/cli/{chunk-cm89scdv.js.map → chunk-es8h0v3j.js.map} +3 -3
  44. package/dist/cli/{chunk-zhvd6adm.js → chunk-gfc5fqvf.js} +14 -14
  45. package/dist/cli/{chunk-nd1821sk.js → chunk-gxtg6ed2.js} +33 -19
  46. package/dist/cli/chunk-gxtg6ed2.js.map +10 -0
  47. package/dist/cli/{chunk-p804f3pe.js → chunk-hvcxng5f.js} +6 -6
  48. package/dist/cli/{chunk-ta27feev.js → chunk-j1x92mx9.js} +21 -2
  49. package/dist/cli/chunk-j1x92mx9.js.map +10 -0
  50. package/dist/cli/{chunk-rekqz4qg.js → chunk-k3gr1nm9.js} +19 -16
  51. package/dist/cli/chunk-k3gr1nm9.js.map +10 -0
  52. package/dist/cli/{chunk-1n228xqb.js → chunk-kdpzw38a.js} +2 -2
  53. package/dist/cli/{chunk-cy5bm0j0.js → chunk-ms9z66nz.js} +2 -2
  54. package/dist/cli/{chunk-cy5bm0j0.js.map → chunk-ms9z66nz.js.map} +2 -2
  55. package/dist/cli/{chunk-zf748avv.js → chunk-nbyvgnnm.js} +193 -286
  56. package/dist/cli/chunk-nbyvgnnm.js.map +36 -0
  57. package/dist/cli/{chunk-6bm0xpgd.js → chunk-s0bdnc7v.js} +2 -2
  58. package/dist/cli/{chunk-yxmk4pec.js → chunk-sc93apfs.js} +17 -16
  59. package/dist/cli/{chunk-yxmk4pec.js.map → chunk-sc93apfs.js.map} +3 -3
  60. package/dist/cli/{chunk-cmtcnh9f.js → chunk-tfycddbt.js} +2 -2
  61. package/dist/cli/{chunk-9xr4dgee.js → chunk-twy7psdz.js} +29 -16
  62. package/dist/cli/chunk-twy7psdz.js.map +10 -0
  63. package/dist/cli/{chunk-ntv4qrt7.js → chunk-y4msrwm9.js} +15 -15
  64. package/dist/cli/{chunk-yj17vs39.js → chunk-ydp3065p.js} +5 -5
  65. package/dist/cli/index.js +24 -19
  66. package/dist/cli/index.js.map +3 -3
  67. package/dist/types/ai/ask-context.d.ts +6 -2
  68. package/dist/types/ai/ask.d.ts +24 -5
  69. package/dist/types/ai/component-markdown.d.ts +2 -0
  70. package/dist/types/ai/openapi-components.d.ts +4 -1
  71. package/dist/types/analytics/clics.d.ts +37 -0
  72. package/dist/types/analytics/index.d.ts +2 -0
  73. package/dist/types/analytics/schema.d.ts +18 -0
  74. package/dist/types/astro/integration.d.ts +11 -4
  75. package/dist/types/astro/markdown-negotiation.d.ts +3 -0
  76. package/dist/types/astro/pages.d.ts +10 -0
  77. package/dist/types/cli/init/scaffold.d.ts +1 -1
  78. package/dist/types/components/content/api-field.d.ts +4 -1
  79. package/dist/types/components/content/api-page.d.ts +6 -1
  80. package/dist/types/components/openapi/code-samples.d.ts +29 -0
  81. package/dist/types/components/openapi/helpers.d.ts +22 -1
  82. package/dist/types/components/openapi/security.d.ts +10 -0
  83. package/dist/types/components/openapi/snippets.d.ts +60 -0
  84. package/dist/types/core/changelog-index.d.ts +8 -0
  85. package/dist/types/core/config-input.d.ts +37 -6
  86. package/dist/types/core/data.d.ts +4 -0
  87. package/dist/types/core/i18n-ui.d.ts +2 -0
  88. package/dist/types/core/links.d.ts +8 -0
  89. package/dist/types/core/powered-by.d.ts +12 -0
  90. package/dist/types/core/probe.d.ts +2 -0
  91. package/dist/types/core/project-graph.d.ts +6 -0
  92. package/dist/types/core/redirect-patterns.d.ts +11 -3
  93. package/dist/types/core/schema.d.ts +228 -3
  94. package/dist/types/core/sources/cache.d.ts +3 -0
  95. package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
  96. package/dist/types/core/sources/contentful.d.ts +17 -1
  97. package/dist/types/core/sources/lexical.d.ts +5 -0
  98. package/dist/types/core/sources/lower.d.ts +10 -2
  99. package/dist/types/core/sources/normalize.d.ts +20 -1
  100. package/dist/types/core/sources/notion.d.ts +8 -0
  101. package/dist/types/core/sources/remote.d.ts +37 -10
  102. package/dist/types/core/sources/sanity.d.ts +1 -1
  103. package/dist/types/core/types.d.ts +17 -0
  104. package/dist/types/deploy/adapter-output.d.ts +2 -1
  105. package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
  106. package/dist/types/deploy/adapters/node.d.ts +58 -23
  107. package/dist/types/deploy/adapters/registry.d.ts +10 -0
  108. package/dist/types/deploy/adapters/types.d.ts +3 -2
  109. package/dist/types/deploy/cloudflare-negotiation.d.ts +5 -2
  110. package/dist/types/deploy/node-headers.d.ts +12 -4
  111. package/dist/types/deploy/platforms/cloudflare.d.ts +10 -7
  112. package/dist/types/deploy/platforms/node.d.ts +3 -1
  113. package/dist/types/deploy/platforms/types.d.ts +18 -7
  114. package/dist/types/deploy/platforms/vercel.d.ts +21 -2
  115. package/dist/types/deploy/redirects.d.ts +17 -1
  116. package/dist/types/deploy/sitemap.d.ts +2 -1
  117. package/dist/types/deploy/vercel-negotiation.d.ts +44 -21
  118. package/dist/types/narration/build.d.ts +34 -12
  119. package/dist/types/narration/provider.d.ts +96 -8
  120. package/dist/types/openapi/checks.d.ts +27 -0
  121. package/dist/types/openapi/graphql.d.ts +6 -0
  122. package/dist/types/openapi/model.d.ts +15 -4
  123. package/dist/types/openapi/parse.d.ts +3 -0
  124. package/dist/types/openapi/references.d.ts +16 -0
  125. package/dist/types/openapi/sentence.d.ts +11 -1
  126. package/dist/types/ratelimit/index.d.ts +1 -1
  127. package/dist/types/ratelimit/schema.d.ts +8 -0
  128. package/dist/types/ratelimit/upstash.d.ts +39 -14
  129. package/dist/types/reference/graphql.d.ts +76 -1
  130. package/dist/types/reference/index.d.ts +1 -1
  131. package/dist/types/reference/openapi.d.ts +2 -2
  132. package/dist/types/reference/options.d.ts +37 -1
  133. package/dist/types/reference/schema.d.ts +84 -0
  134. package/dist/types/search/adapters/registry.d.ts +3 -0
  135. package/dist/types/search/adapters/typesense.d.ts +14 -4
  136. package/dist/types/search/build.d.ts +3 -1
  137. package/dist/types/search/orama-index.d.ts +9 -9
  138. package/dist/types/search/sync/algolia.d.ts +5 -2
  139. package/dist/types/search/sync/index.d.ts +3 -1
  140. package/dist/types/search/sync/typesense.d.ts +11 -7
  141. package/dist/types/seo/jsonld.d.ts +11 -6
  142. package/dist/types/sources/contentful.d.ts +16 -0
  143. package/dist/types/sources/github-releases.d.ts +8 -1
  144. package/dist/types/sources/notion.d.ts +8 -0
  145. package/dist/types/sources/payload.d.ts +2 -0
  146. package/dist/types/sources/registry.d.ts +63 -0
  147. package/dist/types/sources/shared.d.ts +3 -0
  148. package/dist/types/sources/strapi.d.ts +2 -0
  149. package/docs/01-quickstart.mdx +4 -2
  150. package/docs/02-deployment.mdx +59 -13
  151. package/docs/03-upgrading.mdx +2 -1
  152. package/docs/04-migrating.mdx +9 -9
  153. package/docs/08-faq.mdx +12 -12
  154. package/docs/advanced/changelog.mdx +30 -2
  155. package/docs/advanced/custom-pages.mdx +1 -1
  156. package/docs/advanced/skills.mdx +1 -1
  157. package/docs/cli/audit.mdx +30 -7
  158. package/docs/cli/doctor.mdx +6 -2
  159. package/docs/cli/evals.mdx +4 -4
  160. package/docs/cli/translate.mdx +1 -0
  161. package/docs/cli/validate.mdx +4 -3
  162. package/docs/configuration/analytics.mdx +19 -1
  163. package/docs/configuration/assistant.mdx +6 -2
  164. package/docs/configuration/customization.mdx +4 -2
  165. package/docs/configuration/export.mdx +5 -3
  166. package/docs/configuration/index.mdx +4 -2
  167. package/docs/configuration/narration.mdx +43 -6
  168. package/docs/configuration/rate-limiting.mdx +23 -2
  169. package/docs/configuration/search.mdx +37 -14
  170. package/docs/content/components.mdx +2 -2
  171. package/docs/content/frontmatter.mdx +5 -3
  172. package/docs/content/i18n.mdx +2 -2
  173. package/docs/content/includes.mdx +1 -1
  174. package/docs/content/navigation.mdx +8 -6
  175. package/docs/content/sources/contentful.mdx +9 -4
  176. package/docs/content/sources/custom.mdx +7 -3
  177. package/docs/content/sources/github-releases.mdx +12 -2
  178. package/docs/content/sources/index.mdx +3 -3
  179. package/docs/content/sources/notion.mdx +17 -2
  180. package/docs/content/sources/obsidian.mdx +3 -1
  181. package/docs/content/sources/payload.mdx +5 -2
  182. package/docs/content/sources/remote-mdx.mdx +6 -0
  183. package/docs/content/sources/sanity.mdx +4 -2
  184. package/docs/content/sources/strapi.mdx +5 -2
  185. package/docs/content/syntax.mdx +2 -2
  186. package/docs/discoverability/agent-discovery.mdx +1 -1
  187. package/docs/discoverability/index.mdx +1 -1
  188. package/docs/discoverability/json-api.mdx +2 -0
  189. package/docs/discoverability/llms-txt.mdx +1 -1
  190. package/docs/discoverability/markdown.mdx +3 -1
  191. package/docs/discoverability/mcp.mdx +6 -0
  192. package/docs/discoverability/sitemap-and-robots.mdx +1 -1
  193. package/docs/discoverability/structured-data.mdx +8 -6
  194. package/docs/references/api-pages.mdx +1 -1
  195. package/docs/references/asyncapi.mdx +5 -1
  196. package/docs/references/graphql.mdx +15 -1
  197. package/docs/references/openapi.mdx +64 -8
  198. package/package.json +9 -9
  199. package/skills/blume/SKILL.md +1 -1
  200. package/skills/blume-migrate/SKILL.md +2 -2
  201. package/skills/blume-migrate/assets/{oxfmt@0.67.0.patch → oxfmt@0.71.0.patch} +7 -7
  202. package/skills/blume-migrate/references/docusaurus.md +4 -4
  203. package/skills/blume-migrate/references/fumadocs.md +17 -13
  204. package/skills/blume-migrate/references/monorepo.md +5 -5
  205. package/skills/blume-migrate/references/nextra.md +8 -5
  206. package/skills/blume-migrate/references/starlight.md +9 -7
  207. package/src/ai/ask-context.ts +33 -3
  208. package/src/ai/ask-limits.ts +13 -0
  209. package/src/ai/ask.ts +24 -6
  210. package/src/ai/changelog-markdown.ts +11 -6
  211. package/src/ai/component-markdown.ts +1 -1
  212. package/src/ai/cors.ts +12 -3
  213. package/src/ai/mcp/query.ts +14 -6
  214. package/src/ai/openapi-components.ts +28 -4
  215. package/src/ai/relative-links.ts +4 -38
  216. package/src/analytics/clics.ts +58 -0
  217. package/src/analytics/head.ts +5 -0
  218. package/src/analytics/index.ts +2 -0
  219. package/src/analytics/schema.ts +2 -0
  220. package/src/astro/generate.ts +91 -56
  221. package/src/astro/integration.ts +72 -22
  222. package/src/astro/markdown-negotiation.ts +3 -0
  223. package/src/astro/module-types.ts +3 -1
  224. package/src/astro/pages.ts +23 -0
  225. package/src/astro/render-deps.ts +10 -5
  226. package/src/astro/runtime-deps.ts +23 -2
  227. package/src/astro/templates.ts +129 -81
  228. package/src/audit/catalog.ts +19 -3
  229. package/src/audit/checks/links.ts +14 -1
  230. package/src/audit/checks/network.ts +110 -6
  231. package/src/audit/checks/redirects.ts +6 -4
  232. package/src/audit/checks/robots.ts +58 -2
  233. package/src/audit/run.ts +3 -0
  234. package/src/audit/types.ts +2 -0
  235. package/src/audit/url.ts +14 -5
  236. package/src/blume-modules.d.ts +5 -1
  237. package/src/cli/args.ts +51 -0
  238. package/src/cli/build-failure.ts +23 -0
  239. package/src/cli/commands/audit.ts +10 -1
  240. package/src/cli/commands/dev.ts +18 -2
  241. package/src/cli/commands/doctor.ts +45 -12
  242. package/src/cli/commands/eval.ts +36 -4
  243. package/src/cli/commands/init.ts +6 -4
  244. package/src/cli/commands/validate.ts +10 -1
  245. package/src/cli/init/scaffold.ts +9 -6
  246. package/src/cli/prepare.ts +6 -3
  247. package/src/cli/required-secrets.ts +3 -2
  248. package/src/components/content/ApiPlayground.astro +6 -2
  249. package/src/components/content/api-field.ts +4 -1
  250. package/src/components/content/api-page.ts +31 -7
  251. package/src/components/content/mermaid-element.ts +15 -1
  252. package/src/components/content/view-switcher.ts +7 -4
  253. package/src/components/islands/hooks.ts +27 -1
  254. package/src/components/layout/NavTree.astro +49 -5
  255. package/src/components/layout/NavTreeScript.astro +18 -0
  256. package/src/components/layout/PageActions.astro +139 -24
  257. package/src/components/layout/PageLayout.astro +13 -3
  258. package/src/components/layout/RootLayout.astro +27 -14
  259. package/src/components/layout/Search.astro +17 -3
  260. package/src/components/layout/TableOfContents.astro +24 -17
  261. package/src/components/layout/analytics-client.ts +8 -8
  262. package/src/components/layout/head-scripts.ts +6 -1
  263. package/src/components/layout/search/algolia.ts +10 -1
  264. package/src/components/layout/search/analytics.ts +42 -14
  265. package/src/components/layout/search/endpoint.ts +48 -5
  266. package/src/components/layout/search/pagefind.ts +114 -5
  267. package/src/components/layout/search/types.ts +12 -0
  268. package/src/components/layout/search/typesense.ts +18 -6
  269. package/src/components/openapi/AsyncApiOperation.astro +14 -7
  270. package/src/components/openapi/Authorization.astro +10 -0
  271. package/src/components/openapi/GraphqlOperation.astro +5 -0
  272. package/src/components/openapi/Operation.astro +24 -1
  273. package/src/components/openapi/ParametersTable.astro +8 -4
  274. package/src/components/openapi/Playground.astro +7 -1
  275. package/src/components/openapi/RequestBody.astro +19 -2
  276. package/src/components/openapi/Responses.astro +1 -0
  277. package/src/components/openapi/SchemaTable.astro +15 -3
  278. package/src/components/openapi/async-snippets.ts +61 -5
  279. package/src/components/openapi/async.ts +123 -29
  280. package/src/components/openapi/graphql-helpers.ts +35 -12
  281. package/src/components/openapi/helpers.ts +36 -2
  282. package/src/components/openapi/message-model.ts +54 -11
  283. package/src/components/openapi/message.ts +14 -4
  284. package/src/components/openapi/operation-model.ts +16 -7
  285. package/src/components/openapi/playground-client.ts +77 -58
  286. package/src/components/openapi/playground-schema.ts +1 -1
  287. package/src/components/openapi/schema-tree.ts +44 -14
  288. package/src/components/openapi/security.ts +10 -0
  289. package/src/components/openapi/snippets.ts +5 -3
  290. package/src/components/openapi/validate-json.ts +4 -3
  291. package/src/components/powered-by-middleware.ts +33 -0
  292. package/src/core/changelog-index.ts +31 -1
  293. package/src/core/component-diagnostics.ts +53 -0
  294. package/src/core/component-overrides.ts +32 -0
  295. package/src/core/config-input.ts +42 -6
  296. package/src/core/data.ts +2 -0
  297. package/src/core/diagnostics.ts +5 -0
  298. package/src/core/i18n-ui.ts +2 -0
  299. package/src/core/includes.ts +1 -1
  300. package/src/core/links.ts +47 -17
  301. package/src/core/powered-by.ts +12 -0
  302. package/src/core/probe.ts +26 -6
  303. package/src/core/project-graph.ts +59 -18
  304. package/src/core/redirect-patterns.ts +36 -7
  305. package/src/core/schema.ts +26 -6
  306. package/src/core/sources/cache.ts +6 -0
  307. package/src/core/sources/contentful-rich-text.ts +29 -6
  308. package/src/core/sources/contentful.ts +135 -25
  309. package/src/core/sources/filesystem.ts +26 -4
  310. package/src/core/sources/github-releases.ts +12 -1
  311. package/src/core/sources/lexical.ts +15 -10
  312. package/src/core/sources/lower.ts +19 -3
  313. package/src/core/sources/mdx-remote.ts +62 -10
  314. package/src/core/sources/normalize.ts +227 -41
  315. package/src/core/sources/notion.ts +34 -10
  316. package/src/core/sources/obsidian.ts +16 -3
  317. package/src/core/sources/payload.ts +38 -15
  318. package/src/core/sources/remote.ts +72 -15
  319. package/src/core/sources/resolve.ts +11 -1
  320. package/src/core/sources/sanity.ts +43 -25
  321. package/src/core/sources/strapi.ts +2 -2
  322. package/src/core/types.ts +18 -0
  323. package/src/core/ui-packs/ar.ts +1 -0
  324. package/src/core/ui-packs/bg.ts +1 -0
  325. package/src/core/ui-packs/bn.ts +1 -0
  326. package/src/core/ui-packs/ca.ts +1 -0
  327. package/src/core/ui-packs/cs.ts +1 -0
  328. package/src/core/ui-packs/da.ts +1 -0
  329. package/src/core/ui-packs/de.ts +1 -0
  330. package/src/core/ui-packs/el.ts +1 -0
  331. package/src/core/ui-packs/es.ts +1 -0
  332. package/src/core/ui-packs/fa.ts +1 -0
  333. package/src/core/ui-packs/fi.ts +1 -0
  334. package/src/core/ui-packs/fr.ts +1 -0
  335. package/src/core/ui-packs/he.ts +1 -0
  336. package/src/core/ui-packs/hi.ts +1 -0
  337. package/src/core/ui-packs/hr.ts +1 -0
  338. package/src/core/ui-packs/hu.ts +1 -0
  339. package/src/core/ui-packs/id.ts +1 -0
  340. package/src/core/ui-packs/it.ts +1 -0
  341. package/src/core/ui-packs/ja.ts +1 -0
  342. package/src/core/ui-packs/ko.ts +1 -0
  343. package/src/core/ui-packs/nl.ts +1 -0
  344. package/src/core/ui-packs/no.ts +1 -0
  345. package/src/core/ui-packs/pl.ts +1 -0
  346. package/src/core/ui-packs/pt-br.ts +1 -0
  347. package/src/core/ui-packs/pt.ts +1 -0
  348. package/src/core/ui-packs/ro.ts +1 -0
  349. package/src/core/ui-packs/ru.ts +1 -0
  350. package/src/core/ui-packs/sk.ts +1 -0
  351. package/src/core/ui-packs/sr.ts +1 -0
  352. package/src/core/ui-packs/sv.ts +1 -0
  353. package/src/core/ui-packs/th.ts +1 -0
  354. package/src/core/ui-packs/tr.ts +1 -0
  355. package/src/core/ui-packs/uk.ts +1 -0
  356. package/src/core/ui-packs/vi.ts +1 -0
  357. package/src/core/ui-packs/zh-tw.ts +1 -0
  358. package/src/core/ui-packs/zh.ts +1 -0
  359. package/src/deploy/adapter-output.ts +7 -2
  360. package/src/deploy/adapters/cloudflare.ts +7 -5
  361. package/src/deploy/adapters/node.ts +47 -9
  362. package/src/deploy/adapters/types.ts +7 -3
  363. package/src/deploy/artifacts.ts +2 -1
  364. package/src/deploy/cloudflare-negotiation.ts +36 -7
  365. package/src/deploy/headers.ts +15 -1
  366. package/src/deploy/node-headers.ts +32 -20
  367. package/src/deploy/platforms/cloudflare.ts +14 -9
  368. package/src/deploy/platforms/netlify.ts +2 -1
  369. package/src/deploy/platforms/node.ts +12 -2
  370. package/src/deploy/platforms/types.ts +21 -7
  371. package/src/deploy/platforms/vercel.ts +115 -17
  372. package/src/deploy/redirects.ts +66 -6
  373. package/src/deploy/rss.ts +3 -1
  374. package/src/deploy/sitemap.ts +39 -5
  375. package/src/deploy/vercel-negotiation.ts +325 -103
  376. package/src/eval/agents.ts +18 -1
  377. package/src/eval/prompts.ts +6 -3
  378. package/src/eval/report.ts +34 -13
  379. package/src/eval/run.ts +5 -0
  380. package/src/markdown/base-links.ts +15 -14
  381. package/src/markdown/package-commands.ts +9 -8
  382. package/src/markdown/relative-links.ts +3 -2
  383. package/src/narration/build.ts +218 -40
  384. package/src/narration/provider.ts +89 -9
  385. package/src/openapi/checks.ts +273 -0
  386. package/src/openapi/graphql-build.ts +21 -0
  387. package/src/openapi/graphql.ts +11 -0
  388. package/src/openapi/model.ts +15 -3
  389. package/src/openapi/parse.ts +127 -2
  390. package/src/openapi/references.ts +43 -3
  391. package/src/openapi/render-mdx.ts +68 -8
  392. package/src/openapi/sentence.ts +29 -2
  393. package/src/openapi/source.ts +39 -14
  394. package/src/ratelimit/index.ts +1 -1
  395. package/src/ratelimit/runtime.ts +37 -19
  396. package/src/ratelimit/upstash.ts +40 -10
  397. package/src/reference/graphql.ts +15 -1
  398. package/src/reference/index.ts +1 -0
  399. package/src/reference/openapi.ts +2 -2
  400. package/src/reference/options.ts +29 -1
  401. package/src/registry/eject.ts +8 -2
  402. package/src/search/adapters/locale-scope.ts +30 -0
  403. package/src/search/adapters/typesense.ts +14 -4
  404. package/src/search/build.ts +21 -3
  405. package/src/search/orama-index.ts +163 -31
  406. package/src/search/source-pages.ts +29 -0
  407. package/src/search/sync/algolia.ts +99 -9
  408. package/src/search/sync/index.ts +52 -13
  409. package/src/search/sync/typesense.ts +72 -27
  410. package/src/seo/jsonld.ts +38 -20
  411. package/src/sources/contentful.ts +12 -0
  412. package/src/sources/github-releases.ts +7 -1
  413. package/src/sources/notion.ts +7 -0
  414. package/src/sources/shared.ts +3 -0
  415. package/src/theme/color.ts +9 -10
  416. package/src/theme/entry.ts +43 -6
  417. package/src/translate/validate.ts +23 -1
  418. package/dist/cli/chunk-0gz36akr.js.map +0 -12
  419. package/dist/cli/chunk-2n4ps1b3.js.map +0 -15
  420. package/dist/cli/chunk-43zcf4gz.js.map +0 -36
  421. package/dist/cli/chunk-4ejxbzee.js +0 -39
  422. package/dist/cli/chunk-4ejxbzee.js.map +0 -10
  423. package/dist/cli/chunk-4h8z9vv5.js.map +0 -16
  424. package/dist/cli/chunk-713mngdq.js.map +0 -14
  425. package/dist/cli/chunk-9xr4dgee.js.map +0 -10
  426. package/dist/cli/chunk-amrb6hgh.js +0 -145
  427. package/dist/cli/chunk-amrb6hgh.js.map +0 -11
  428. package/dist/cli/chunk-nd1821sk.js.map +0 -10
  429. package/dist/cli/chunk-rekqz4qg.js.map +0 -10
  430. package/dist/cli/chunk-ta27feev.js.map +0 -10
  431. package/dist/cli/chunk-xkz5xbtv.js.map +0 -213
  432. package/dist/cli/chunk-y5h4r2y0.js.map +0 -10
  433. package/dist/cli/chunk-zf748avv.js.map +0 -37
  434. /package/dist/cli/{chunk-9geymqns.js.map → chunk-0w6hs479.js.map} +0 -0
  435. /package/dist/cli/{chunk-y4ykbark.js.map → chunk-1f882900.js.map} +0 -0
  436. /package/dist/cli/{chunk-py62fewh.js.map → chunk-53jqw8z0.js.map} +0 -0
  437. /package/dist/cli/{chunk-5wj2qwn2.js.map → chunk-58bt3hag.js.map} +0 -0
  438. /package/dist/cli/{chunk-e7vvk5ya.js.map → chunk-5cmts6dv.js.map} +0 -0
  439. /package/dist/cli/{chunk-g2z9x01v.js.map → chunk-9qzgg6mj.js.map} +0 -0
  440. /package/dist/cli/{chunk-q3wxxq39.js.map → chunk-a57yh0h9.js.map} +0 -0
  441. /package/dist/cli/{chunk-2f3ndkpw.js.map → chunk-desvm72z.js.map} +0 -0
  442. /package/dist/cli/{chunk-gp84za0h.js.map → chunk-dhwtqnnd.js.map} +0 -0
  443. /package/dist/cli/{chunk-2f7n4qzt.js.map → chunk-dqhg54mr.js.map} +0 -0
  444. /package/dist/cli/{chunk-zhvd6adm.js.map → chunk-gfc5fqvf.js.map} +0 -0
  445. /package/dist/cli/{chunk-p804f3pe.js.map → chunk-hvcxng5f.js.map} +0 -0
  446. /package/dist/cli/{chunk-1n228xqb.js.map → chunk-kdpzw38a.js.map} +0 -0
  447. /package/dist/cli/{chunk-6bm0xpgd.js.map → chunk-s0bdnc7v.js.map} +0 -0
  448. /package/dist/cli/{chunk-cmtcnh9f.js.map → chunk-tfycddbt.js.map} +0 -0
  449. /package/dist/cli/{chunk-ntv4qrt7.js.map → chunk-y4msrwm9.js.map} +0 -0
  450. /package/dist/cli/{chunk-yj17vs39.js.map → chunk-ydp3065p.js.map} +0 -0
@@ -34,7 +34,11 @@ import {
34
34
  navVariants,
35
35
  } from "../components/layout/nav-utils.ts";
36
36
  import { normalizeBasePath, withBasePath } from "../core/base-path.ts";
37
- import { validateUsedComponents } from "../core/component-diagnostics.ts";
37
+ import { withChangelogIndexText } from "../core/changelog-index.ts";
38
+ import {
39
+ missingExampleDiagnostics,
40
+ validateUsedComponents,
41
+ } from "../core/component-diagnostics.ts";
38
42
  import {
39
43
  analyzeComponentOverrides,
40
44
  emptyComponentOverrides,
@@ -93,13 +97,13 @@ import {
93
97
  builtinProxyReferences,
94
98
  hasScalarReferences,
95
99
  needsPlaygroundProxy,
96
- referenceRoutes,
97
100
  } from "../openapi/references.ts";
98
101
  import { buildReferenceFiles } from "../openapi/scalar.ts";
99
102
  import { isOpenApiSource } from "../openapi/source.ts";
100
103
  import { registry } from "../registry/registry.ts";
101
104
  import { buildSearchDocuments } from "../search/documents.ts";
102
105
  import { resolveSearchPopular } from "../search/popular.ts";
106
+ import { sourcePages } from "../search/source-pages.ts";
103
107
  import {
104
108
  examplesEntryTemplate,
105
109
  tailwindEntryTemplate,
@@ -125,6 +129,7 @@ import {
125
129
  customOgRoutes,
126
130
  discoverPages,
127
131
  hasGeneratedChangelog,
132
+ navTargetRoutes,
128
133
  routeIsTaken,
129
134
  } from "./pages.ts";
130
135
  import { candidateHolding } from "./render-deps.ts";
@@ -180,28 +185,35 @@ export type { PrerenderDepsPlugin } from "./render-deps.ts";
180
185
  const BLUME_SRC = join(packageRoot(), "src");
181
186
 
182
187
  /**
183
- * Absolute path to `babel-plugin-react-compiler`, resolved from Blume's own
184
- * package root (Blume ships it). Returns null when React or the compiler is off.
188
+ * Whether the generated `react()` call turns the React Compiler on: React and
189
+ * `react.compiler` are both on, and `oxc-transform-react` (Blume ships it)
190
+ * resolves. False when React or the compiler is off.
185
191
  *
186
- * The path must be absolute: @vitejs/plugin-react resolves babel plugins from
187
- * the *project* root, not `.blume/`, so a bare specifier fails in a user project
188
- * that never installed the plugin directly. Resolving from `packageRoot()` binds
189
- * to Blume's shipped copy regardless of the user's package manager or hoisting.
192
+ * The compiler is loaded by `@vitejs/plugin-react` with a bare
193
+ * `import("oxc-transform-react")` from its own directory, which fails the
194
+ * build when it throws, so the check walks the same chain — Blume →
195
+ * `@astrojs/react` → `@vitejs/plugin-react` — rather than resolving from
196
+ * Blume's root, which a strict package manager may not link the plugin to.
190
197
  */
191
198
  export const resolveReactCompiler = (
192
199
  config: ResolvedConfig,
193
200
  needsReact: boolean,
194
201
  pkgDir: string = packageRoot()
195
- ): string | null => {
202
+ ): boolean => {
196
203
  if (!(needsReact && config.react.compiler)) {
197
- return null;
204
+ return false;
198
205
  }
199
206
  try {
200
- return createRequire(pathToFileURL(join(pkgDir, "_.js")).href).resolve(
201
- "babel-plugin-react-compiler"
207
+ const astroReact = createRequire(
208
+ pathToFileURL(join(pkgDir, "_.js")).href
209
+ ).resolve("@astrojs/react");
210
+ const pluginReact = createRequire(astroReact).resolve(
211
+ "@vitejs/plugin-react"
202
212
  );
213
+ createRequire(pluginReact).resolve("oxc-transform-react");
214
+ return true;
203
215
  } catch {
204
- return null;
216
+ return false;
205
217
  }
206
218
  };
207
219
 
@@ -213,11 +225,11 @@ export const resolveReactCompiler = (
213
225
  export const reactCompilerWarnings = (
214
226
  config: ResolvedConfig,
215
227
  needsReact: boolean,
216
- compilerPath: string | null
228
+ compiler: boolean
217
229
  ): string[] =>
218
- needsReact && config.react.compiler && !compilerPath
230
+ needsReact && config.react.compiler && !compiler
219
231
  ? [
220
- "React Compiler is enabled but `babel-plugin-react-compiler` could not be resolved; falling back to an uncompiled build. Reinstall Blume, or set `react: { compiler: false }` to silence this.",
232
+ "React Compiler is enabled but `oxc-transform-react` could not be resolved; falling back to an uncompiled build. Reinstall Blume, or set `react: { compiler: false }` to silence this.",
221
233
  ]
222
234
  : [];
223
235
 
@@ -1142,23 +1154,32 @@ export const buildRuntimeData = (project: BlumeProject): string => {
1142
1154
 
1143
1155
  // Resolved UI dictionaries: one per locale under i18n, English baseline
1144
1156
  // otherwise. Threaded into chrome so the catch-all can pick the active locale.
1157
+ // The `changelog` config's title and description replace the dictionaries'.
1145
1158
  const uiByLocale = i18n
1146
1159
  ? Object.fromEntries(
1147
1160
  i18n.locales.map(({ code }) => [
1148
1161
  code,
1149
- resolveUIStrings(code, {
1150
- defaultLocale: i18n.defaultLocale,
1151
- overrides: i18n.ui,
1152
- }),
1162
+ withChangelogIndexText(
1163
+ config,
1164
+ resolveUIStrings(code, {
1165
+ defaultLocale: i18n.defaultLocale,
1166
+ overrides: i18n.ui,
1167
+ }),
1168
+ code
1169
+ ),
1153
1170
  ])
1154
1171
  )
1155
1172
  : {};
1156
- const defaultUi = i18n
1157
- ? resolveUIStrings(i18n.defaultLocale, {
1158
- defaultLocale: i18n.defaultLocale,
1159
- overrides: i18n.ui,
1160
- })
1161
- : EN_UI;
1173
+ const defaultUi = withChangelogIndexText(
1174
+ config,
1175
+ i18n
1176
+ ? resolveUIStrings(i18n.defaultLocale, {
1177
+ defaultLocale: i18n.defaultLocale,
1178
+ overrides: i18n.ui,
1179
+ })
1180
+ : EN_UI,
1181
+ i18n?.defaultLocale
1182
+ );
1162
1183
 
1163
1184
  const navigationByLocale = i18n
1164
1185
  ? Object.fromEntries(
@@ -1255,6 +1276,7 @@ export const buildRuntimeData = (project: BlumeProject): string => {
1255
1276
  openInChat: config.ai.openInChat,
1256
1277
  repoUrl,
1257
1278
  search: {
1279
+ analytics: config.search.analytics,
1258
1280
  enabled: config.search.provider.mode !== "none",
1259
1281
  popular: resolveSearchPopular(config.search.popular, config.basePath),
1260
1282
  provider: config.search.provider.kind,
@@ -1796,21 +1818,26 @@ export const diagnosticWarning = (diagnostic: Diagnostic): string =>
1796
1818
 
1797
1819
  /**
1798
1820
  * Missing-dependency preflight: the search provider's SDK, content source
1799
- * SDKs, the assistant backend's provider SDK, the deployment adapter's package,
1800
- * and — since React ships with Blume while Vue/Svelte don't — any island
1801
- * framework's Astro integration. A build fails here, before anything is
1802
- * written, with the install command for the project's package manager —
1803
- * otherwise Vite dies later on an opaque unresolved import from the hidden
1804
- * runtime. Dev warns and keeps serving: only the pages and routes that import
1805
- * the package break, and installing it is picked up on the next restart.
1821
+ * SDKs, the assistant backend's and narration provider's SDKs, the deployment
1822
+ * adapter's package, and — since React ships with Blume while Vue/Svelte
1823
+ * don't — any island framework's Astro integration. A build fails here,
1824
+ * before anything is written, with the install command for the project's
1825
+ * package manager — otherwise Vite dies later on an opaque unresolved import
1826
+ * from the hidden runtime. Dev warns and keeps serving: only the pages and
1827
+ * routes that import the package break, and installing it is picked up on
1828
+ * the next restart. Dev leaves narration's SDK out, since only a build
1829
+ * generates the clips.
1806
1830
  */
1807
1831
  const dependencyPreflight = async (
1808
1832
  project: BlumeProject,
1809
1833
  frameworks: Set<string>
1810
1834
  ): Promise<string[]> => {
1811
1835
  const build = project.mode === "build";
1836
+ const { config } = project;
1812
1837
  const diagnostic = await missingDependencyDiagnostic(
1813
- project.config,
1838
+ build
1839
+ ? config
1840
+ : { ...config, narration: { ...config.narration, provider: null } },
1814
1841
  project.context.root,
1815
1842
  build ? "error" : "warning",
1816
1843
  frameworks
@@ -2064,11 +2091,12 @@ export const generateRuntime = async (
2064
2091
  const needsVue = frameworks.has("vue");
2065
2092
  const needsSvelte = frameworks.has("svelte");
2066
2093
 
2067
- // Absolute path to the React Compiler babel plugin (null when off). Resolved
2068
- // here, Node-side, so the generated config points babel straight at Blume's
2069
- // shipped copy — see resolveReactCompiler. Any unresolved-but-requested
2070
- // warning is folded into `warnings` below (declared later).
2071
- const reactCompilerPath = resolveReactCompiler(config, needsReact);
2094
+ // Whether react() turns the React Compiler on (false when off). Checked here,
2095
+ // Node-side, so an unresolvable compiler degrades to an uncompiled build
2096
+ // instead of failing it — see resolveReactCompiler. Any
2097
+ // unresolved-but-requested warning is folded into `warnings` below (declared
2098
+ // later).
2099
+ const reactCompiler = resolveReactCompiler(config, needsReact);
2072
2100
 
2073
2101
  // Custom pages that should get a generated OG card (the home most of all).
2074
2102
  // Computed before the MCP `.well-known` routes are appended below — those are
@@ -2146,7 +2174,7 @@ export const generateRuntime = async (
2146
2174
  needsSvelte,
2147
2175
  needsVue,
2148
2176
  pages,
2149
- reactCompilerPath,
2177
+ reactCompiler,
2150
2178
  searchClientPath,
2151
2179
  themePath,
2152
2180
  })
@@ -2209,7 +2237,7 @@ export const generateRuntime = async (
2209
2237
  languageIcons,
2210
2238
  sources: [
2211
2239
  `${BLUME_SRC}/**/*.{astro,ts,tsx}`,
2212
- `${context.root}/**/*.{astro,mdx,ts,tsx}`,
2240
+ `${context.root}/**/*.{astro,jsx,mdx,ts,tsx}`,
2213
2241
  ],
2214
2242
  twoslashCss: twoslashCss(),
2215
2243
  userTheme,
@@ -2247,7 +2275,10 @@ export const generateRuntime = async (
2247
2275
  writeMcpFiles(mcp, write, agentData),
2248
2276
  writeApiFiles(project, api, write, agentData, mcp),
2249
2277
  playgroundProxy.enabled
2250
- ? write(playgroundProxy.entrypoint, playgroundProxyTemplate(proxyOrigins))
2278
+ ? write(
2279
+ playgroundProxy.entrypoint,
2280
+ playgroundProxyTemplate(proxyOrigins, config.rateLimit)
2281
+ )
2251
2282
  : Promise.resolve(false),
2252
2283
  ]);
2253
2284
 
@@ -2317,7 +2348,11 @@ export const generateRuntime = async (
2317
2348
  if (searchAdapter.kind === "mixedbread") {
2318
2349
  await write(
2319
2350
  join(srcDir, "pages", "api", "search.ts"),
2320
- mixedbreadSearchEndpointTemplate(searchAdapter.options)
2351
+ mixedbreadSearchEndpointTemplate(
2352
+ searchAdapter.options,
2353
+ sourcePages(project),
2354
+ config.rateLimit
2355
+ )
2321
2356
  );
2322
2357
  }
2323
2358
 
@@ -2372,7 +2407,7 @@ export const generateRuntime = async (
2372
2407
  ...(depsLinkWarning ? [depsLinkWarning] : []),
2373
2408
  ...proxyAllowlistWarnings(config, openApiData),
2374
2409
  ...apiPageProxyWarnings(project),
2375
- ...reactCompilerWarnings(config, needsReact, reactCompilerPath),
2410
+ ...reactCompilerWarnings(config, needsReact, reactCompiler),
2376
2411
  ...mcp.warnings,
2377
2412
  ...islandDiscovery.warnings,
2378
2413
  ...exampleDiscovery.warnings,
@@ -2380,24 +2415,18 @@ export const generateRuntime = async (
2380
2415
  ...overrideWarnings,
2381
2416
  ];
2382
2417
 
2383
- // Missing-navigation-target check, now that every servable route is known:
2384
- // content routes, custom `.astro` pages, the generated changelog, and any
2385
- // OpenAPI reference routes (so a tab an author points at one still validates).
2386
- const navTargetRoutes = new Set<string>([
2387
- ...project.graph.routes.keys(),
2388
- ...pages.map((page) => page.pattern),
2389
- ...referenceRoutes(config),
2390
- ]);
2391
- if (changelogIndex) {
2392
- navTargetRoutes.add("/changelog");
2393
- }
2418
+ // Missing-navigation-target check, now that every servable route is known
2419
+ // (see `navTargetRoutes`).
2394
2420
  // Curated `search.popular` icons live outside the navigation model, so they
2395
2421
  // miss `validateNavIcons` in the graph build — they're checked here too,
2396
2422
  // where the search config is known. A typo otherwise just renders the
2397
2423
  // default glyph.
2398
2424
  warnings.push(
2399
2425
  ...[
2400
- ...validateNavTargets(project.graph.navigation, navTargetRoutes),
2426
+ ...validateNavTargets(
2427
+ project.graph.navigation,
2428
+ navTargetRoutes(project, pages)
2429
+ ),
2401
2430
  ...validateSearchPopularIcons(config.search.popular),
2402
2431
  ].map(diagnosticWarning)
2403
2432
  );
@@ -2414,6 +2443,12 @@ export const generateRuntime = async (
2414
2443
  knownComponentTags,
2415
2444
  new Set(registry.map((item) => item.name))
2416
2445
  ).map(diagnosticWarning),
2446
+ ...missingExampleDiagnostics(
2447
+ project.graph.pages,
2448
+ exampleDiscovery,
2449
+ context.root,
2450
+ knownComponentTags
2451
+ ).map(diagnosticWarning),
2417
2452
  ...dependencyWarnings
2418
2453
  );
2419
2454
  if (hasScalarReferences(config)) {
@@ -7,6 +7,7 @@ import { join, relative, resolve } from "pathe";
7
7
  import { loadEnvFiles } from "../cli/env.ts";
8
8
  import type { CustomPageRoute } from "../core/custom-pages.ts";
9
9
  import { enrichDiagnostic } from "../core/diagnostics.ts";
10
+ import { POWERED_BY_HEADERS } from "../core/powered-by.ts";
10
11
  import { scanProject } from "../core/project-graph.ts";
11
12
  import type { BlumeProject } from "../core/project-graph.ts";
12
13
  import {
@@ -146,23 +147,33 @@ export const publishBuildProject = (project: BlumeProject | null): void => {
146
147
  * the Astro root recorded on `astro:config:done`. Scan diagnostics surface as
147
148
  * warnings — there is no `--strict` to honor here, and the build itself has
148
149
  * already succeeded. `null` when nothing asked for a scan.
150
+ *
151
+ * The app's runtime settings were baked in at eject, `poweredBy` among them
152
+ * (the integration option that registers the runtime middleware), so the
153
+ * artifacts follow that option rather than the config file: one switch puts
154
+ * `X-Powered-By` on the server-rendered responses and in `_headers` alike.
149
155
  */
150
156
  const scanForArtifacts = async (
151
157
  astroRoot: URL | null,
152
- artifactsRoot: string | undefined,
158
+ options: Pick<BlumeIntegrationOptions, "buildArtifactsRoot" | "poweredBy">,
153
159
  logger: ArtifactLogger
154
160
  ): Promise<BlumeProject | null> => {
155
- if (!(astroRoot && artifactsRoot)) {
161
+ if (!(astroRoot && options.buildArtifactsRoot)) {
156
162
  return null;
157
163
  }
158
- const root = resolve(fileURLToPath(astroRoot), artifactsRoot);
164
+ const root = resolve(fileURLToPath(astroRoot), options.buildArtifactsRoot);
159
165
  // Remote sources read their tokens from the environment during the scan.
160
166
  loadEnvFiles(root);
161
167
  const project = await scanProject(root, { mode: "build" });
162
168
  for (const diagnostic of project.diagnostics) {
163
169
  logger.warn(`[${diagnostic.code}] ${diagnostic.message}`);
164
170
  }
165
- return project;
171
+ return options.poweredBy === undefined
172
+ ? project
173
+ : {
174
+ ...project,
175
+ config: { ...project.config, poweredBy: options.poweredBy },
176
+ };
166
177
  };
167
178
 
168
179
  /**
@@ -317,6 +328,12 @@ export type BlumePageRoute = CustomPageRoute;
317
328
 
318
329
  export interface BlumeIntegrationOptions {
319
330
  pages: BlumePageRoute[];
331
+ /**
332
+ * Whether responses name Blume in `X-Powered-By` (see
333
+ * `core/powered-by.ts`): the dev server's, and the server-rendered ones of
334
+ * a build, through the runtime middleware. Defaults to `true`.
335
+ */
336
+ poweredBy?: boolean;
320
337
  /**
321
338
  * Page routes that have a raw-Markdown variant (the content manifest). The
322
339
  * hidden runtime leaves this out: the CLI publishes the live set through
@@ -342,10 +359,11 @@ export interface BlumeIntegrationOptions {
342
359
  */
343
360
  buildArtifactsRoot?: string;
344
361
  /**
345
- * The pattern redirects (`/beta/:slug*`), compiled against base-less
346
- * request paths (see `core/redirect-patterns.ts`). Astro's own `redirects`
347
- * carry only the exact ones, since it can't prerender a pattern's pages, so
348
- * the dev server answers these itself.
362
+ * Every configured redirect, compiled against base-less request paths
363
+ * (see `compileEveryRedirect`), for the dev server to answer itself.
364
+ * Astro's own `redirects` carry only the exact ones, since it can't
365
+ * prerender a pattern's pages, and its dev handler answers one whose
366
+ * destination `[...slug]` serves with a `301` whatever its status.
349
367
  */
350
368
  redirects?: CompiledRedirect[];
351
369
  }
@@ -398,10 +416,12 @@ const negotiateMarkdown =
398
416
  if (homeLinkHeader && isHomeUrl(req.url)) {
399
417
  res.setHeader("Link", homeLinkHeader);
400
418
  }
401
- if (prefersMarkdown(req.headers.accept)) {
402
- const variant = markdownVariantUrl(req.url, contentRoutes);
403
- if (variant) {
404
- res.setHeader("Vary", "Accept");
419
+ const variant = markdownVariantUrl(req.url, contentRoutes);
420
+ if (variant) {
421
+ // Both answers at a negotiated URL depend on `Accept`, the HTML one
422
+ // too, so a cache never hands one client's variant to the other.
423
+ res.setHeader("Vary", "Accept");
424
+ if (prefersMarkdown(req.headers.accept)) {
405
425
  req.url = variant;
406
426
  }
407
427
  }
@@ -410,11 +430,11 @@ const negotiateMarkdown =
410
430
  };
411
431
 
412
432
  /**
413
- * Answer a pattern redirect in dev with its configured status, the way the
414
- * server wrappers do in a build. Request URLs arrive base-less (see
415
- * {@link negotiateMarkdown}), and the patterns were based to match.
433
+ * Answer a configured redirect in dev with its status, the way the server
434
+ * wrappers do in a build. Request URLs arrive base-less (see
435
+ * {@link negotiateMarkdown}), and the redirects were based to match.
416
436
  */
417
- const answerPatternRedirects =
437
+ const answerRedirects =
418
438
  (redirects: readonly CompiledRedirect[]) =>
419
439
  (req: IncomingMessage, res: ServerResponse, next: () => void): void => {
420
440
  const answer = matchCompiledRedirect(redirects, requestPath(req.url ?? ""));
@@ -426,6 +446,24 @@ const answerPatternRedirects =
426
446
  res.end();
427
447
  };
428
448
 
449
+ /**
450
+ * Name Blume in `X-Powered-By` on every dev response, as the deployed site
451
+ * does. It goes on the Node response before anything answers, so the
452
+ * redirects, the `public/` files Vite serves, and the rendered pages all
453
+ * carry it, and a page or project middleware that sets its own value
454
+ * replaces it.
455
+ */
456
+ const identifyBlume = (
457
+ _req: IncomingMessage,
458
+ res: ServerResponse,
459
+ next: () => void
460
+ ): void => {
461
+ for (const [name, value] of Object.entries(POWERED_BY_HEADERS)) {
462
+ res.setHeader(name, value);
463
+ }
464
+ next();
465
+ };
466
+
429
467
  /** The `.d.ts` the integration injects for the `blume:*` virtual modules. */
430
468
  const MODULE_TYPES_FILE = "modules.d.ts";
431
469
 
@@ -459,11 +497,7 @@ export const blumeIntegration = (
459
497
  "astro:build:done": async ({ dir, logger }) => {
460
498
  const project =
461
499
  registry().buildProject ??
462
- (await scanForArtifacts(
463
- astroRoot,
464
- options.buildArtifactsRoot,
465
- logger
466
- ));
500
+ (await scanForArtifacts(astroRoot, options, logger));
467
501
  if (!project) {
468
502
  return;
469
503
  }
@@ -502,6 +536,15 @@ export const blumeIntegration = (
502
536
  entrypoint: "blume/components/icon-sprite-middleware.ts",
503
537
  order: "post",
504
538
  });
539
+ // Names Blume on the responses Astro renders (see
540
+ // components/powered-by-middleware.ts). Innermost too, so a header
541
+ // the project's own middleware sets wins.
542
+ if (options.poweredBy !== false) {
543
+ addMiddleware({
544
+ entrypoint: "blume/components/powered-by-middleware.ts",
545
+ order: "post",
546
+ });
547
+ }
505
548
  for (const page of options.pages) {
506
549
  injectRoute({
507
550
  entrypoint: page.entrypoint,
@@ -533,7 +576,14 @@ export const blumeIntegration = (
533
576
  });
534
577
  if (options.redirects) {
535
578
  server.middlewares.stack.unshift({
536
- handle: answerPatternRedirects(options.redirects),
579
+ handle: answerRedirects(options.redirects),
580
+ route: "",
581
+ });
582
+ }
583
+ // Ahead of the redirects, so their answers carry it too.
584
+ if (options.poweredBy !== false) {
585
+ server.middlewares.stack.unshift({
586
+ handle: identifyBlume,
537
587
  route: "",
538
588
  });
539
589
  }
@@ -8,6 +8,9 @@
8
8
  * helpers (`deploy/cloudflare-negotiation.ts` — its deploy bundle is uploaded
9
9
  * unbundled, so it cannot import this module); when editing here, mirror the
10
10
  * change there. Parity is enforced by `test/cloudflare-negotiation.test.ts`.
11
+ * Vercel's routing conditions (`deploy/vercel-negotiation.ts`) spell the same
12
+ * rule as regexes, checked against {@link prefersMarkdown} by
13
+ * `test/vercel-negotiation.test.ts`.
11
14
  */
12
15
 
13
16
  interface AcceptEntry {
@@ -82,7 +82,9 @@ declare module "blume:consent-client" {
82
82
  }
83
83
 
84
84
  declare module "blume:search-client" {
85
- export const createSearch: () =>
85
+ export const createSearch: (
86
+ options?: import("blume/components/layout/search/types.ts").SearchClientOptions
87
+ ) =>
86
88
  | import("blume/components/layout/search/types.ts").SearchFn
87
89
  | Promise<import("blume/components/layout/search/types.ts").SearchFn>;
88
90
  }
@@ -4,6 +4,7 @@ import {
4
4
  } from "../core/changelog-index.ts";
5
5
  import { staticSegments } from "../core/custom-pages.ts";
6
6
  import type { BlumeProject } from "../core/project-graph.ts";
7
+ import { referenceRoutes } from "../openapi/references.ts";
7
8
  import type { BlumePageRoute } from "./integration.ts";
8
9
 
9
10
  export {
@@ -48,6 +49,28 @@ export const hasGeneratedChangelog = (
48
49
  hasChangelogIndex(project.graph.pages, project.config) &&
49
50
  !routeIsTaken(userPages, project.graph.pages, CHANGELOG_INDEX_ROUTE);
50
51
 
52
+ /**
53
+ * Every route a navigation entry (a tab, selector item, featured link, header
54
+ * action, or CTA) may point at: content routes, custom `.astro` pages, the
55
+ * generated changelog, and reference routes (so a tab an author points at one
56
+ * still validates). `generateRuntime` and `blume doctor` both check
57
+ * `validateNavTargets` against it, so they flag the same entries.
58
+ */
59
+ export const navTargetRoutes = (
60
+ project: BlumeProject,
61
+ userPages: { pattern: string }[]
62
+ ): Set<string> => {
63
+ const routes = new Set<string>([
64
+ ...project.graph.routes.keys(),
65
+ ...userPages.map((page) => page.pattern),
66
+ ...referenceRoutes(project.config),
67
+ ]);
68
+ if (hasGeneratedChangelog(project, userPages)) {
69
+ routes.add(CHANGELOG_INDEX_ROUTE);
70
+ }
71
+ return routes;
72
+ };
73
+
51
74
  const humanizeSegment = (segment: string): string =>
52
75
  segment
53
76
  .split(/[-_]/u)
@@ -369,11 +369,16 @@ export const prerenderDepsPlugin = (
369
369
  if (!dir || !serverSide) {
370
370
  return;
371
371
  }
372
- await linkRenderDeps(
373
- dir,
374
- imported.get(environment ?? "") ?? new Map<string, string>(),
375
- pkgDir
376
- );
372
+ const packages = imported.get(environment ?? "");
373
+ // A bundle that leaves no package import external loads nothing from
374
+ // `node_modules` at runtime, so it gets none. The Cloudflare adapter
375
+ // bundles the Worker whole, and a copy of its output that follows the
376
+ // links (a CI artifact) would otherwise upload every one of Blume's
377
+ // dependencies as a Worker module.
378
+ if (environment !== undefined && !packages?.size) {
379
+ return;
380
+ }
381
+ await linkRenderDeps(dir, packages ?? new Map<string, string>(), pkgDir);
377
382
  },
378
383
  };
379
384
  };
@@ -103,6 +103,25 @@ export const assistantProviderDependencies = (
103
103
  )
104
104
  : [];
105
105
 
106
+ /**
107
+ * The narration provider's SDK, when missing: `openai()` speaks through
108
+ * `@ai-sdk/openai`, which the build loads to generate the clips, while
109
+ * `gateway()` needs nothing beyond the core `ai` package Blume ships.
110
+ */
111
+ export const narrationProviderDependencies = (
112
+ narration: ResolvedConfig["narration"],
113
+ root: string,
114
+ pkgDir: string = packageRoot()
115
+ ): MissingDependency[] =>
116
+ narration.enabled && narration.provider
117
+ ? unresolved(
118
+ `Narration provider "${narration.provider.kind}"`,
119
+ narration.provider.runtimeDeps,
120
+ root,
121
+ pkgDir
122
+ )
123
+ : [];
124
+
106
125
  /**
107
126
  * The deployment adapter's package, when missing. Node and Vercel ship with
108
127
  * Blume, so theirs always resolve; Netlify and Cloudflare are optional peers.
@@ -152,8 +171,9 @@ export const islandFrameworkDependencies = (
152
171
  /**
153
172
  * Every package the resolved config's adapters (and the given island
154
173
  * frameworks) import that isn't installed: the search SDK, content source
155
- * SDKs, the assistant provider SDK, the deployment adapter, and island
156
- * integrations. The adapters' `runtimeDeps` are the one place that knows.
174
+ * SDKs, the assistant and narration provider SDKs, the deployment adapter,
175
+ * and island integrations. The adapters' `runtimeDeps` are the one place that
176
+ * knows.
157
177
  */
158
178
  export const missingRuntimeDependencies = (
159
179
  config: ResolvedConfig,
@@ -164,6 +184,7 @@ export const missingRuntimeDependencies = (
164
184
  ...searchProviderDependencies(config.search.provider, root, pkgDir),
165
185
  ...sourceAdapterDependencies(config.content.sources, root, pkgDir),
166
186
  ...assistantProviderDependencies(config.ai.assistant, root, pkgDir),
187
+ ...narrationProviderDependencies(config.narration, root, pkgDir),
167
188
  ...deploymentAdapterDependencies(config.deployment, root, pkgDir),
168
189
  ...islandFrameworkDependencies(frameworks, root),
169
190
  ];