blume 2.0.3 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (607) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +142 -0
  3. package/README.md +1 -1
  4. package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
  5. package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
  6. package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
  7. package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
  8. package/dist/cli/chunk-150jk7km.js +52 -0
  9. package/dist/cli/chunk-150jk7km.js.map +10 -0
  10. package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
  11. package/dist/cli/chunk-313vnn40.js.map +10 -0
  12. package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
  13. package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
  14. package/dist/cli/chunk-3x6x3pph.js.map +10 -0
  15. package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
  16. package/dist/cli/chunk-42t4jxdx.js.map +12 -0
  17. package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
  18. package/dist/cli/chunk-54ztw1nj.js.map +10 -0
  19. package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
  20. package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
  21. package/dist/cli/chunk-66w9j7p6.js +322 -0
  22. package/dist/cli/chunk-66w9j7p6.js.map +14 -0
  23. package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
  24. package/dist/cli/chunk-7ppf1rva.js.map +10 -0
  25. package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
  26. package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
  27. package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
  28. package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
  29. package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
  30. package/dist/cli/chunk-cfyg47zg.js.map +10 -0
  31. package/dist/cli/chunk-cm89scdv.js +443 -0
  32. package/dist/cli/chunk-cm89scdv.js.map +11 -0
  33. package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
  34. package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
  35. package/dist/cli/chunk-e6atmn4h.js.map +36 -0
  36. package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
  37. package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
  38. package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
  39. package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
  40. package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
  41. package/dist/cli/chunk-ehweg4fr.js.map +218 -0
  42. package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
  43. package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
  44. package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
  45. package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
  46. package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
  47. package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
  48. package/dist/cli/chunk-gb420vvz.js.map +17 -0
  49. package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
  50. package/dist/cli/chunk-hebn0tpx.js.map +14 -0
  51. package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
  52. package/dist/cli/chunk-htrwgabr.js.map +15 -0
  53. package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
  54. package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
  55. package/dist/cli/chunk-j134vrp2.js +65 -0
  56. package/dist/cli/chunk-j134vrp2.js.map +10 -0
  57. package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
  58. package/dist/cli/chunk-kwrg63tm.js +31 -0
  59. package/dist/cli/chunk-kwrg63tm.js.map +10 -0
  60. package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
  61. package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
  62. package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
  63. package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
  64. package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
  65. package/dist/cli/chunk-ncj7w596.js.map +35 -0
  66. package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
  67. package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
  68. package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
  69. package/dist/cli/chunk-nrns10mj.js.map +10 -0
  70. package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
  71. package/dist/cli/chunk-t2m5j4pr.js +104 -0
  72. package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
  73. package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
  74. package/dist/cli/chunk-tphac74f.js +126 -0
  75. package/dist/cli/chunk-tphac74f.js.map +11 -0
  76. package/dist/cli/chunk-w1r4vase.js +18 -0
  77. package/dist/cli/chunk-w1r4vase.js.map +10 -0
  78. package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
  79. package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
  80. package/dist/cli/index.js +31 -20
  81. package/dist/cli/index.js.map +5 -5
  82. package/dist/types/ai/agent-surface.d.ts +8 -7
  83. package/dist/types/ai/ai-catalog.d.ts +7 -0
  84. package/dist/types/ai/ask-context.d.ts +26 -0
  85. package/dist/types/ai/ask.d.ts +271 -58
  86. package/dist/types/ai/component-markdown.d.ts +2 -0
  87. package/dist/types/ai/index.d.ts +2 -2
  88. package/dist/types/ai/openapi-components.d.ts +4 -1
  89. package/dist/types/ai/site-skill.d.ts +26 -0
  90. package/dist/types/ai/skills.d.ts +16 -0
  91. package/dist/types/astro/integration.d.ts +9 -0
  92. package/dist/types/astro/markdown-negotiation.d.ts +3 -0
  93. package/dist/types/astro/pages.d.ts +10 -0
  94. package/dist/types/captcha/hcaptcha.d.ts +27 -0
  95. package/dist/types/captcha/index.d.ts +28 -0
  96. package/dist/types/captcha/schema.d.ts +29 -0
  97. package/dist/types/captcha/turnstile.d.ts +28 -0
  98. package/dist/types/cli/init/scaffold.d.ts +1 -1
  99. package/dist/types/components/content/api-field.d.ts +62 -0
  100. package/dist/types/components/content/api-page.d.ts +100 -0
  101. package/dist/types/components/layout/nav-utils.d.ts +26 -0
  102. package/dist/types/components/openapi/code-samples.d.ts +29 -0
  103. package/dist/types/components/openapi/helpers.d.ts +158 -0
  104. package/dist/types/components/openapi/security.d.ts +95 -0
  105. package/dist/types/components/openapi/snippets.d.ts +60 -0
  106. package/dist/types/consent/ethyca.d.ts +48 -0
  107. package/dist/types/consent/index.d.ts +37 -0
  108. package/dist/types/consent/native.d.ts +28 -0
  109. package/dist/types/consent/osano.d.ts +42 -0
  110. package/dist/types/consent/schema.d.ts +110 -0
  111. package/dist/types/core/changelog-index.d.ts +8 -0
  112. package/dist/types/core/config-input.d.ts +217 -23
  113. package/dist/types/core/data.d.ts +53 -4
  114. package/dist/types/core/footer.d.ts +8 -0
  115. package/dist/types/core/i18n-ui.d.ts +88 -0
  116. package/dist/types/core/includes.d.ts +8 -2
  117. package/dist/types/core/links.d.ts +8 -0
  118. package/dist/types/core/localizable.d.ts +7 -0
  119. package/dist/types/core/page-modes.d.ts +29 -0
  120. package/dist/types/core/probe.d.ts +2 -0
  121. package/dist/types/core/project-graph.d.ts +6 -0
  122. package/dist/types/core/redirect-patterns.d.ts +152 -0
  123. package/dist/types/core/related.d.ts +40 -0
  124. package/dist/types/core/schema.d.ts +670 -56
  125. package/dist/types/core/sources/cache.d.ts +3 -0
  126. package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
  127. package/dist/types/core/sources/contentful.d.ts +17 -1
  128. package/dist/types/core/sources/lexical.d.ts +5 -0
  129. package/dist/types/core/sources/normalize.d.ts +20 -1
  130. package/dist/types/core/sources/read.d.ts +5 -0
  131. package/dist/types/core/sources/remote.d.ts +37 -10
  132. package/dist/types/core/sources/sanity.d.ts +1 -1
  133. package/dist/types/core/types.d.ts +18 -1
  134. package/dist/types/core/variables.d.ts +42 -0
  135. package/dist/types/deploy/adapter-output.d.ts +2 -1
  136. package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
  137. package/dist/types/deploy/adapters/node.d.ts +58 -23
  138. package/dist/types/deploy/adapters/registry.d.ts +10 -0
  139. package/dist/types/deploy/adapters/types.d.ts +3 -2
  140. package/dist/types/deploy/node-headers.d.ts +13 -2
  141. package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
  142. package/dist/types/deploy/platforms/netlify.d.ts +7 -0
  143. package/dist/types/deploy/platforms/node.d.ts +3 -1
  144. package/dist/types/deploy/platforms/types.d.ts +18 -7
  145. package/dist/types/deploy/platforms/vercel.d.ts +26 -1
  146. package/dist/types/deploy/redirects.d.ts +55 -11
  147. package/dist/types/deploy/sitemap.d.ts +2 -1
  148. package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
  149. package/dist/types/markdown/code-title.d.ts +17 -0
  150. package/dist/types/markdown/features.d.ts +3 -2
  151. package/dist/types/narration/build.d.ts +70 -0
  152. package/dist/types/narration/provider.d.ts +26 -0
  153. package/dist/types/narration/script.d.ts +154 -0
  154. package/dist/types/openapi/checks.d.ts +27 -0
  155. package/dist/types/openapi/graphql.d.ts +6 -0
  156. package/dist/types/openapi/model.d.ts +27 -10
  157. package/dist/types/openapi/overlay.d.ts +54 -0
  158. package/dist/types/openapi/parse.d.ts +16 -0
  159. package/dist/types/openapi/references.d.ts +30 -4
  160. package/dist/types/ratelimit/cloudflare.d.ts +39 -0
  161. package/dist/types/ratelimit/index.d.ts +27 -0
  162. package/dist/types/ratelimit/memory.d.ts +36 -0
  163. package/dist/types/ratelimit/schema.d.ts +119 -0
  164. package/dist/types/ratelimit/upstash.d.ts +46 -0
  165. package/dist/types/ratelimit/wrangler.d.ts +23 -0
  166. package/dist/types/reference/asyncapi.d.ts +10 -10
  167. package/dist/types/reference/graphql.d.ts +89 -11
  168. package/dist/types/reference/index.d.ts +1 -1
  169. package/dist/types/reference/openapi.d.ts +33 -12
  170. package/dist/types/reference/options.d.ts +82 -6
  171. package/dist/types/reference/scalar.d.ts +13 -0
  172. package/dist/types/reference/schema.d.ts +144 -36
  173. package/dist/types/search/adapters/registry.d.ts +3 -0
  174. package/dist/types/search/adapters/typesense.d.ts +14 -4
  175. package/dist/types/search/build.d.ts +3 -1
  176. package/dist/types/search/documents.d.ts +12 -1
  177. package/dist/types/search/orama-index.d.ts +13 -9
  178. package/dist/types/search/sync/algolia.d.ts +5 -2
  179. package/dist/types/search/sync/index.d.ts +3 -1
  180. package/dist/types/search/sync/typesense.d.ts +11 -7
  181. package/dist/types/seo/metatags.d.ts +20 -0
  182. package/dist/types/sources/contentful.d.ts +16 -0
  183. package/dist/types/sources/github-releases.d.ts +8 -1
  184. package/dist/types/sources/payload.d.ts +2 -0
  185. package/dist/types/sources/registry.d.ts +54 -0
  186. package/dist/types/sources/shared.d.ts +3 -0
  187. package/dist/types/sources/strapi.d.ts +2 -0
  188. package/docs/01-quickstart.mdx +4 -2
  189. package/docs/02-deployment.mdx +71 -17
  190. package/docs/03-upgrading.mdx +4 -4
  191. package/docs/04-migrating.mdx +1 -1
  192. package/docs/advanced/changelog.mdx +13 -2
  193. package/docs/advanced/skills.mdx +15 -1
  194. package/docs/cli/audit.mdx +51 -8
  195. package/docs/cli/doctor.mdx +5 -1
  196. package/docs/cli/evals.mdx +4 -4
  197. package/docs/cli/index.mdx +1 -0
  198. package/docs/cli/translate.mdx +1 -0
  199. package/docs/cli/validate.mdx +4 -3
  200. package/docs/configuration/analytics.mdx +3 -1
  201. package/docs/configuration/assistant.mdx +194 -38
  202. package/docs/configuration/consent.mdx +100 -0
  203. package/docs/configuration/customization.mdx +8 -6
  204. package/docs/configuration/export.mdx +5 -3
  205. package/docs/configuration/index.mdx +64 -5
  206. package/docs/configuration/meta.ts +3 -0
  207. package/docs/configuration/narration.mdx +119 -0
  208. package/docs/configuration/rate-limiting.mdx +90 -0
  209. package/docs/configuration/search.mdx +63 -12
  210. package/docs/configuration/theming.mdx +3 -1
  211. package/docs/content/components.mdx +108 -2
  212. package/docs/content/frontmatter.mdx +80 -2
  213. package/docs/content/i18n.mdx +39 -4
  214. package/docs/content/includes.mdx +16 -0
  215. package/docs/content/meta.mdx +1 -0
  216. package/docs/content/meta.ts +1 -0
  217. package/docs/content/navigation.mdx +32 -10
  218. package/docs/content/sources/contentful.mdx +35 -0
  219. package/docs/content/sources/custom.mdx +43 -0
  220. package/docs/content/sources/github-releases.mdx +39 -0
  221. package/docs/content/sources/index.mdx +91 -0
  222. package/docs/content/sources/meta.ts +16 -0
  223. package/docs/content/sources/notion.mdx +32 -0
  224. package/docs/content/sources/obsidian.mdx +37 -0
  225. package/docs/content/sources/payload.mdx +31 -0
  226. package/docs/content/sources/remote-mdx.mdx +44 -0
  227. package/docs/content/sources/sanity.mdx +29 -0
  228. package/docs/content/sources/strapi.mdx +32 -0
  229. package/docs/content/syntax.mdx +69 -4
  230. package/docs/content/variables.mdx +41 -0
  231. package/docs/discoverability/agent-discovery.mdx +29 -2
  232. package/docs/discoverability/index.mdx +2 -2
  233. package/docs/discoverability/json-api.mdx +2 -0
  234. package/docs/discoverability/llms-txt.mdx +2 -2
  235. package/docs/discoverability/markdown.mdx +3 -1
  236. package/docs/discoverability/mcp.mdx +4 -0
  237. package/docs/discoverability/metadata.mdx +17 -0
  238. package/docs/discoverability/sitemap-and-robots.mdx +1 -1
  239. package/docs/references/api-pages.mdx +74 -0
  240. package/docs/references/asyncapi.mdx +4 -2
  241. package/docs/references/graphql.mdx +14 -2
  242. package/docs/references/meta.ts +1 -1
  243. package/docs/references/openapi.mdx +148 -7
  244. package/docs/references/scalar.mdx +3 -1
  245. package/package.json +43 -8
  246. package/skills/blume/SKILL.md +3 -0
  247. package/skills/blume-migrate/SKILL.md +6 -6
  248. package/skills/blume-migrate/references/docusaurus.md +7 -7
  249. package/skills/blume-migrate/references/fumadocs.md +17 -13
  250. package/skills/blume-migrate/references/mintlify.md +37 -19
  251. package/skills/blume-migrate/references/nextra.md +10 -7
  252. package/skills/blume-migrate/references/starlight.md +11 -8
  253. package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
  254. package/skills/blume-write-skill/SKILL.md +82 -0
  255. package/src/ai/agent-readability.ts +2 -1
  256. package/src/ai/agent-surface.ts +9 -7
  257. package/src/ai/ai-catalog.ts +6 -3
  258. package/src/ai/ask-context.ts +103 -20
  259. package/src/ai/ask-data.ts +6 -0
  260. package/src/ai/ask-limits.ts +13 -0
  261. package/src/ai/ask-tools.ts +142 -0
  262. package/src/ai/ask.ts +354 -76
  263. package/src/ai/changelog-markdown.ts +11 -6
  264. package/src/ai/component-markdown.ts +76 -1
  265. package/src/ai/cors.ts +14 -3
  266. package/src/ai/index.ts +12 -0
  267. package/src/ai/llms.ts +6 -2
  268. package/src/ai/markdown.ts +2 -1
  269. package/src/ai/mcp/data.ts +6 -0
  270. package/src/ai/mcp/query.ts +14 -6
  271. package/src/ai/openapi-components.ts +36 -6
  272. package/src/ai/relative-links.ts +4 -38
  273. package/src/ai/site-skill.ts +274 -0
  274. package/src/ai/skills.ts +35 -2
  275. package/src/ai/write-skill.ts +97 -0
  276. package/src/astro/generate.ts +210 -66
  277. package/src/astro/index.ts +1 -0
  278. package/src/astro/integration.ts +42 -4
  279. package/src/astro/markdown-negotiation.ts +3 -0
  280. package/src/astro/module-types.ts +9 -1
  281. package/src/astro/pages.ts +23 -0
  282. package/src/astro/templates.ts +406 -108
  283. package/src/astro/variables.ts +31 -0
  284. package/src/audit/catalog.ts +38 -3
  285. package/src/audit/checks/contrast.ts +183 -0
  286. package/src/audit/checks/i18n.ts +2 -3
  287. package/src/audit/checks/indexability.ts +2 -3
  288. package/src/audit/checks/links.ts +19 -13
  289. package/src/audit/checks/network.ts +110 -6
  290. package/src/audit/checks/redirects.ts +6 -4
  291. package/src/audit/checks/robots.ts +58 -2
  292. package/src/audit/checks/sitemap.ts +2 -3
  293. package/src/audit/redirects.ts +46 -15
  294. package/src/audit/run.ts +5 -0
  295. package/src/audit/types.ts +4 -1
  296. package/src/audit/url.ts +14 -5
  297. package/src/blume-modules.d.ts +12 -1
  298. package/src/captcha/client.ts +152 -0
  299. package/src/captcha/hcaptcha.ts +36 -0
  300. package/src/captcha/index.ts +28 -0
  301. package/src/captcha/schema.ts +32 -0
  302. package/src/captcha/turnstile.ts +38 -0
  303. package/src/captcha/verify.ts +71 -0
  304. package/src/cli/args.ts +51 -0
  305. package/src/cli/build-failure.ts +23 -0
  306. package/src/cli/command-meta.ts +5 -0
  307. package/src/cli/commands/audit.ts +10 -1
  308. package/src/cli/commands/dev.ts +18 -2
  309. package/src/cli/commands/doctor.ts +67 -28
  310. package/src/cli/commands/eval.ts +36 -4
  311. package/src/cli/commands/init.ts +6 -4
  312. package/src/cli/commands/skill.ts +96 -0
  313. package/src/cli/commands/validate.ts +10 -1
  314. package/src/cli/index.ts +5 -0
  315. package/src/cli/init/scaffold.ts +3 -3
  316. package/src/cli/prepare.ts +6 -3
  317. package/src/cli/required-secrets.ts +72 -30
  318. package/src/components/BlumePage.astro +2 -0
  319. package/src/components/content/ApiEndpoint.astro +18 -0
  320. package/src/components/content/ApiField.astro +79 -0
  321. package/src/components/content/ApiPlayground.astro +66 -0
  322. package/src/components/content/ApiRail.astro +19 -0
  323. package/src/components/content/Color.astro +1 -0
  324. package/src/components/content/FileTree.astro +1 -0
  325. package/src/components/content/GithubInfo.astro +1 -0
  326. package/src/components/content/Panel.astro +1 -0
  327. package/src/components/content/ParamField.astro +25 -0
  328. package/src/components/content/RequestExample.astro +17 -0
  329. package/src/components/content/ResponseExample.astro +17 -0
  330. package/src/components/content/ResponseField.astro +32 -0
  331. package/src/components/content/Step.astro +1 -0
  332. package/src/components/content/Tile.astro +1 -0
  333. package/src/components/content/Tooltip.astro +1 -0
  334. package/src/components/content/Tree.astro +1 -0
  335. package/src/components/content/TypeTable.astro +4 -1
  336. package/src/components/content/View.astro +21 -0
  337. package/src/components/content/ViewSwitcher.astro +168 -0
  338. package/src/components/content/api-field.ts +103 -0
  339. package/src/components/content/api-page.ts +248 -0
  340. package/src/components/content/mermaid-element.ts +15 -1
  341. package/src/components/content/view-switcher.ts +71 -0
  342. package/src/components/index.ts +2 -0
  343. package/src/components/islands/Assistant.astro +10 -1
  344. package/src/components/islands/assistant.tsx +104 -14
  345. package/src/components/islands/code-question.ts +62 -0
  346. package/src/components/islands/hooks.ts +136 -21
  347. package/src/components/islands/support-link.ts +68 -0
  348. package/src/components/layout/Analytics.astro +11 -2
  349. package/src/components/layout/Banner.astro +14 -10
  350. package/src/components/layout/Breadcrumbs.astro +6 -2
  351. package/src/components/layout/ConsentBanner.astro +62 -0
  352. package/src/components/layout/ConsentHead.astro +38 -0
  353. package/src/components/layout/Directory.astro +94 -0
  354. package/src/components/layout/DrawerSwitchers.astro +51 -0
  355. package/src/components/layout/Empty.astro +2 -2
  356. package/src/components/layout/Header.astro +122 -80
  357. package/src/components/layout/LanguageSwitcher.astro +48 -15
  358. package/src/components/layout/NarrationPlayer.astro +1085 -0
  359. package/src/components/layout/NavSelector.astro +33 -7
  360. package/src/components/layout/PageActions.astro +139 -24
  361. package/src/components/layout/PageFeedback.astro +54 -49
  362. package/src/components/layout/PageLayout.astro +71 -3
  363. package/src/components/layout/ReferenceLayout.astro +17 -6
  364. package/src/components/layout/RelatedPages.astro +42 -0
  365. package/src/components/layout/RootLayout.astro +318 -47
  366. package/src/components/layout/Search.astro +47 -19
  367. package/src/components/layout/SiteFooter.astro +124 -0
  368. package/src/components/layout/SiteMetatags.astro +16 -0
  369. package/src/components/layout/TableOfContents.astro +24 -17
  370. package/src/components/layout/consent/native.ts +79 -0
  371. package/src/components/layout/consent/types.ts +37 -0
  372. package/src/components/layout/footer-links.ts +53 -0
  373. package/src/components/layout/footer-socials.ts +87 -0
  374. package/src/components/layout/head-scripts.ts +6 -1
  375. package/src/components/layout/locale-redirect.ts +107 -0
  376. package/src/components/layout/nav-utils.ts +83 -0
  377. package/src/components/layout/page-feedback.ts +96 -0
  378. package/src/components/layout/search/algolia.ts +10 -1
  379. package/src/components/layout/search/analytics.ts +126 -0
  380. package/src/components/layout/search/endpoint.ts +48 -5
  381. package/src/components/layout/search/flexsearch.ts +17 -5
  382. package/src/components/layout/search/orama-cloud.ts +26 -14
  383. package/src/components/layout/search/pagefind.ts +114 -5
  384. package/src/components/layout/search/types.ts +32 -0
  385. package/src/components/layout/search/typesense.ts +19 -3
  386. package/src/components/openapi/AsyncApiOperation.astro +14 -7
  387. package/src/components/openapi/Authorization.astro +10 -0
  388. package/src/components/openapi/GraphqlOperation.astro +5 -0
  389. package/src/components/openapi/Operation.astro +184 -13
  390. package/src/components/openapi/ParametersTable.astro +8 -4
  391. package/src/components/openapi/Playground.astro +7 -1
  392. package/src/components/openapi/RequestBody.astro +24 -5
  393. package/src/components/openapi/RequestPanel.astro +59 -7
  394. package/src/components/openapi/Responses.astro +7 -4
  395. package/src/components/openapi/SchemaTable.astro +15 -3
  396. package/src/components/openapi/async-snippets.ts +65 -9
  397. package/src/components/openapi/async.ts +123 -29
  398. package/src/components/openapi/code-samples.ts +97 -0
  399. package/src/components/openapi/graphql-helpers.ts +35 -12
  400. package/src/components/openapi/helpers.ts +36 -2
  401. package/src/components/openapi/message-model.ts +54 -11
  402. package/src/components/openapi/message.ts +14 -4
  403. package/src/components/openapi/operation-model.ts +16 -7
  404. package/src/components/openapi/playground-client.ts +24 -5
  405. package/src/components/openapi/playground-schema.ts +1 -1
  406. package/src/components/openapi/schema-tree.ts +44 -14
  407. package/src/components/openapi/security.ts +16 -3
  408. package/src/components/openapi/snippets.ts +873 -10
  409. package/src/components/openapi/validate-json.ts +4 -3
  410. package/src/components/props.ts +6 -0
  411. package/src/consent/client.ts +95 -0
  412. package/src/consent/clients.ts +19 -0
  413. package/src/consent/ethyca.ts +71 -0
  414. package/src/consent/head.ts +24 -0
  415. package/src/consent/index.ts +37 -0
  416. package/src/consent/init.ts +29 -0
  417. package/src/consent/native.ts +36 -0
  418. package/src/consent/osano.ts +59 -0
  419. package/src/consent/schema.ts +30 -0
  420. package/src/core/builtin-tags.ts +5 -0
  421. package/src/core/changelog-index.ts +31 -1
  422. package/src/core/client-address.ts +19 -0
  423. package/src/core/component-diagnostics.ts +53 -0
  424. package/src/core/component-overrides.ts +32 -0
  425. package/src/core/config-input.ts +225 -23
  426. package/src/core/data.ts +46 -4
  427. package/src/core/diagnostics.ts +8 -2
  428. package/src/core/footer.ts +26 -0
  429. package/src/core/graph.ts +39 -36
  430. package/src/core/i18n-ui.ts +84 -2
  431. package/src/core/includes.ts +21 -4
  432. package/src/core/links.ts +63 -19
  433. package/src/core/localizable.ts +26 -0
  434. package/src/core/navigation.ts +43 -12
  435. package/src/core/page-modes.ts +56 -0
  436. package/src/core/probe.ts +26 -6
  437. package/src/core/project-graph.ts +163 -16
  438. package/src/core/redirect-patterns.ts +520 -0
  439. package/src/core/related.ts +131 -0
  440. package/src/core/schema.ts +339 -66
  441. package/src/core/sources/cache.ts +6 -0
  442. package/src/core/sources/contentful-rich-text.ts +29 -6
  443. package/src/core/sources/contentful.ts +135 -25
  444. package/src/core/sources/filesystem.ts +26 -4
  445. package/src/core/sources/github-releases.ts +12 -1
  446. package/src/core/sources/lexical.ts +15 -10
  447. package/src/core/sources/mdx-remote.ts +62 -10
  448. package/src/core/sources/normalize.ts +228 -41
  449. package/src/core/sources/notion.ts +7 -1
  450. package/src/core/sources/obsidian.ts +16 -3
  451. package/src/core/sources/payload.ts +38 -15
  452. package/src/core/sources/read.ts +8 -3
  453. package/src/core/sources/remote.ts +72 -15
  454. package/src/core/sources/resolve.ts +11 -1
  455. package/src/core/sources/sanity.ts +43 -25
  456. package/src/core/sources/strapi.ts +2 -2
  457. package/src/core/types.ts +19 -1
  458. package/src/core/ui-packs/ar.ts +44 -0
  459. package/src/core/ui-packs/bg.ts +46 -0
  460. package/src/core/ui-packs/bn.ts +44 -0
  461. package/src/core/ui-packs/ca.ts +47 -0
  462. package/src/core/ui-packs/cs.ts +45 -0
  463. package/src/core/ui-packs/da.ts +46 -0
  464. package/src/core/ui-packs/de.ts +47 -0
  465. package/src/core/ui-packs/el.ts +46 -0
  466. package/src/core/ui-packs/es.ts +47 -0
  467. package/src/core/ui-packs/fa.ts +46 -0
  468. package/src/core/ui-packs/fi.ts +46 -0
  469. package/src/core/ui-packs/fr.ts +47 -0
  470. package/src/core/ui-packs/he.ts +44 -0
  471. package/src/core/ui-packs/hi.ts +45 -0
  472. package/src/core/ui-packs/hr.ts +46 -0
  473. package/src/core/ui-packs/hu.ts +45 -0
  474. package/src/core/ui-packs/id.ts +46 -0
  475. package/src/core/ui-packs/it.ts +46 -0
  476. package/src/core/ui-packs/ja.ts +46 -0
  477. package/src/core/ui-packs/ko.ts +45 -0
  478. package/src/core/ui-packs/nl.ts +47 -0
  479. package/src/core/ui-packs/no.ts +45 -0
  480. package/src/core/ui-packs/pl.ts +46 -0
  481. package/src/core/ui-packs/pt-br.ts +47 -0
  482. package/src/core/ui-packs/pt.ts +46 -0
  483. package/src/core/ui-packs/ro.ts +46 -0
  484. package/src/core/ui-packs/ru.ts +46 -0
  485. package/src/core/ui-packs/sk.ts +45 -0
  486. package/src/core/ui-packs/sr.ts +46 -0
  487. package/src/core/ui-packs/sv.ts +45 -0
  488. package/src/core/ui-packs/th.ts +44 -0
  489. package/src/core/ui-packs/tr.ts +46 -0
  490. package/src/core/ui-packs/uk.ts +46 -0
  491. package/src/core/ui-packs/vi.ts +46 -0
  492. package/src/core/ui-packs/zh-tw.ts +44 -0
  493. package/src/core/ui-packs/zh.ts +44 -0
  494. package/src/core/variables.ts +103 -0
  495. package/src/deploy/adapter-output.ts +7 -2
  496. package/src/deploy/adapters/cloudflare.ts +7 -5
  497. package/src/deploy/adapters/node.ts +47 -9
  498. package/src/deploy/adapters/types.ts +7 -3
  499. package/src/deploy/artifacts.ts +79 -9
  500. package/src/deploy/cloudflare-negotiation.ts +35 -5
  501. package/src/deploy/headers.ts +2 -1
  502. package/src/deploy/node-headers.ts +63 -9
  503. package/src/deploy/platforms/cloudflare.ts +45 -9
  504. package/src/deploy/platforms/netlify.ts +35 -2
  505. package/src/deploy/platforms/node.ts +12 -2
  506. package/src/deploy/platforms/types.ts +21 -7
  507. package/src/deploy/platforms/vercel.ts +149 -17
  508. package/src/deploy/redirects.ts +151 -24
  509. package/src/deploy/rss.ts +3 -1
  510. package/src/deploy/sitemap.ts +39 -5
  511. package/src/deploy/vercel-negotiation.ts +326 -102
  512. package/src/eval/agents.ts +18 -1
  513. package/src/eval/prompts.ts +6 -3
  514. package/src/eval/report.ts +34 -13
  515. package/src/eval/run.ts +5 -0
  516. package/src/markdown/api-rail.ts +259 -0
  517. package/src/markdown/code-title.ts +35 -9
  518. package/src/markdown/features.ts +3 -2
  519. package/src/markdown/fence-meta.ts +2 -0
  520. package/src/markdown/include.ts +11 -1
  521. package/src/markdown/index.ts +28 -5
  522. package/src/markdown/math.ts +4 -4
  523. package/src/markdown/relative-links.ts +3 -2
  524. package/src/markdown/variables.ts +56 -0
  525. package/src/markdown/views.ts +82 -0
  526. package/src/narration/build.ts +412 -0
  527. package/src/narration/player.ts +249 -0
  528. package/src/narration/provider.ts +29 -0
  529. package/src/narration/script.ts +592 -0
  530. package/src/og/card.ts +7 -6
  531. package/src/openapi/checks.ts +273 -0
  532. package/src/openapi/graphql-build.ts +21 -0
  533. package/src/openapi/graphql.ts +11 -0
  534. package/src/openapi/model.ts +72 -27
  535. package/src/openapi/overlay.ts +256 -0
  536. package/src/openapi/parse.ts +182 -4
  537. package/src/openapi/references.ts +64 -8
  538. package/src/openapi/render-mdx.ts +5 -1
  539. package/src/openapi/scalar.ts +40 -6
  540. package/src/openapi/source.ts +40 -15
  541. package/src/ratelimit/cloudflare.ts +54 -0
  542. package/src/ratelimit/index.ts +30 -0
  543. package/src/ratelimit/memory.ts +45 -0
  544. package/src/ratelimit/runtime.ts +247 -0
  545. package/src/ratelimit/schema.ts +28 -0
  546. package/src/ratelimit/upstash.ts +60 -0
  547. package/src/ratelimit/wrangler.ts +70 -0
  548. package/src/reference/asyncapi.ts +2 -2
  549. package/src/reference/graphql.ts +20 -3
  550. package/src/reference/index.ts +1 -0
  551. package/src/reference/openapi.ts +21 -7
  552. package/src/reference/options.ts +80 -8
  553. package/src/reference/scalar.ts +33 -8
  554. package/src/registry/eject.ts +23 -5
  555. package/src/registry/registry.ts +7 -0
  556. package/src/search/adapters/locale-scope.ts +30 -0
  557. package/src/search/adapters/typesense.ts +14 -4
  558. package/src/search/build.ts +21 -3
  559. package/src/search/documents.ts +26 -2
  560. package/src/search/orama-index.ts +191 -34
  561. package/src/search/pagefind-ranking.ts +39 -0
  562. package/src/search/source-pages.ts +29 -0
  563. package/src/search/sync/algolia.ts +111 -10
  564. package/src/search/sync/index.ts +52 -13
  565. package/src/search/sync/orama-cloud.ts +3 -0
  566. package/src/search/sync/typesense.ts +76 -26
  567. package/src/seo/metatags.ts +67 -0
  568. package/src/sources/contentful.ts +12 -0
  569. package/src/sources/github-releases.ts +7 -1
  570. package/src/sources/shared.ts +3 -0
  571. package/src/theme/chrome-icons.ts +1 -0
  572. package/src/theme/color.ts +500 -0
  573. package/src/theme/entry.ts +85 -6
  574. package/src/theme/palette.ts +121 -45
  575. package/src/translate/prompts.ts +1 -0
  576. package/src/translate/validate.ts +31 -3
  577. package/src/upgrade/upgrade.ts +4 -171
  578. package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
  579. package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
  580. package/dist/cli/chunk-35d4wj9f.js.map +0 -15
  581. package/dist/cli/chunk-364znk6q.js +0 -75
  582. package/dist/cli/chunk-364znk6q.js.map +0 -11
  583. package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
  584. package/dist/cli/chunk-8ktnccpt.js.map +0 -10
  585. package/dist/cli/chunk-9t7a85s3.js.map +0 -10
  586. package/dist/cli/chunk-b07cmahc.js +0 -145
  587. package/dist/cli/chunk-b07cmahc.js.map +0 -11
  588. package/dist/cli/chunk-c8chx29p.js.map +0 -36
  589. package/dist/cli/chunk-e04dxsz1.js +0 -39
  590. package/dist/cli/chunk-e04dxsz1.js.map +0 -10
  591. package/dist/cli/chunk-j85vccga.js.map +0 -36
  592. package/dist/cli/chunk-p3v96n38.js.map +0 -10
  593. package/dist/cli/chunk-pehfxfta.js.map +0 -10
  594. package/dist/cli/chunk-pv29h0wf.js.map +0 -190
  595. package/dist/cli/chunk-q58y5e6a.js.map +0 -10
  596. package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
  597. package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
  598. package/dist/cli/chunk-yfyb25rh.js.map +0 -14
  599. package/docs/content/sources.mdx +0 -334
  600. /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
  601. /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
  602. /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
  603. /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
  604. /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
  605. /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
  606. /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
  607. /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.js.map} +0 -0
@@ -19,27 +19,42 @@ import {
19
19
  writeAgentReport,
20
20
  fixPrompt,
21
21
  launchInstalledAgent
22
- } from "./chunk-1d7ve1dm.js";
22
+ } from "./chunk-42t4jxdx.js";
23
23
  import {
24
24
  routeSetFor,
25
25
  frontmatter_default,
26
+ isPatternPath,
27
+ patternDestination,
26
28
  gradeExternal,
27
29
  probeAll,
28
30
  applyBaseToAstroRedirects,
29
31
  deployPlatform
30
- } from "./chunk-pv29h0wf.js";
32
+ } from "./chunk-ehweg4fr.js";
31
33
  import {
32
34
  normalizeBasePath,
33
35
  normalizePath,
34
36
  stripBasePath
35
- } from "./chunk-3em5wd2y.js";
37
+ } from "./chunk-zccbjcj0.js";
36
38
  import {
37
39
  deployStaticDir,
38
40
  examplesRouteBase
39
- } from "./chunk-5m5nmvyq.js";
41
+ } from "./chunk-gb420vvz.js";
42
+ import {
43
+ parseColor,
44
+ composite,
45
+ contrastRatio,
46
+ MIN_TEXT_CONTRAST,
47
+ themeInk,
48
+ labelOn,
49
+ resolveAccent,
50
+ resolveAction
51
+ } from "./chunk-cm89scdv.js";
40
52
  import {
41
53
  scanProject
42
- } from "./chunk-j85vccga.js";
54
+ } from "./chunk-ncj7w596.js";
55
+ import {
56
+ parseIgnoreFlag
57
+ } from "./chunk-j134vrp2.js";
43
58
 
44
59
  // src/cli/commands/audit.ts
45
60
  import { defineCommand } from "citty";
@@ -116,7 +131,11 @@ var resolveHref = (pageUrl, href, origin, deployBase = "") => {
116
131
  if (origin && parsed.origin === origin) {
117
132
  const served = decodePath(parsed.pathname);
118
133
  if (!underBase(deployBase, served)) {
119
- return { kind: "outside-base", path: normalizePath(served) };
134
+ return {
135
+ absolute: true,
136
+ kind: "outside-base",
137
+ path: normalizePath(served)
138
+ };
120
139
  }
121
140
  return {
122
141
  hash: parsed.hash.slice(1),
@@ -135,7 +154,11 @@ var resolveHref = (pageUrl, href, origin, deployBase = "") => {
135
154
  }
136
155
  const served = decodePath(resolved.pathname);
137
156
  if (target.startsWith("/") && !underBase(deployBase, served)) {
138
- return { kind: "outside-base", path: normalizePath(served) };
157
+ return {
158
+ absolute: false,
159
+ kind: "outside-base",
160
+ path: normalizePath(served)
161
+ };
139
162
  }
140
163
  return {
141
164
  hash: resolved.hash.slice(1),
@@ -337,6 +360,105 @@ var contentChecks = {
337
360
  tier: "static"
338
361
  };
339
362
 
363
+ // src/audit/checks/contrast.ts
364
+ var MODES = ["light", "dark"];
365
+ var fillPair = (key, fill, page, mode) => ({
366
+ fix: `Neither white nor dark text reaches ${MIN_TEXT_CONTRAST}:1 on this shade. Move \`${key}\`'s ${mode} shade lighter or darker.`,
367
+ key,
368
+ label: key === "theme.action" ? "The call-to-action label" : "Button labels on the accent",
369
+ surface: composite(fill, page),
370
+ text: parseColor(labelOn(fill, mode)) ?? fill
371
+ });
372
+ var accentPairs = (fill, page, mode) => [
373
+ {
374
+ fix: `${mode === "light" ? "Darken" : "Lighten"} \`theme.accent\`'s ${mode} shade (\`theme.accent: { light, dark }\`).`,
375
+ key: "theme.accent",
376
+ label: "Accent text on the page",
377
+ surface: page,
378
+ text: fill
379
+ },
380
+ fillPair("theme.accent", fill, page, mode)
381
+ ];
382
+ var backgroundPairs = (page, mode) => {
383
+ const fix = `Pick a \`theme.background\` ${mode} color further from the text color.`;
384
+ return [
385
+ {
386
+ fix,
387
+ key: "theme.background",
388
+ label: "Body text on the page",
389
+ surface: page,
390
+ text: themeInk(mode, "foreground")
391
+ },
392
+ {
393
+ fix,
394
+ key: "theme.background",
395
+ label: "Secondary text on the page",
396
+ surface: page,
397
+ text: themeInk(mode, "mutedForeground")
398
+ }
399
+ ];
400
+ };
401
+ var modeColors = (theme, mode) => {
402
+ const unread = [];
403
+ const read = (color) => {
404
+ const parsed = parseColor(color.value);
405
+ if (!parsed) {
406
+ unread.push(color);
407
+ }
408
+ return parsed;
409
+ };
410
+ const custom = theme.background?.[mode];
411
+ const customPage = custom === undefined ? null : read({ key: "theme.background", value: custom });
412
+ if (custom !== undefined && !customPage) {
413
+ return { pairs: [], unread };
414
+ }
415
+ const page = customPage ?? themeInk(mode, "background");
416
+ const pairs = customPage ? backgroundPairs(customPage, mode) : [];
417
+ const accent = read({
418
+ key: "theme.accent",
419
+ value: resolveAccent(theme)[mode]
420
+ });
421
+ if (accent) {
422
+ pairs.push(...accentPairs(accent, page, mode));
423
+ }
424
+ const action = resolveAction(theme);
425
+ const actionFill = action && read({ key: "theme.action", value: action[mode] });
426
+ if (actionFill) {
427
+ pairs.push(fillPair("theme.action", actionFill, page, mode));
428
+ }
429
+ return { pairs, unread };
430
+ };
431
+ var contrastChecks = {
432
+ category: "accessibility",
433
+ run(context) {
434
+ const { theme } = context.project.config;
435
+ const site = {
436
+ file: context.project.context.configFile ?? undefined,
437
+ url: "/"
438
+ };
439
+ const found = [];
440
+ const reported = new Set;
441
+ for (const mode of MODES) {
442
+ const { pairs, unread } = modeColors(theme, mode);
443
+ for (const color of unread) {
444
+ const id = `${color.key}:${color.value}`;
445
+ if (!reported.has(id)) {
446
+ reported.add(id);
447
+ found.push(finding("BLUME_AUDIT_THEME_COLOR_UNCHECKED", site, `\`${color.key}\` is "${color.value}", which the audit can't read as a color, so its contrast went unchecked.`));
448
+ }
449
+ }
450
+ for (const pair of pairs) {
451
+ const ratio = contrastRatio(pair.text, pair.surface);
452
+ if (ratio < MIN_TEXT_CONTRAST) {
453
+ found.push(finding("BLUME_AUDIT_THEME_CONTRAST_LOW", site, `${pair.label} in ${mode} mode is ${ratio.toFixed(2)}:1, under the ${MIN_TEXT_CONTRAST}:1 WCAG AA asks of body text (\`${pair.key}\`).`, pair.fix));
454
+ }
455
+ }
456
+ }
457
+ return found;
458
+ },
459
+ tier: "static"
460
+ };
461
+
340
462
  // src/audit/checks/dns-aid.ts
341
463
  var RR_SVCB = 64;
342
464
  var RR_HTTPS = 65;
@@ -495,6 +617,68 @@ var duplicateChecks = {
495
617
  tier: "static"
496
618
  };
497
619
 
620
+ // src/audit/redirects.ts
621
+ var pathOnly = (value) => {
622
+ const cut = value.search(/[?#]/u);
623
+ return cut === -1 ? value : value.slice(0, cut);
624
+ };
625
+ var resolveRedirects = (redirects, served) => {
626
+ const byFrom = new Map;
627
+ for (const redirect of redirects) {
628
+ byFrom.set(normalizePath(redirect.from), redirect);
629
+ }
630
+ const hopFrom = (path) => byFrom.get(path)?.to ?? patternDestination(redirects, path);
631
+ return redirects.map((redirect) => {
632
+ const from = normalizePath(redirect.from);
633
+ if (isPatternPath(redirect.from)) {
634
+ return { ...redirect, chain: [from], outcome: "pattern" };
635
+ }
636
+ const chain = [from];
637
+ const seen = new Set([from]);
638
+ let current = redirect.to;
639
+ for (;; ) {
640
+ if (/^https?:\/\//iu.test(current)) {
641
+ chain.push(current);
642
+ break;
643
+ }
644
+ const next = normalizePath(pathOnly(current));
645
+ if (seen.has(next)) {
646
+ chain.push(next);
647
+ return {
648
+ ...redirect,
649
+ chain,
650
+ outcome: "loop"
651
+ };
652
+ }
653
+ chain.push(next);
654
+ seen.add(next);
655
+ const hop = hopFrom(next);
656
+ if (hop === undefined) {
657
+ break;
658
+ }
659
+ current = hop;
660
+ }
661
+ const destination = chain.at(-1) ?? from;
662
+ const external = /^https?:\/\//iu.test(destination);
663
+ if (!(external || served(destination))) {
664
+ return { ...redirect, chain, outcome: "broken" };
665
+ }
666
+ return {
667
+ ...redirect,
668
+ chain,
669
+ outcome: chain.length > 2 ? "chain" : "ok"
670
+ };
671
+ });
672
+ };
673
+ var redirectAt = (redirects, path) => {
674
+ const exact = redirects.find((entry) => normalizePath(entry.from) === path);
675
+ if (exact) {
676
+ return exact;
677
+ }
678
+ const to = patternDestination(redirects, path);
679
+ return to === undefined ? undefined : { to };
680
+ };
681
+
498
682
  // src/audit/checks/indexability.ts
499
683
  var parseCanonical = (canonical) => {
500
684
  try {
@@ -538,7 +722,7 @@ var canonicalChecks = (context, page) => {
538
722
  if (target === normalizePath(page.url)) {
539
723
  return found;
540
724
  }
541
- const redirect = context.redirects.find((entry) => normalizePath(entry.from) === target);
725
+ const redirect = redirectAt(context.redirects, target);
542
726
  if (redirect) {
543
727
  found.push(finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical points at ${target}, which is a redirect to ${redirect.to}.`));
544
728
  } else if (context.byUrl.has(target)) {
@@ -643,7 +827,7 @@ var hreflangChecks = (context, page) => {
643
827
  continue;
644
828
  }
645
829
  const target = context.byUrl.get(path);
646
- const redirect = context.redirects.find((entry) => normalizePath(entry.from) === path);
830
+ const redirect = redirectAt(context.redirects, path);
647
831
  if (redirect) {
648
832
  found.push(finding("BLUME_AUDIT_HREFLANG_BAD_TARGET", pageSite(context, page), `hreflang="${alternate.lang}" points at ${path}, which redirects to ${redirect.to}.`));
649
833
  } else if (!target) {
@@ -758,7 +942,6 @@ var anchorResolves = (target, fragment) => {
758
942
  return target.ids.has(fragment);
759
943
  }
760
944
  };
761
- var redirectFrom = (context, path) => context.redirects.find((entry) => normalizePath(entry.from) === path);
762
945
  var linkChecks = {
763
946
  category: "links",
764
947
  run(context) {
@@ -793,6 +976,9 @@ var linkChecks = {
793
976
  return;
794
977
  }
795
978
  if (resolved.kind === "outside-base") {
979
+ if (resolved.absolute) {
980
+ return;
981
+ }
796
982
  if (link.content) {
797
983
  found.push(finding("BLUME_AUDIT_LINK_TO_BROKEN", pageSite(context, page), `Link to ${link.href} is missing deployment.base (${deployBase}), so the deployed site does not serve it.`));
798
984
  } else if (!brokenChrome.has(resolved.path)) {
@@ -811,7 +997,7 @@ var linkChecks = {
811
997
  found.push(finding("BLUME_AUDIT_INTERNAL_LINK_NOFOLLOW", pageSite(context, page), `Internal link to ${resolved.path} is rel="nofollow".`));
812
998
  }
813
999
  const { path } = resolved;
814
- const redirect = redirectFrom(context, path);
1000
+ const redirect = redirectAt(context.redirects, path);
815
1001
  if (redirect) {
816
1002
  if (link.content) {
817
1003
  found.push(finding("BLUME_AUDIT_LINK_TO_REDIRECT", pageSite(context, page), `Link to ${path} goes through a redirect to ${redirect.to}.`));
@@ -838,7 +1024,7 @@ var linkChecks = {
838
1024
  found.push(finding("BLUME_AUDIT_LINK_TO_BROKEN", { url: page.url }, `Navigation links to ${path}, which the build does not serve.`, "Fix the entry in your navigation config or meta file."));
839
1025
  }
840
1026
  for (const [path, page] of redirectedChrome) {
841
- const redirect = redirectFrom(context, path);
1027
+ const redirect = redirectAt(context.redirects, path);
842
1028
  found.push(finding("BLUME_AUDIT_LINK_TO_REDIRECT", { url: page.url }, `Navigation links to ${path}, which redirects to ${redirect?.to}.`, "Point the navigation entry straight at the destination."));
843
1029
  }
844
1030
  for (const [key, page] of brokenChromeAnchors) {
@@ -846,7 +1032,10 @@ var linkChecks = {
846
1032
  }
847
1033
  const homeUrl = normalizeBasePath(context.project.config.basePath) || "/";
848
1034
  for (const page of orphanPages(context.pages, context.graph, homeUrl)) {
849
- found.push(finding("BLUME_AUDIT_ORPHAN_PAGE", pageSite(context, page), "No other page's body links here — it is reachable only from the sidebar."));
1035
+ const fromNavigation = [
1036
+ ...context.graph.chromeIn.get(page.url) ?? []
1037
+ ].some((from) => from !== page.url);
1038
+ found.push(finding("BLUME_AUDIT_ORPHAN_PAGE", pageSite(context, page), fromNavigation ? "No other page's body links here — it is reachable only from the sidebar." : "No page links here, from its body or from navigation, so readers and crawlers can't reach it."));
850
1039
  }
851
1040
  return found;
852
1041
  },
@@ -962,6 +1151,33 @@ var servedPageChecks = (context, page, result, origin) => {
962
1151
  }
963
1152
  return found;
964
1153
  };
1154
+ var liveRedirects = (context) => context.redirects.filter((redirect) => (redirect.outcome === "ok" || redirect.outcome === "chain") && !context.byUrl.has(normalizePath(redirect.from)));
1155
+ var liveRedirectCheck = (context, redirect, result, deployBase) => {
1156
+ const from = normalizePath(redirect.from);
1157
+ const site = {
1158
+ file: context.project.context.configFile ?? undefined,
1159
+ url: from
1160
+ };
1161
+ const landed = result.redirected && result.finalUrl ? normalizePath(stripBasePath(deployBase, decodePath(new URL(result.finalUrl).pathname))) : from;
1162
+ if (landed === from) {
1163
+ let answer = `could not be reached (${result.error ?? "no response"})`;
1164
+ if (result.timedOut) {
1165
+ answer = "did not respond in time";
1166
+ } else if (result.status !== undefined) {
1167
+ answer = `answered it with HTTP ${result.status} instead`;
1168
+ }
1169
+ const found = finding("BLUME_AUDIT_REDIRECT_NOT_SERVED", site, `${from} should redirect to ${redirect.to}, but the live site ${answer}.`);
1170
+ return result.ok ? { ...found, severity: "warning" } : found;
1171
+ }
1172
+ const destination = redirect.chain.at(-1) ?? from;
1173
+ if (/^https?:\/\//iu.test(destination) || landed === destination) {
1174
+ return null;
1175
+ }
1176
+ return {
1177
+ ...finding("BLUME_AUDIT_REDIRECT_NOT_SERVED", site, `${from} redirects to ${landed} on the live site, not to ${destination}.`),
1178
+ severity: "warning"
1179
+ };
1180
+ };
965
1181
  var networkChecks = {
966
1182
  category: "network",
967
1183
  async run(context) {
@@ -974,7 +1190,16 @@ var networkChecks = {
974
1190
  const targets = context.pages.map((page) => liveUrl(origin, page, deployBase));
975
1191
  const robotsUrl = new URL(`${deployBase}/robots.txt`, origin).toString();
976
1192
  const sitemapUrl = new URL(`${deployBase}/sitemap.xml`, origin).toString();
977
- const results = await probeAll([...targets, robotsUrl, sitemapUrl]);
1193
+ const redirects = liveRedirects(context).map((redirect) => [
1194
+ redirect,
1195
+ new URL(`${deployBase}${redirect.from}`, origin).toString()
1196
+ ]);
1197
+ const results = await probeAll([
1198
+ ...targets,
1199
+ robotsUrl,
1200
+ sitemapUrl,
1201
+ ...redirects.map(([, url]) => url)
1202
+ ]);
978
1203
  for (const page of context.pages) {
979
1204
  const result = results.get(liveUrl(origin, page, deployBase));
980
1205
  if (!result) {
@@ -987,6 +1212,13 @@ var networkChecks = {
987
1212
  }
988
1213
  found.push(...servedPageChecks(context, page, result, origin));
989
1214
  }
1215
+ for (const [redirect, url] of redirects) {
1216
+ const result = results.get(url);
1217
+ const wrong = liveRedirectCheck(context, redirect, result, deployBase);
1218
+ if (wrong) {
1219
+ found.push(wrong);
1220
+ }
1221
+ }
990
1222
  const robots = results.get(robotsUrl);
991
1223
  if (context.project.config.seo.robots && robots && !robots.ok) {
992
1224
  found.push(finding("BLUME_AUDIT_ROBOTS_NOT_ACCESSIBLE", { url: "/robots.txt" }, `robots.txt is not reachable at ${robotsUrl}.`));
@@ -1008,7 +1240,7 @@ var externalChecks = {
1008
1240
  for (const page of context.pages) {
1009
1241
  for (const link of page.links) {
1010
1242
  const resolved = resolveHref(page.url, link.href, origin, deployBase);
1011
- if (resolved.kind !== "external") {
1243
+ if (resolved.kind !== "external" || context.ignore(resolved.url)) {
1012
1244
  continue;
1013
1245
  }
1014
1246
  const pages = linkers.get(resolved.url);
@@ -1135,7 +1367,7 @@ var redirectChecks = {
1135
1367
  for (const redirect of context.redirects) {
1136
1368
  const from = normalizePath(redirect.from);
1137
1369
  if (context.byUrl.has(from)) {
1138
- found.push(finding("BLUME_AUDIT_REDIRECT_SOURCE_IS_PAGE", { ...site, url: from }, `A redirect is configured from ${from}, but ${from} is also a real page — the redirect never fires.`));
1370
+ found.push(finding("BLUME_AUDIT_REDIRECT_SOURCE_IS_PAGE", { ...site, url: from }, `A redirect is configured from ${from}, but ${from} is also a real page — readers get one or the other, depending on the host.`));
1139
1371
  continue;
1140
1372
  }
1141
1373
  if (redirect.outcome === "loop") {
@@ -1161,6 +1393,18 @@ var redirectChecks = {
1161
1393
  // src/audit/checks/robots.ts
1162
1394
  import robotsParser from "robots-parser";
1163
1395
  var MATCH_ORIGIN = "https://robots-audit.invalid";
1396
+ var USER_AGENT_LINE = /^\s*user-agent\s*:\s*(?<agent>[^#]*)/iu;
1397
+ var namedAgents = (raw) => {
1398
+ const agents = new Map;
1399
+ for (const line of raw.split(/\r?\n/u)) {
1400
+ const agent = USER_AGENT_LINE.exec(line)?.groups?.agent?.trim() ?? "";
1401
+ const key = agent.toLowerCase().split("/")[0]?.trim() ?? "";
1402
+ if (key && key !== "*" && !agents.has(key)) {
1403
+ agents.set(key, agent);
1404
+ }
1405
+ }
1406
+ return [...agents.values()];
1407
+ };
1164
1408
  var robotsChecks = {
1165
1409
  category: "robots",
1166
1410
  run(context) {
@@ -1180,6 +1424,12 @@ var robotsChecks = {
1180
1424
  }
1181
1425
  const parser = robotsParser(`${MATCH_ORIGIN}/robots.txt`, robots.raw);
1182
1426
  const lines = robots.raw.split(/\r?\n/u);
1427
+ const ruleAt = (url, agent) => {
1428
+ const line = parser.getMatchingLineNumber(url, agent);
1429
+ return { line, rule: line > 0 ? lines[line - 1]?.trim() : undefined };
1430
+ };
1431
+ const agents = namedAgents(robots.raw);
1432
+ const blockedFor = new Map;
1183
1433
  for (const loc of context.sitemap?.urls ?? []) {
1184
1434
  let pathname;
1185
1435
  try {
@@ -1190,11 +1440,29 @@ var robotsChecks = {
1190
1440
  const path = normalizePath(pathname);
1191
1441
  const url = `${MATCH_ORIGIN}${pathname}`;
1192
1442
  if (parser.isDisallowed(url, "*")) {
1193
- const line = parser.getMatchingLineNumber(url, "*");
1194
- const rule = line > 0 ? lines[line - 1]?.trim() : undefined;
1443
+ const { rule } = ruleAt(url, "*");
1195
1444
  found.push(finding("BLUME_AUDIT_ROBOTS_DISALLOWS_INDEXABLE", { file: robots.file, url: path }, `robots.txt "${rule ?? "Disallow"}" blocks ${path}, which sitemap.xml advertises.`));
1445
+ continue;
1446
+ }
1447
+ for (const agent of agents) {
1448
+ if (!parser.isDisallowed(url, agent)) {
1449
+ continue;
1450
+ }
1451
+ const blocked = blockedFor.get(agent);
1452
+ if (blocked) {
1453
+ blocked.push(url);
1454
+ } else {
1455
+ blockedFor.set(agent, [url]);
1456
+ }
1196
1457
  }
1197
1458
  }
1459
+ for (const [agent, urls] of blockedFor) {
1460
+ const [first = ""] = urls;
1461
+ const { line, rule } = ruleAt(first, agent);
1462
+ const path = normalizePath(new URL(first).pathname);
1463
+ const more = urls.length > 1 ? ` and ${urls.length - 1} more` : "";
1464
+ found.push(finding("BLUME_AUDIT_ROBOTS_BLOCKS_CRAWLER", { file: robots.file, line, url: "/robots.txt" }, `robots.txt "${rule ?? "Disallow"}" blocks ${agent} from ${path}${more}, which sitemap.xml advertises.`));
1465
+ }
1198
1466
  return found;
1199
1467
  },
1200
1468
  tier: "static"
@@ -1238,7 +1506,7 @@ var checkListedUrl = (context, loc, origin, file, deployBase) => {
1238
1506
  const path = normalizePath(stripBasePath(deployBase, decodePath(parsed.pathname)));
1239
1507
  const page = context.byUrl.get(path);
1240
1508
  if (!page) {
1241
- const redirect = context.redirects.find((entry) => normalizePath(entry.from) === path);
1509
+ const redirect = redirectAt(context.redirects, path);
1242
1510
  return [
1243
1511
  finding("BLUME_AUDIT_SITEMAP_BAD_URL", { file, url: loc }, redirect ? `sitemap.xml lists ${path}, which redirects to ${redirect.to}.` : `sitemap.xml lists ${path}, which the build does not serve.`)
1244
1512
  ];
@@ -1779,56 +2047,6 @@ var crawlStaticDir = async (options) => {
1779
2047
  };
1780
2048
  };
1781
2049
 
1782
- // src/audit/redirects.ts
1783
- var pathOnly = (value) => {
1784
- const cut = value.search(/[?#]/u);
1785
- return cut === -1 ? value : value.slice(0, cut);
1786
- };
1787
- var resolveRedirects = (redirects, served) => {
1788
- const byFrom = new Map;
1789
- for (const redirect of redirects) {
1790
- byFrom.set(normalizePath(redirect.from), redirect);
1791
- }
1792
- return redirects.map((redirect) => {
1793
- const from = normalizePath(redirect.from);
1794
- const chain = [from];
1795
- const seen = new Set([from]);
1796
- let current = redirect.to;
1797
- for (;; ) {
1798
- if (/^https?:\/\//iu.test(current)) {
1799
- chain.push(current);
1800
- break;
1801
- }
1802
- const next = normalizePath(pathOnly(current));
1803
- if (seen.has(next)) {
1804
- chain.push(next);
1805
- return {
1806
- ...redirect,
1807
- chain,
1808
- outcome: "loop"
1809
- };
1810
- }
1811
- chain.push(next);
1812
- seen.add(next);
1813
- const hop = byFrom.get(next);
1814
- if (!hop) {
1815
- break;
1816
- }
1817
- current = hop.to;
1818
- }
1819
- const destination = chain.at(-1) ?? from;
1820
- const external = /^https?:\/\//iu.test(destination);
1821
- if (!(external || served(destination))) {
1822
- return { ...redirect, chain, outcome: "broken" };
1823
- }
1824
- return {
1825
- ...redirect,
1826
- chain,
1827
- outcome: chain.length > 2 ? "chain" : "ok"
1828
- };
1829
- });
1830
- };
1831
-
1832
2050
  // src/audit/terms.ts
1833
2051
  var shortId = (id) => id.replace("BLUME_AUDIT_", "").toLowerCase();
1834
2052
  var checkTerms = () => [
@@ -1856,6 +2074,7 @@ var MODULES = [
1856
2074
  ogImageChecks,
1857
2075
  i18nChecks,
1858
2076
  assetChecks,
2077
+ contrastChecks,
1859
2078
  sitemapChecks,
1860
2079
  robotsChecks,
1861
2080
  llmsChecks,
@@ -1915,6 +2134,7 @@ var runAudit = async (options) => {
1915
2134
  byUrl,
1916
2135
  files: crawl.files,
1917
2136
  graph: buildGraph(crawl.pages, siteOrigin(project.config.deployment.options.site), normalizeBasePath(project.config.deployment.options.base)),
2137
+ ignore: options.ignore ?? (() => false),
1918
2138
  llms: crawl.llms,
1919
2139
  origin,
1920
2140
  pages: crawl.pages,
@@ -1996,6 +2216,11 @@ var auditCommand = defineCommand({
1996
2216
  description: "Exit non-zero at this severity or above: error | warning | info. Defaults to error.",
1997
2217
  type: "string"
1998
2218
  },
2219
+ ignore: {
2220
+ description: 'With --external, skip outbound links whose URL matches this glob (e.g. "https://example.com/**"). Repeat it for more; internal links are always checked.',
2221
+ type: "string",
2222
+ valueHint: "glob"
2223
+ },
1999
2224
  json: {
2000
2225
  description: "Emit the report as JSON on stdout (for CI/editors).",
2001
2226
  type: "boolean"
@@ -2026,7 +2251,7 @@ var auditCommand = defineCommand({
2026
2251
  }
2027
2252
  },
2028
2253
  meta: commandMeta.audit,
2029
- async run({ args }) {
2254
+ async run({ args, rawArgs }) {
2030
2255
  if (args["list-checks"]) {
2031
2256
  process.stdout.write(formatCatalog());
2032
2257
  return;
@@ -2055,11 +2280,13 @@ var auditCommand = defineCommand({
2055
2280
  const only = splitTerms(args.only);
2056
2281
  const skip = splitTerms(args.skip);
2057
2282
  rejectUnknownTerms([...only, ...skip]);
2283
+ const ignore = parseIgnoreFlag(rawArgs);
2058
2284
  let result;
2059
2285
  try {
2060
2286
  const project = await scanProject(root, { mode: "build" });
2061
2287
  result = await runAudit({
2062
2288
  external: args.external,
2289
+ ignore,
2063
2290
  only,
2064
2291
  origin: args.url,
2065
2292
  project,
@@ -2113,5 +2340,5 @@ export {
2113
2340
  shouldFail
2114
2341
  };
2115
2342
 
2116
- //# debugId=E1B16241D184BD6E64756E2164756E21
2117
- //# sourceMappingURL=chunk-wrr3j9w9.js.map
2343
+ //# debugId=E0347EF127A1E50964756E2164756E21
2344
+ //# sourceMappingURL=chunk-e6atmn4h.js.map