blume 1.7.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (673) hide show
  1. package/AGENTS.md +19 -0
  2. package/CHANGELOG.md +217 -0
  3. package/README.md +34 -21
  4. package/dist/cli/chunk-11j0384y.js +148 -0
  5. package/dist/cli/chunk-11j0384y.js.map +10 -0
  6. package/dist/cli/{chunk-rqy0s5wh.js → chunk-1w8dp3qb.js} +17 -16
  7. package/dist/cli/{chunk-rqy0s5wh.js.map → chunk-1w8dp3qb.js.map} +3 -3
  8. package/dist/cli/chunk-2q1dwty4.js +75 -0
  9. package/dist/cli/chunk-2q1dwty4.js.map +11 -0
  10. package/dist/cli/chunk-41za066z.js +122 -0
  11. package/dist/cli/chunk-41za066z.js.map +11 -0
  12. package/dist/cli/chunk-5a2z0198.js +133 -0
  13. package/dist/cli/chunk-5a2z0198.js.map +10 -0
  14. package/dist/cli/{chunk-5g0w1e2c.js → chunk-6k8vp3ta.js} +25 -13
  15. package/dist/cli/{chunk-5g0w1e2c.js.map → chunk-6k8vp3ta.js.map} +4 -4
  16. package/dist/cli/{chunk-5qk08vmp.js → chunk-79njf86q.js} +133 -54
  17. package/dist/cli/chunk-79njf86q.js.map +11 -0
  18. package/dist/cli/{chunk-e7f42gdj.js → chunk-7ez8ny0t.js} +2 -2
  19. package/dist/cli/{chunk-nn13znc2.js → chunk-88cpgt6h.js} +1 -1
  20. package/dist/cli/chunk-a9kptbw5.js +361 -0
  21. package/dist/cli/chunk-a9kptbw5.js.map +14 -0
  22. package/dist/cli/chunk-abh8yjkn.js +31 -0
  23. package/dist/cli/chunk-abh8yjkn.js.map +10 -0
  24. package/dist/cli/chunk-b5aj94ah.js +91 -0
  25. package/dist/cli/chunk-b5aj94ah.js.map +10 -0
  26. package/dist/cli/{chunk-b27xqwn9.js → chunk-bctazmbk.js} +9 -5
  27. package/dist/cli/chunk-bctazmbk.js.map +10 -0
  28. package/dist/cli/chunk-beat36xx.js +279 -0
  29. package/dist/cli/chunk-beat36xx.js.map +10 -0
  30. package/dist/cli/chunk-bnbmcwfb.js +145 -0
  31. package/dist/cli/chunk-bnbmcwfb.js.map +11 -0
  32. package/dist/cli/{chunk-0xjyb285.js → chunk-bw22s759.js} +15 -5
  33. package/dist/cli/{chunk-0xjyb285.js.map → chunk-bw22s759.js.map} +4 -4
  34. package/dist/cli/chunk-by2290sx.js +39 -0
  35. package/dist/cli/chunk-by2290sx.js.map +10 -0
  36. package/dist/cli/chunk-d1tadaw7.js +79 -0
  37. package/dist/cli/chunk-d1tadaw7.js.map +10 -0
  38. package/dist/cli/{chunk-ahnw3kxw.js → chunk-d80hr03s.js} +24 -19
  39. package/dist/cli/chunk-d80hr03s.js.map +15 -0
  40. package/dist/cli/chunk-ernrthtr.js +97 -0
  41. package/dist/cli/chunk-ernrthtr.js.map +10 -0
  42. package/dist/cli/chunk-f2972sbt.js +374 -0
  43. package/dist/cli/chunk-f2972sbt.js.map +10 -0
  44. package/dist/cli/{chunk-vacwm2hv.js → chunk-f7t03s3g.js} +2 -2
  45. package/dist/cli/{chunk-2z47ypj8.js → chunk-fa25z98p.js} +16 -3
  46. package/dist/cli/chunk-fa25z98p.js.map +11 -0
  47. package/dist/cli/{chunk-cjtn640a.js → chunk-fh5hj5jt.js} +43 -20
  48. package/dist/cli/chunk-fh5hj5jt.js.map +10 -0
  49. package/dist/cli/{chunk-yg63d42r.js → chunk-j8mw0za6.js} +86 -57
  50. package/dist/cli/chunk-j8mw0za6.js.map +35 -0
  51. package/dist/cli/{chunk-ct47dqpx.js → chunk-jts8mvcz.js} +67 -7
  52. package/dist/cli/{chunk-2mzebbbz.js.map → chunk-jts8mvcz.js.map} +6 -4
  53. package/dist/cli/{chunk-ps4m1xh4.js → chunk-mnqj32sj.js} +505 -542
  54. package/dist/cli/chunk-mnqj32sj.js.map +12 -0
  55. package/dist/cli/{chunk-8cjtbafj.js → chunk-mwt1k8n7.js} +100 -374
  56. package/dist/cli/chunk-mwt1k8n7.js.map +10 -0
  57. package/dist/cli/chunk-nk3ts2xk.js +51 -0
  58. package/dist/cli/chunk-nk3ts2xk.js.map +10 -0
  59. package/dist/cli/{chunk-3r45185y.js → chunk-pat2zzwc.js} +9 -11
  60. package/dist/cli/{chunk-3r45185y.js.map → chunk-pat2zzwc.js.map} +2 -2
  61. package/dist/cli/chunk-pnnvybbk.js +176 -0
  62. package/dist/cli/chunk-pnnvybbk.js.map +11 -0
  63. package/dist/cli/{chunk-4x36ddpw.js → chunk-sqn5t4q0.js} +81 -87
  64. package/dist/cli/chunk-sqn5t4q0.js.map +10 -0
  65. package/dist/cli/{chunk-bvwwhd84.js → chunk-tzne8qfq.js} +15 -15
  66. package/dist/cli/{chunk-bvwwhd84.js.map → chunk-tzne8qfq.js.map} +1 -1
  67. package/dist/cli/chunk-xaz13gwg.js +12449 -0
  68. package/dist/cli/chunk-xaz13gwg.js.map +182 -0
  69. package/dist/cli/chunk-y3e45rc8.js +102 -0
  70. package/dist/cli/chunk-y3e45rc8.js.map +10 -0
  71. package/dist/cli/chunk-z01ze5c1.js +261 -0
  72. package/dist/cli/chunk-z01ze5c1.js.map +10 -0
  73. package/dist/cli/{chunk-k79xp7av.js → chunk-z1f5arsg.js} +219 -689
  74. package/dist/cli/chunk-z1f5arsg.js.map +36 -0
  75. package/dist/cli/{chunk-1jefwnfs.js → chunk-zg2gtj10.js} +1076 -2592
  76. package/dist/cli/chunk-zg2gtj10.js.map +35 -0
  77. package/dist/cli/{chunk-dwgcp5sm.js → chunk-zxccj738.js} +1 -1
  78. package/dist/cli/index.js +214 -57
  79. package/dist/cli/index.js.map +8 -7
  80. package/dist/types/ai/agent-readability.d.ts +52 -0
  81. package/dist/types/ai/ai-catalog.d.ts +42 -0
  82. package/dist/types/ai/api/paths.d.ts +17 -0
  83. package/dist/types/ai/api-catalog.d.ts +18 -0
  84. package/dist/types/ai/ask.d.ts +368 -0
  85. package/dist/types/ai/changelog-markdown.d.ts +2 -0
  86. package/dist/types/ai/component-markdown.d.ts +2 -2
  87. package/dist/types/ai/index.d.ts +24 -0
  88. package/dist/types/ai/link-headers.d.ts +24 -0
  89. package/dist/types/ai/llms.d.ts +25 -0
  90. package/dist/types/ai/markdown.d.ts +45 -0
  91. package/dist/types/ai/mcp/discovery.d.ts +68 -0
  92. package/dist/types/ai/mcp/tools.d.ts +16 -0
  93. package/dist/types/ai/openapi-components.d.ts +43 -0
  94. package/dist/types/ai/relative-links.d.ts +26 -0
  95. package/dist/types/ai/serializers.d.ts +15 -0
  96. package/dist/types/ai/skills.d.ts +42 -0
  97. package/dist/types/ai/tar.d.ts +25 -0
  98. package/dist/types/ai/visibility.d.ts +17 -0
  99. package/dist/types/ai/web-bot-auth.d.ts +16 -0
  100. package/dist/types/analytics/adobe.d.ts +35 -0
  101. package/dist/types/analytics/amplitude.d.ts +50 -0
  102. package/dist/types/analytics/clarity.d.ts +31 -0
  103. package/dist/types/analytics/clearbit.d.ts +29 -0
  104. package/dist/types/analytics/cloudflare.d.ts +41 -0
  105. package/dist/types/analytics/fathom.d.ts +41 -0
  106. package/dist/types/analytics/google-analytics.d.ts +44 -0
  107. package/dist/types/analytics/google-tag-manager.d.ts +40 -0
  108. package/dist/types/analytics/head.d.ts +30 -0
  109. package/dist/types/analytics/heap.d.ts +40 -0
  110. package/dist/types/analytics/hightouch.d.ts +44 -0
  111. package/dist/types/analytics/hotjar.d.ts +33 -0
  112. package/dist/types/analytics/index.d.ts +61 -0
  113. package/dist/types/analytics/inline.d.ts +17 -0
  114. package/dist/types/analytics/logrocket.d.ts +44 -0
  115. package/dist/types/analytics/mixpanel.d.ts +67 -0
  116. package/dist/types/analytics/pirsch.d.ts +42 -0
  117. package/dist/types/analytics/plausible.d.ts +56 -0
  118. package/dist/types/analytics/posthog.d.ts +45 -0
  119. package/dist/types/analytics/schema.d.ts +320 -0
  120. package/dist/types/analytics/script.d.ts +46 -0
  121. package/dist/types/analytics/segment.d.ts +50 -0
  122. package/dist/types/analytics/vercel.d.ts +48 -0
  123. package/dist/types/astro/integration.d.ts +76 -0
  124. package/dist/types/astro/markdown-negotiation.d.ts +23 -0
  125. package/dist/types/astro/module-types.d.ts +14 -0
  126. package/dist/types/astro/pages.d.ts +44 -0
  127. package/dist/types/cli/env.d.ts +12 -0
  128. package/dist/types/cli/init/scaffold.d.ts +154 -0
  129. package/dist/types/components/layout/nav-utils.d.ts +11 -0
  130. package/dist/types/core/adapter.d.ts +47 -0
  131. package/dist/types/core/api-name.d.ts +7 -0
  132. package/dist/types/core/changelog-index.d.ts +13 -0
  133. package/dist/types/core/config-input.d.ts +186 -515
  134. package/dist/types/core/config.d.ts +60 -34
  135. package/dist/types/core/content-assets.d.ts +76 -0
  136. package/dist/types/core/custom-pages.d.ts +33 -0
  137. package/dist/types/core/data.d.ts +27 -12
  138. package/dist/types/core/define-components.d.ts +12 -9
  139. package/dist/types/core/deployment-env.d.ts +6 -11
  140. package/dist/types/core/frontmatter.d.ts +10 -0
  141. package/dist/types/core/graph.d.ts +18 -0
  142. package/dist/types/core/heading-markers.d.ts +54 -0
  143. package/dist/types/core/i18n-ui.d.ts +6 -2
  144. package/dist/types/core/i18n.d.ts +87 -0
  145. package/dist/types/core/includes.d.ts +138 -0
  146. package/dist/types/core/last-modified.d.ts +47 -0
  147. package/dist/types/core/links.d.ts +95 -0
  148. package/dist/types/core/locale-links.d.ts +60 -0
  149. package/dist/types/core/manifest.d.ts +17 -0
  150. package/dist/types/core/meta.d.ts +38 -0
  151. package/dist/types/core/nav-diagnostics.d.ts +26 -0
  152. package/dist/types/core/navigation.d.ts +6 -0
  153. package/dist/types/core/node-require.d.ts +19 -0
  154. package/dist/types/core/package-json.d.ts +13 -0
  155. package/dist/types/core/probe.d.ts +42 -0
  156. package/dist/types/core/project-graph.d.ts +51 -0
  157. package/dist/types/core/project.d.ts +2 -0
  158. package/dist/types/core/safe-href.d.ts +2 -0
  159. package/dist/types/core/safe-links.d.ts +26 -0
  160. package/dist/types/core/schema.d.ts +2282 -452
  161. package/dist/types/core/site-url.d.ts +16 -0
  162. package/dist/types/core/sources/assets.d.ts +36 -0
  163. package/dist/types/core/sources/cache.d.ts +37 -0
  164. package/dist/types/core/sources/collection.d.ts +28 -0
  165. package/dist/types/core/sources/contentful-rich-text.d.ts +31 -0
  166. package/dist/types/core/sources/contentful.d.ts +40 -0
  167. package/dist/types/core/sources/filesystem.d.ts +24 -0
  168. package/dist/types/core/sources/github-releases.d.ts +31 -0
  169. package/dist/types/core/sources/json.d.ts +30 -0
  170. package/dist/types/core/sources/lexical.d.ts +19 -0
  171. package/dist/types/core/sources/lower.d.ts +75 -0
  172. package/dist/types/core/sources/mdx-remote.d.ts +28 -0
  173. package/dist/types/core/sources/normalize.d.ts +147 -0
  174. package/dist/types/core/sources/notion.d.ts +131 -0
  175. package/dist/types/core/sources/obsidian.d.ts +46 -0
  176. package/dist/types/core/sources/payload.d.ts +39 -0
  177. package/dist/types/core/sources/portable-text.d.ts +42 -0
  178. package/dist/types/core/sources/read.d.ts +23 -0
  179. package/dist/types/core/sources/remote.d.ts +74 -0
  180. package/dist/types/core/sources/resolve.d.ts +19 -0
  181. package/dist/types/core/sources/sanity.d.ts +43 -0
  182. package/dist/types/core/sources/strapi-blocks.d.ts +12 -0
  183. package/dist/types/core/sources/strapi.d.ts +33 -0
  184. package/dist/types/core/sources/types.d.ts +7 -0
  185. package/dist/types/core/sources/watch.d.ts +45 -0
  186. package/dist/types/core/text-width.d.ts +11 -0
  187. package/dist/types/core/types.d.ts +15 -1
  188. package/dist/types/core/unrecognized-keys.d.ts +7 -0
  189. package/dist/types/core/versions.d.ts +72 -0
  190. package/dist/types/core/yaml.d.ts +9 -0
  191. package/dist/types/deploy/adapter-output.d.ts +45 -0
  192. package/dist/types/deploy/adapters/cloudflare.d.ts +40 -0
  193. package/dist/types/deploy/adapters/index.d.ts +29 -0
  194. package/dist/types/deploy/adapters/netlify.d.ts +37 -0
  195. package/dist/types/deploy/adapters/node.d.ts +37 -0
  196. package/dist/types/deploy/adapters/registry.d.ts +133 -0
  197. package/dist/types/deploy/adapters/types.d.ts +71 -0
  198. package/dist/types/deploy/adapters/vercel.d.ts +38 -0
  199. package/dist/types/deploy/artifacts.d.ts +65 -0
  200. package/dist/types/deploy/cloudflare-negotiation.d.ts +196 -0
  201. package/dist/types/deploy/function-bundle.d.ts +80 -0
  202. package/dist/types/deploy/headers.d.ts +50 -0
  203. package/dist/types/deploy/node-headers.d.ts +42 -0
  204. package/dist/types/deploy/platforms/cloudflare.d.ts +40 -0
  205. package/dist/types/deploy/platforms/index.d.ts +18 -0
  206. package/dist/types/deploy/platforms/netlify.d.ts +13 -0
  207. package/dist/types/deploy/platforms/node.d.ts +11 -0
  208. package/dist/types/deploy/platforms/paths.d.ts +27 -0
  209. package/dist/types/deploy/platforms/static.d.ts +10 -0
  210. package/dist/types/deploy/platforms/types.d.ts +104 -0
  211. package/dist/types/deploy/platforms/vercel.d.ts +32 -0
  212. package/dist/types/deploy/redirects.d.ts +53 -0
  213. package/dist/types/deploy/robots.d.ts +8 -0
  214. package/dist/types/deploy/rss.d.ts +31 -0
  215. package/dist/types/deploy/sitemap.d.ts +21 -0
  216. package/dist/types/deploy/vercel-negotiation.d.ts +109 -0
  217. package/dist/types/markdown/code-title.d.ts +32 -0
  218. package/dist/types/markdown/fence-meta.d.ts +23 -0
  219. package/dist/types/markdown/themes.d.ts +3 -3
  220. package/dist/types/openapi/asyncapi.d.ts +129 -0
  221. package/dist/types/openapi/graphql-build.d.ts +8 -0
  222. package/dist/types/openapi/graphql.d.ts +122 -0
  223. package/dist/types/openapi/model.d.ts +158 -0
  224. package/dist/types/openapi/parse.d.ts +57 -0
  225. package/dist/types/openapi/references.d.ts +37 -25
  226. package/dist/types/openapi/render-mdx.d.ts +33 -0
  227. package/dist/types/openapi/sentence.d.ts +7 -0
  228. package/dist/types/openapi/signature.d.ts +10 -0
  229. package/dist/types/openapi/source.d.ts +22 -0
  230. package/dist/types/openapi/spec-dependency-error.d.ts +10 -0
  231. package/dist/types/reference/asyncapi.d.ts +166 -0
  232. package/dist/types/reference/graphql.d.ts +181 -0
  233. package/dist/types/reference/index.d.ts +32 -0
  234. package/dist/types/reference/openapi.d.ts +165 -0
  235. package/dist/types/reference/options.d.ts +157 -0
  236. package/dist/types/reference/scalar.d.ts +136 -0
  237. package/dist/types/reference/schema.d.ts +630 -0
  238. package/dist/types/search/adapters/algolia.d.ts +32 -0
  239. package/dist/types/search/adapters/flexsearch.d.ts +12 -0
  240. package/dist/types/search/adapters/index.d.ts +31 -0
  241. package/dist/types/search/adapters/mixedbread.d.ts +22 -0
  242. package/dist/types/search/adapters/orama-cloud.d.ts +33 -0
  243. package/dist/types/search/adapters/orama.d.ts +13 -0
  244. package/dist/types/search/adapters/pagefind.d.ts +12 -0
  245. package/dist/types/search/adapters/registry.d.ts +228 -0
  246. package/dist/types/search/adapters/types.d.ts +34 -0
  247. package/dist/types/search/adapters/typesense.d.ts +42 -0
  248. package/dist/types/search/build.d.ts +23 -0
  249. package/dist/types/search/documents.d.ts +90 -0
  250. package/dist/types/search/facets.d.ts +3 -0
  251. package/dist/types/search/sync/algolia.d.ts +14 -0
  252. package/dist/types/search/sync/index.d.ts +14 -0
  253. package/dist/types/search/sync/orama-cloud.d.ts +10 -0
  254. package/dist/types/search/sync/typesense.d.ts +14 -0
  255. package/dist/types/sources/contentful.d.ts +68 -0
  256. package/dist/types/sources/custom.d.ts +20 -0
  257. package/dist/types/sources/filesystem.d.ts +42 -0
  258. package/dist/types/sources/github-releases.d.ts +46 -0
  259. package/dist/types/sources/index.d.ts +48 -0
  260. package/dist/types/sources/mdx-remote.d.ts +63 -0
  261. package/dist/types/sources/notion.d.ts +65 -0
  262. package/dist/types/sources/obsidian.d.ts +34 -0
  263. package/dist/types/sources/payload.d.ts +68 -0
  264. package/dist/types/sources/registry.d.ts +1414 -0
  265. package/dist/types/sources/sanity.d.ts +69 -0
  266. package/dist/types/sources/shared.d.ts +46 -0
  267. package/dist/types/sources/strapi.d.ts +66 -0
  268. package/dist/types/theme/icon-kind.d.ts +11 -0
  269. package/dist/types/theme/icons.d.ts +20 -0
  270. package/docs/01-quickstart.mdx +18 -18
  271. package/docs/02-deployment.mdx +50 -26
  272. package/docs/03-upgrading.mdx +351 -0
  273. package/docs/04-migrating.mdx +58 -0
  274. package/docs/08-faq.mdx +3 -3
  275. package/docs/advanced/blog.mdx +13 -6
  276. package/docs/advanced/changelog.mdx +23 -35
  277. package/docs/advanced/custom-pages.mdx +20 -8
  278. package/docs/advanced/meta.ts +1 -8
  279. package/docs/advanced/skills.mdx +8 -0
  280. package/docs/cli/audit.mdx +646 -0
  281. package/docs/cli/doctor.mdx +29 -0
  282. package/docs/{reference/eval.mdx → cli/evals.mdx} +9 -8
  283. package/docs/cli/index.mdx +105 -0
  284. package/docs/cli/meta.ts +7 -0
  285. package/docs/{reference → cli}/translate.mdx +1 -1
  286. package/docs/cli/validate.mdx +41 -0
  287. package/docs/cli/version.mdx +40 -0
  288. package/docs/configuration/analytics.mdx +350 -59
  289. package/docs/configuration/ask-ai.mdx +162 -61
  290. package/docs/configuration/customization.mdx +15 -9
  291. package/docs/configuration/index.mdx +50 -31
  292. package/docs/configuration/search.mdx +75 -54
  293. package/docs/configuration/theming.mdx +24 -15
  294. package/docs/content/components.mdx +21 -5
  295. package/docs/{reference → content}/frontmatter.mdx +35 -1
  296. package/docs/content/i18n.mdx +8 -6
  297. package/docs/content/includes.mdx +2 -4
  298. package/docs/content/index.mdx +1 -1
  299. package/docs/content/islands.mdx +10 -5
  300. package/docs/content/meta.mdx +1 -1
  301. package/docs/content/meta.ts +1 -0
  302. package/docs/content/navigation.mdx +9 -7
  303. package/docs/content/sources.mdx +145 -50
  304. package/docs/content/syntax.mdx +16 -12
  305. package/docs/content/versioning.mdx +3 -3
  306. package/docs/discoverability/agent-discovery.mdx +11 -11
  307. package/docs/discoverability/index.mdx +4 -4
  308. package/docs/discoverability/json-api.mdx +4 -4
  309. package/docs/discoverability/llms-txt.mdx +6 -6
  310. package/docs/discoverability/markdown.mdx +4 -4
  311. package/docs/discoverability/mcp.mdx +11 -11
  312. package/docs/discoverability/sitemap-and-robots.mdx +3 -3
  313. package/docs/index.mdx +2 -2
  314. package/docs/references/asyncapi.mdx +59 -0
  315. package/docs/{advanced → references}/graphql.mdx +45 -32
  316. package/docs/{reference → references}/meta.ts +2 -2
  317. package/docs/references/openapi.mdx +171 -0
  318. package/docs/references/scalar.mdx +64 -0
  319. package/package.json +42 -8
  320. package/skills/blume/SKILL.md +21 -8
  321. package/skills/blume-migrate/SKILL.md +22 -21
  322. package/skills/blume-migrate/assets/oxfmt@0.67.0.patch +49 -0
  323. package/skills/blume-migrate/references/docusaurus.md +5 -4
  324. package/skills/blume-migrate/references/fumadocs.md +4 -4
  325. package/skills/blume-migrate/references/mintlify.md +23 -8
  326. package/skills/blume-migrate/references/monorepo.md +6 -6
  327. package/skills/blume-migrate/references/starlight.md +4 -4
  328. package/src/ai/agent-readability.ts +21 -22
  329. package/src/ai/ai-catalog.ts +50 -32
  330. package/src/ai/api/handlers.ts +46 -11
  331. package/src/ai/api-catalog.ts +8 -8
  332. package/src/ai/ask-data.ts +1 -1
  333. package/src/ai/ask.ts +624 -100
  334. package/src/ai/changelog-markdown.ts +91 -0
  335. package/src/ai/component-markdown.ts +328 -12
  336. package/src/ai/index.ts +45 -0
  337. package/src/ai/link-headers.ts +7 -6
  338. package/src/ai/llms.ts +20 -15
  339. package/src/ai/markdown.ts +35 -5
  340. package/src/ai/mcp/data.ts +9 -5
  341. package/src/ai/openapi-components.ts +4 -1
  342. package/src/ai/relative-links.ts +170 -0
  343. package/src/ai/serializers.ts +2 -2
  344. package/src/ai/skills.ts +1 -1
  345. package/src/ai/web-bot-auth.ts +2 -2
  346. package/src/analytics/adobe.ts +46 -0
  347. package/src/analytics/amplitude.ts +79 -0
  348. package/src/analytics/clarity.ts +46 -0
  349. package/src/analytics/clearbit.ts +47 -0
  350. package/src/analytics/cloudflare.ts +67 -0
  351. package/src/analytics/fathom.ts +64 -0
  352. package/src/analytics/google-analytics.ts +84 -0
  353. package/src/analytics/google-tag-manager.ts +61 -0
  354. package/src/analytics/head.ts +130 -0
  355. package/src/analytics/heap.ts +65 -0
  356. package/src/analytics/hightouch.ts +77 -0
  357. package/src/analytics/hotjar.ts +47 -0
  358. package/src/analytics/index.ts +71 -0
  359. package/src/analytics/inline.ts +21 -0
  360. package/src/analytics/logrocket.ts +71 -0
  361. package/src/analytics/mixpanel.ts +92 -0
  362. package/src/analytics/pirsch.ts +66 -0
  363. package/src/analytics/plausible.ts +83 -0
  364. package/src/analytics/posthog.ts +78 -0
  365. package/src/analytics/schema.ts +60 -0
  366. package/src/analytics/script.ts +60 -0
  367. package/src/analytics/segment.ts +85 -0
  368. package/src/analytics/vercel.ts +50 -0
  369. package/src/astro/adapter-root.ts +7 -9
  370. package/src/astro/component-slots.ts +131 -91
  371. package/src/astro/generate.ts +112 -345
  372. package/src/astro/integration.ts +2 -6
  373. package/src/astro/pages.ts +13 -101
  374. package/src/astro/render-deps.ts +379 -0
  375. package/src/astro/runtime-deps.ts +201 -0
  376. package/src/astro/templates.ts +554 -541
  377. package/src/audit/agent.ts +24 -0
  378. package/src/audit/catalog.ts +2 -2
  379. package/src/audit/checks/assets.ts +2 -2
  380. package/src/audit/checks/dns-aid.ts +1 -1
  381. package/src/audit/checks/duplicates.ts +3 -1
  382. package/src/audit/checks/i18n.ts +1 -1
  383. package/src/audit/checks/indexability.ts +7 -7
  384. package/src/audit/checks/links.ts +2 -2
  385. package/src/audit/checks/llms.ts +6 -6
  386. package/src/audit/checks/network.ts +3 -3
  387. package/src/audit/checks/og-image.ts +2 -2
  388. package/src/audit/checks/robots.ts +1 -1
  389. package/src/audit/checks/sitemap.ts +2 -2
  390. package/src/audit/checks/social.ts +1 -1
  391. package/src/audit/run.ts +4 -3
  392. package/src/audit/terms.ts +31 -0
  393. package/src/audit/url.ts +13 -13
  394. package/src/cli/command-meta.ts +10 -0
  395. package/src/cli/commands/audit.ts +39 -20
  396. package/src/cli/commands/build.ts +71 -316
  397. package/src/cli/commands/check.ts +1 -0
  398. package/src/cli/commands/dev.ts +40 -1
  399. package/src/cli/commands/doctor.ts +90 -14
  400. package/src/cli/commands/eject.ts +44 -7
  401. package/src/cli/commands/eval.ts +2 -2
  402. package/src/cli/commands/init.ts +161 -41
  403. package/src/cli/commands/migrate.ts +121 -0
  404. package/src/cli/commands/preview.ts +7 -1
  405. package/src/cli/commands/translate.ts +2 -2
  406. package/src/cli/commands/upgrade.ts +141 -0
  407. package/src/cli/commands/version.ts +57 -44
  408. package/src/cli/eject-scripts.ts +121 -6
  409. package/src/cli/index.ts +11 -1
  410. package/src/cli/init/install.ts +70 -0
  411. package/src/cli/init/questions.ts +7 -0
  412. package/src/cli/init/scaffold.ts +459 -75
  413. package/src/cli/lazy-command.ts +37 -1
  414. package/src/cli/prepare.ts +40 -6
  415. package/src/cli/required-secrets.ts +38 -11
  416. package/src/cli/unknown-flags.ts +266 -0
  417. package/src/cli/yarn-pnp.ts +52 -0
  418. package/src/components/content/AccordionItem.astro +7 -1
  419. package/src/components/content/Card.astro +4 -3
  420. package/src/components/content/ColorItem.astro +22 -4
  421. package/src/components/content/GithubInfo.astro +2 -2
  422. package/src/components/content/Prompt.astro +25 -25
  423. package/src/components/content/Tabs.astro +3 -1
  424. package/src/components/content/Tile.astro +2 -3
  425. package/src/components/content/Tooltip.astro +57 -9
  426. package/src/components/content/content-strings.ts +34 -0
  427. package/src/components/content/diff.ts +1 -1
  428. package/src/components/content/mermaid-element.ts +13 -2
  429. package/src/components/content/prompt-markdown.ts +292 -0
  430. package/src/components/content/tooltip-id.ts +41 -0
  431. package/src/components/islands/hooks.ts +25 -2
  432. package/src/components/layout/Analytics.astro +21 -79
  433. package/src/components/layout/Banner.astro +3 -1
  434. package/src/components/layout/DiscoveryLinks.astro +69 -0
  435. package/src/components/layout/Header.astro +83 -20
  436. package/src/components/layout/LanguageSwitcher.astro +4 -1
  437. package/src/components/layout/Logo.astro +23 -2
  438. package/src/components/layout/NavSelector.astro +13 -2
  439. package/src/components/layout/NavTree.astro +12 -3
  440. package/src/components/layout/NavTreeScript.astro +17 -3
  441. package/src/components/layout/PageActions.astro +3 -3
  442. package/src/components/layout/PageFeedback.astro +11 -1
  443. package/src/components/layout/PageLayout.astro +52 -5
  444. package/src/components/layout/ReferenceLayout.astro +21 -12
  445. package/src/components/layout/RootLayout.astro +69 -66
  446. package/src/components/layout/Search.astro +30 -6
  447. package/src/components/layout/WebMcp.astro +1 -1
  448. package/src/components/layout/analytics-client.ts +72 -15
  449. package/src/components/layout/drawer-inert.ts +113 -15
  450. package/src/components/layout/dropdown-clamp.ts +105 -0
  451. package/src/components/layout/head-scripts.ts +15 -6
  452. package/src/components/layout/nav-utils.ts +17 -0
  453. package/src/components/layout/search/algolia.ts +8 -8
  454. package/src/components/layout/search/orama-cloud.ts +9 -7
  455. package/src/components/layout/search/typesense.ts +11 -17
  456. package/src/components/openapi/MessageComposer.astro +2 -2
  457. package/src/components/openapi/Playground.astro +2 -2
  458. package/src/components/openapi/playground-client.ts +79 -10
  459. package/src/core/changelog-index.ts +24 -0
  460. package/src/core/component-overrides.ts +399 -154
  461. package/src/core/config-input.ts +188 -553
  462. package/src/core/config.ts +130 -41
  463. package/src/core/custom-pages.ts +105 -0
  464. package/src/core/data.ts +31 -12
  465. package/src/core/define-components.ts +12 -9
  466. package/src/core/deployment-env.ts +18 -74
  467. package/src/core/diagnostics.ts +14 -7
  468. package/src/core/graph.ts +69 -25
  469. package/src/core/i18n-ui.ts +6 -2
  470. package/src/core/i18n.ts +17 -0
  471. package/src/core/includes.ts +156 -38
  472. package/src/core/last-modified.ts +6 -11
  473. package/src/core/links.ts +166 -2
  474. package/src/core/manifest.ts +10 -3
  475. package/src/core/navigation.ts +115 -16
  476. package/src/core/new-tab.ts +35 -0
  477. package/src/core/node-require.ts +21 -0
  478. package/src/core/project-graph.ts +42 -26
  479. package/src/core/project.ts +9 -4
  480. package/src/core/request-body.ts +61 -0
  481. package/src/core/safe-href.ts +28 -0
  482. package/src/core/safe-links.ts +68 -0
  483. package/src/core/schema.ts +517 -739
  484. package/src/core/server-features.ts +8 -9
  485. package/src/core/sources/assets.ts +47 -11
  486. package/src/core/sources/collection.ts +67 -0
  487. package/src/core/sources/contentful-rich-text.ts +285 -0
  488. package/src/core/sources/contentful.ts +173 -0
  489. package/src/core/sources/github-releases.ts +51 -1
  490. package/src/core/sources/json.ts +71 -0
  491. package/src/core/sources/lexical.ts +195 -0
  492. package/src/core/sources/lower.ts +226 -0
  493. package/src/core/sources/normalize.ts +52 -2
  494. package/src/core/sources/notion.ts +39 -28
  495. package/src/core/sources/payload.ts +135 -0
  496. package/src/core/sources/portable-text.ts +11 -16
  497. package/src/core/sources/remote.ts +226 -0
  498. package/src/core/sources/resolve.ts +104 -166
  499. package/src/core/sources/sanity.ts +16 -49
  500. package/src/core/sources/strapi-blocks.ts +124 -0
  501. package/src/core/sources/strapi.ts +191 -0
  502. package/src/core/sources/types.ts +12 -1
  503. package/src/core/types.ts +15 -1
  504. package/src/core/ui-packs/ar.ts +6 -2
  505. package/src/core/ui-packs/bg.ts +6 -2
  506. package/src/core/ui-packs/bn.ts +6 -2
  507. package/src/core/ui-packs/ca.ts +3 -1
  508. package/src/core/ui-packs/cs.ts +6 -2
  509. package/src/core/ui-packs/da.ts +6 -2
  510. package/src/core/ui-packs/de.ts +6 -2
  511. package/src/core/ui-packs/el.ts +3 -1
  512. package/src/core/ui-packs/es.ts +3 -1
  513. package/src/core/ui-packs/fa.ts +6 -2
  514. package/src/core/ui-packs/fi.ts +6 -2
  515. package/src/core/ui-packs/fr.ts +3 -1
  516. package/src/core/ui-packs/he.ts +6 -2
  517. package/src/core/ui-packs/hi.ts +6 -2
  518. package/src/core/ui-packs/hr.ts +6 -2
  519. package/src/core/ui-packs/hu.ts +6 -2
  520. package/src/core/ui-packs/id.ts +6 -2
  521. package/src/core/ui-packs/it.ts +3 -1
  522. package/src/core/ui-packs/ja.ts +3 -1
  523. package/src/core/ui-packs/ko.ts +3 -1
  524. package/src/core/ui-packs/nl.ts +6 -2
  525. package/src/core/ui-packs/no.ts +6 -2
  526. package/src/core/ui-packs/pl.ts +6 -2
  527. package/src/core/ui-packs/pt-br.ts +3 -1
  528. package/src/core/ui-packs/pt.ts +3 -1
  529. package/src/core/ui-packs/ro.ts +6 -2
  530. package/src/core/ui-packs/ru.ts +6 -2
  531. package/src/core/ui-packs/sk.ts +6 -2
  532. package/src/core/ui-packs/sr.ts +6 -2
  533. package/src/core/ui-packs/sv.ts +6 -2
  534. package/src/core/ui-packs/th.ts +3 -1
  535. package/src/core/ui-packs/tr.ts +6 -2
  536. package/src/core/ui-packs/uk.ts +6 -2
  537. package/src/core/ui-packs/vi.ts +3 -1
  538. package/src/core/ui-packs/zh-tw.ts +3 -1
  539. package/src/core/ui-packs/zh.ts +3 -1
  540. package/src/core/unrecognized-keys.ts +10 -0
  541. package/src/core/version-cut.ts +116 -8
  542. package/src/deploy/adapter-output.ts +57 -97
  543. package/src/deploy/adapters/cloudflare.ts +39 -0
  544. package/src/deploy/adapters/index.ts +41 -0
  545. package/src/deploy/adapters/netlify.ts +34 -0
  546. package/src/deploy/adapters/node.ts +34 -0
  547. package/src/deploy/adapters/registry.ts +127 -0
  548. package/src/deploy/adapters/types.ts +92 -0
  549. package/src/deploy/adapters/vercel.ts +35 -0
  550. package/src/deploy/artifacts.ts +55 -27
  551. package/src/deploy/cloudflare-negotiation.ts +179 -100
  552. package/src/deploy/function-bundle.ts +18 -3
  553. package/src/deploy/headers.ts +124 -23
  554. package/src/deploy/node-headers.ts +198 -0
  555. package/src/deploy/platforms/cloudflare.ts +312 -0
  556. package/src/deploy/platforms/index.ts +67 -0
  557. package/src/deploy/platforms/netlify.ts +52 -0
  558. package/src/deploy/platforms/node.ts +40 -0
  559. package/src/deploy/platforms/paths.ts +42 -0
  560. package/src/deploy/platforms/static.ts +29 -0
  561. package/src/deploy/platforms/types.ts +112 -0
  562. package/src/deploy/platforms/vercel.ts +193 -0
  563. package/src/deploy/redirects.ts +30 -18
  564. package/src/deploy/robots.ts +3 -3
  565. package/src/deploy/rss.ts +2 -2
  566. package/src/deploy/sitemap.ts +2 -2
  567. package/src/deploy/vercel-negotiation.ts +2 -2
  568. package/src/eval/agents.ts +32 -1
  569. package/src/eval/findings.ts +19 -11
  570. package/src/eval/report.ts +10 -2
  571. package/src/markdown/external-links.ts +65 -0
  572. package/src/markdown/include.ts +45 -27
  573. package/src/markdown/index.ts +34 -9
  574. package/src/markdown/inline-code.ts +12 -6
  575. package/src/markdown/relative-links.ts +324 -0
  576. package/src/markdown/themes.ts +3 -3
  577. package/src/migrate/migrate.ts +149 -0
  578. package/src/openapi/parse.ts +64 -16
  579. package/src/openapi/proxy.ts +62 -10
  580. package/src/openapi/references.ts +147 -147
  581. package/src/openapi/render-mdx.ts +32 -10
  582. package/src/openapi/scalar.ts +15 -13
  583. package/src/openapi/sentence.ts +14 -0
  584. package/src/openapi/source.ts +37 -21
  585. package/src/openapi/spec-dependency-error.ts +15 -0
  586. package/src/reference/asyncapi.ts +83 -0
  587. package/src/reference/graphql.ts +89 -0
  588. package/src/reference/index.ts +40 -0
  589. package/src/reference/openapi.ts +83 -0
  590. package/src/reference/options.ts +201 -0
  591. package/src/reference/scalar.ts +136 -0
  592. package/src/reference/schema.ts +88 -0
  593. package/src/registry/eject.ts +97 -42
  594. package/src/search/adapters/algolia.ts +46 -0
  595. package/src/search/adapters/flexsearch.ts +29 -0
  596. package/src/search/adapters/index.ts +39 -0
  597. package/src/search/adapters/mixedbread.ts +39 -0
  598. package/src/search/adapters/orama-cloud.ts +51 -0
  599. package/src/search/adapters/orama.ts +24 -0
  600. package/src/search/adapters/pagefind.ts +27 -0
  601. package/src/search/adapters/registry.ts +131 -0
  602. package/src/search/adapters/types.ts +46 -0
  603. package/src/search/adapters/typesense.ts +57 -0
  604. package/src/search/build.ts +8 -4
  605. package/src/search/documents.ts +6 -0
  606. package/src/search/sync/algolia.ts +12 -11
  607. package/src/search/sync/index.ts +35 -20
  608. package/src/search/sync/orama-cloud.ts +12 -9
  609. package/src/search/sync/typesense.ts +15 -13
  610. package/src/sources/contentful.ts +63 -0
  611. package/src/sources/custom.ts +38 -0
  612. package/src/sources/filesystem.ts +51 -0
  613. package/src/sources/github-releases.ts +52 -0
  614. package/src/sources/index.ts +60 -0
  615. package/src/sources/mdx-remote.ts +76 -0
  616. package/src/sources/notion.ts +63 -0
  617. package/src/sources/obsidian.ts +38 -0
  618. package/src/sources/payload.ts +60 -0
  619. package/src/sources/registry.ts +182 -0
  620. package/src/sources/sanity.ts +66 -0
  621. package/src/sources/shared.ts +52 -0
  622. package/src/sources/strapi.ts +58 -0
  623. package/src/theme/entry.ts +24 -2
  624. package/src/translate/report.ts +40 -7
  625. package/src/upgrade/upgrade.ts +499 -0
  626. package/dist/cli/chunk-0qymqwzz.js +0 -164
  627. package/dist/cli/chunk-0qymqwzz.js.map +0 -15
  628. package/dist/cli/chunk-1jefwnfs.js.map +0 -48
  629. package/dist/cli/chunk-2mzebbbz.js +0 -69
  630. package/dist/cli/chunk-2z47ypj8.js.map +0 -11
  631. package/dist/cli/chunk-4x36ddpw.js.map +0 -11
  632. package/dist/cli/chunk-5093q3n7.js +0 -68
  633. package/dist/cli/chunk-5093q3n7.js.map +0 -10
  634. package/dist/cli/chunk-5qk08vmp.js.map +0 -11
  635. package/dist/cli/chunk-7s8hm3b6.js +0 -5347
  636. package/dist/cli/chunk-7s8hm3b6.js.map +0 -58
  637. package/dist/cli/chunk-8cjtbafj.js.map +0 -13
  638. package/dist/cli/chunk-97r59kpr.js +0 -381
  639. package/dist/cli/chunk-97r59kpr.js.map +0 -12
  640. package/dist/cli/chunk-ahnw3kxw.js.map +0 -15
  641. package/dist/cli/chunk-b27xqwn9.js.map +0 -10
  642. package/dist/cli/chunk-bf6bt1xt.js +0 -185
  643. package/dist/cli/chunk-bf6bt1xt.js.map +0 -11
  644. package/dist/cli/chunk-cjtn640a.js.map +0 -10
  645. package/dist/cli/chunk-ct47dqpx.js.map +0 -11
  646. package/dist/cli/chunk-esphfr8p.js +0 -107
  647. package/dist/cli/chunk-esphfr8p.js.map +0 -11
  648. package/dist/cli/chunk-ex56aa81.js +0 -1016
  649. package/dist/cli/chunk-ex56aa81.js.map +0 -13
  650. package/dist/cli/chunk-garjf5z9.js +0 -30
  651. package/dist/cli/chunk-garjf5z9.js.map +0 -10
  652. package/dist/cli/chunk-js7saxwm.js +0 -1045
  653. package/dist/cli/chunk-js7saxwm.js.map +0 -22
  654. package/dist/cli/chunk-k79xp7av.js.map +0 -39
  655. package/dist/cli/chunk-ps4m1xh4.js.map +0 -15
  656. package/dist/cli/chunk-q4rae3bg.js +0 -60
  657. package/dist/cli/chunk-q4rae3bg.js.map +0 -10
  658. package/dist/cli/chunk-rz9jmfhz.js +0 -108
  659. package/dist/cli/chunk-rz9jmfhz.js.map +0 -10
  660. package/dist/cli/chunk-vh9w1sgp.js +0 -73
  661. package/dist/cli/chunk-vh9w1sgp.js.map +0 -10
  662. package/dist/cli/chunk-vrfp10qk.js +0 -81
  663. package/dist/cli/chunk-vrfp10qk.js.map +0 -10
  664. package/dist/cli/chunk-yg63d42r.js.map +0 -34
  665. package/docs/advanced/api-reference.mdx +0 -240
  666. package/docs/reference/cli.mdx +0 -197
  667. package/skills/blume-migrate/assets/oxfmt@0.55.0.patch +0 -20
  668. package/src/components/content/changelog-element.ts +0 -69
  669. package/src/search/providers.ts +0 -91
  670. /package/dist/cli/{chunk-e7f42gdj.js.map → chunk-7ez8ny0t.js.map} +0 -0
  671. /package/dist/cli/{chunk-nn13znc2.js.map → chunk-88cpgt6h.js.map} +0 -0
  672. /package/dist/cli/{chunk-vacwm2hv.js.map → chunk-f7t03s3g.js.map} +0 -0
  673. /package/dist/cli/{chunk-dwgcp5sm.js.map → chunk-zxccj738.js.map} +0 -0
@@ -1,7 +1,10 @@
1
1
  ---
2
2
  import { createSatteriMarkdownProcessor } from "@astrojs/markdown-satteri";
3
+ import data from "blume:data";
3
4
 
5
+ import { contentStrings } from "./content-strings.ts";
4
6
  import { escapeRawHtml, unwrapParagraph } from "./inline-markdown.ts";
7
+ import { promptMarkdown } from "./prompt-markdown.ts";
5
8
 
6
9
  interface Props {
7
10
  actions?: boolean | string | string[];
@@ -26,6 +29,15 @@ const renderedDescription = await markdownProcessor.render(
26
29
  escapeRawHtml(description)
27
30
  );
28
31
  const descriptionHtml = unwrapParagraph(renderedDescription.code);
32
+ // The prompt as Markdown, for the copy button and the Cursor link: the rendered
33
+ // body's text alone would drop its links, list markers, and code fences.
34
+ const promptSource = Astro.slots.has("default")
35
+ ? promptMarkdown(await Astro.slots.render("default"))
36
+ : "";
37
+ const { actions: actionStrings, content: strings } = contentStrings(
38
+ data,
39
+ Astro.currentLocale
40
+ );
29
41
 
30
42
  const primaryButton =
31
43
  "inline-flex h-8 cursor-pointer items-center rounded-lg bg-accent px-3.5 font-medium text-accent-foreground text-xs transition hover:bg-accent/90";
@@ -35,6 +47,7 @@ const secondaryButton =
35
47
 
36
48
  <blume-prompt
37
49
  class="not-prose my-6 block rounded-blume border border-border bg-muted/30"
50
+ data-blume-prompt-markdown={promptSource}
38
51
  >
39
52
  <div class="flex items-center justify-between gap-3 px-4 py-3">
40
53
  <p
@@ -47,39 +60,35 @@ const secondaryButton =
47
60
  <div class="flex shrink-0 items-center gap-2">
48
61
  {enabledActions.has("copy") && (
49
62
  <button
50
- aria-label="Copy prompt"
51
63
  class={primaryButton}
52
64
  data-blume-prompt-copy
65
+ data-copied={actionStrings.copied}
53
66
  type="button"
54
67
  >
55
68
  {/* Both labels share one grid cell so the button is always sized
56
- to the wider ("Copy prompt") — swapping to "Copied" on copy
57
- can't resize it and shift the description beside it. */}
69
+ to the wider one — swapping to the copied label on copy can't
70
+ resize it and shift the description beside it. */}
58
71
  <span class="grid *:col-start-1 *:row-start-1 *:text-center">
59
- <span data-blume-prompt-copy-idle>Copy prompt</span>
72
+ <span data-blume-prompt-copy-idle>{strings.copyPrompt}</span>
60
73
  <span aria-hidden="true" class="invisible" data-blume-prompt-copy-done>
61
- Copied
74
+ {actionStrings.copied}
62
75
  </span>
63
76
  </span>
64
77
  </button>
65
78
  )}
66
79
  {enabledActions.has("cursor") && (
67
80
  <a
68
- aria-label="Open prompt in Cursor"
69
81
  class={secondaryButton}
70
82
  data-blume-prompt-cursor
71
- href="cursor://anysphere.cursor-deeplink/prompt"
83
+ href={`cursor://anysphere.cursor-deeplink/prompt?text=${encodeURIComponent(promptSource)}`}
72
84
  >
73
- Open in Cursor
85
+ {actionStrings.openIn.replace("{name}", "Cursor")}
74
86
  </a>
75
87
  )}
76
88
  </div>
77
89
  )
78
90
  }
79
91
  </div>
80
- <div data-blume-prompt-content hidden>
81
- <slot />
82
- </div>
83
92
  </blume-prompt>
84
93
 
85
94
  <script>
@@ -87,17 +96,9 @@ const secondaryButton =
87
96
 
88
97
  class BlumePrompt extends HTMLElement {
89
98
  connectedCallback() {
90
- const content = this.querySelector<HTMLElement>(
91
- "[data-blume-prompt-content]"
92
- );
93
- const promptText = () => content?.textContent?.trim() ?? "";
94
-
95
- const cursor = this.querySelector<HTMLAnchorElement>(
96
- "[data-blume-prompt-cursor]"
97
- );
98
- if (cursor) {
99
- cursor.href = `cursor://anysphere.cursor-deeplink/prompt?text=${encodeURIComponent(promptText())}`;
100
- }
99
+ // Serialized to Markdown at build time; the Cursor link already carries
100
+ // it in its href.
101
+ const promptText = this.dataset.blumePromptMarkdown ?? "";
101
102
 
102
103
  const copy = this.querySelector<HTMLButtonElement>(
103
104
  "[data-blume-prompt-copy]"
@@ -113,10 +114,9 @@ const secondaryButton =
113
114
  const flash = createCopyFlash((copied) => {
114
115
  idle?.classList.toggle("invisible", copied);
115
116
  done?.classList.toggle("invisible", !copied);
116
- }, "Copied");
117
+ }, copy?.dataset.copied ?? "Copied!");
117
118
  copy?.addEventListener("click", async () => {
118
- const text = promptText();
119
- if (text && (await copyText(text))) {
119
+ if (promptText && (await copyText(promptText))) {
120
120
  flash();
121
121
  }
122
122
  });
@@ -272,7 +272,9 @@ const useDropdown = dropdown && !inline;
272
272
  url.searchParams.set(param, id);
273
273
  history.replaceState(history.state, "", url);
274
274
  } else if (this.#hashEnabled()) {
275
- history.replaceState(null, "", `#${encodeURIComponent(id)}`);
275
+ // Keep the entry's state here too: the client router ignores a
276
+ // popstate whose state is null, so Back would change only the URL.
277
+ history.replaceState(history.state, "", `#${encodeURIComponent(id)}`);
276
278
  }
277
279
  }
278
280
  if (sync && this.#syncEnabled()) {
@@ -1,10 +1,10 @@
1
1
  ---
2
+ import { newTabAttrs } from "../../core/new-tab.ts";
2
3
  import Icon from "../Icon.astro";
3
4
  import { contentHref } from "./base-href.ts";
4
5
 
5
6
  const { description, href, title } = Astro.props;
6
7
  const Tag = href ? "a" : "div";
7
- const external = href?.startsWith("http");
8
8
  const previewPattern =
9
9
  "background-image:radial-gradient(circle at 1px 1px,color-mix(in oklab,currentColor 18%,transparent) 1px,transparent 0);background-size:18px 18px;";
10
10
  ---
@@ -13,8 +13,7 @@ const previewPattern =
13
13
  class="not-prose block overflow-hidden rounded-blume border border-border bg-background text-inherit no-underline! transition-colors hover:no-underline! hover:[&[href]]:border-accent"
14
14
  data-blume-tile
15
15
  href={href === undefined ? undefined : contentHref(href)}
16
- rel={external ? "noreferrer" : undefined}
17
- target={external ? "_blank" : undefined}
16
+ {...newTabAttrs(href)}
18
17
  >
19
18
  <div
20
19
  class="flex aspect-[16/9] min-h-32 items-center justify-center bg-muted/40 p-4 text-muted-foreground [&_img]:max-h-full [&_img]:max-w-full [&_svg]:max-h-full [&_svg]:max-w-full"
@@ -1,8 +1,8 @@
1
1
  ---
2
- import { randomUUID } from "node:crypto";
3
-
2
+ import { newTabAttrs } from "../../core/new-tab.ts";
4
3
  import { contentHref } from "./base-href.ts";
5
4
  import { unwrapParagraph } from "./inline-markdown.ts";
5
+ import { tooltipId as tooltipIdFor } from "./tooltip-id.ts";
6
6
 
7
7
  interface Props {
8
8
  cta?: string;
@@ -12,15 +12,24 @@ interface Props {
12
12
  }
13
13
 
14
14
  const { cta, headline, href, tip } = Astro.props;
15
- const tooltipId = `blume-tooltip-${randomUUID()}`;
16
- const external = href?.startsWith("http");
17
15
 
18
16
  const labelHtml = Astro.slots.has("default")
19
17
  ? unwrapParagraph(await Astro.slots.render("default"))
20
18
  : "";
19
+ // Derived from the content, so an unchanged page rebuilds byte-identical.
20
+ const tooltipId = tooltipIdFor(Astro.locals, [
21
+ labelHtml,
22
+ headline,
23
+ tip,
24
+ cta,
25
+ href,
26
+ ]);
21
27
  ---
22
28
 
23
- <span class="not-prose group relative inline-flex cursor-help items-baseline">
29
+ <span
30
+ class="not-prose relative inline-flex cursor-help items-baseline"
31
+ data-blume-tooltip
32
+ >
24
33
  <span
25
34
  aria-describedby={tooltipId}
26
35
  class="underline decoration-dotted underline-offset-4"
@@ -41,8 +50,7 @@ const labelHtml = Astro.slots.has("default")
41
50
  <a
42
51
  class="mt-2 inline-flex font-medium text-accent text-xs hover:underline"
43
52
  href={contentHref(href)}
44
- rel={external ? "noreferrer" : undefined}
45
- target={external ? "_blank" : undefined}
53
+ {...newTabAttrs(href)}
46
54
  >
47
55
  {cta}
48
56
  </a>
@@ -57,9 +65,49 @@ const labelHtml = Astro.slots.has("default")
57
65
  visibility: hidden;
58
66
  }
59
67
 
60
- [data-blume-tooltip-trigger]:focus + [data-blume-tooltip-panel],
61
- .group:hover [data-blume-tooltip-panel] {
68
+ /* Focus anywhere inside keeps it open, so a keyboard reader can Tab from
69
+ the trigger to the call-to-action link without the panel vanishing. */
70
+ [data-blume-tooltip]:hover [data-blume-tooltip-panel],
71
+ [data-blume-tooltip]:focus-within [data-blume-tooltip-panel] {
62
72
  pointer-events: auto;
63
73
  visibility: visible;
64
74
  }
75
+
76
+ /* Escape hides it until the pointer or focus leaves (WCAG 1.4.13). */
77
+ [data-blume-tooltip][data-dismissed] [data-blume-tooltip-panel] {
78
+ pointer-events: none;
79
+ visibility: hidden;
80
+ }
65
81
  </style>
82
+
83
+ <script>
84
+ // Delegated from the document, so tooltips a client-router swap brings in
85
+ // are covered without re-binding; the module runs once per real load.
86
+ const TOOLTIP = "[data-blume-tooltip]";
87
+
88
+ document.addEventListener("keydown", (event) => {
89
+ if (event.key !== "Escape") {
90
+ return;
91
+ }
92
+ for (const tooltip of document.querySelectorAll(TOOLTIP)) {
93
+ if (tooltip.matches(":hover, :focus-within")) {
94
+ tooltip.setAttribute("data-dismissed", "");
95
+ }
96
+ }
97
+ });
98
+
99
+ // Leaving the tooltip re-arms it for the next hover or focus.
100
+ const rearm = (event: FocusEvent | PointerEvent) => {
101
+ const tooltip =
102
+ event.target instanceof Element ? event.target.closest(TOOLTIP) : null;
103
+ const { relatedTarget } = event;
104
+ if (
105
+ tooltip &&
106
+ !(relatedTarget instanceof Node && tooltip.contains(relatedTarget))
107
+ ) {
108
+ tooltip.removeAttribute("data-dismissed");
109
+ }
110
+ };
111
+ document.addEventListener("focusout", rearm);
112
+ document.addEventListener("pointerout", rearm);
113
+ </script>
@@ -0,0 +1,34 @@
1
+ import { EN_UI } from "../../core/i18n-ui.ts";
2
+ import type { UIStrings } from "../../core/i18n-ui.ts";
3
+
4
+ /** The `blume:data` fields a content component resolves its labels from. */
5
+ export interface ContentStringsData {
6
+ config: { i18n: object | null };
7
+ ui: UIStrings;
8
+ uiByLocale: Record<string, UIStrings>;
9
+ }
10
+
11
+ /** The UI string groups a content component's chrome reads. */
12
+ export type ContentStrings = Pick<UIStrings, "actions" | "content">;
13
+
14
+ /**
15
+ * Labels for a component rendered inside page content (MDX), which gets no
16
+ * strings prop from the layout the way chrome components do: the dictionary of
17
+ * the locale Astro resolved for the URL (`Astro.currentLocale`, the page's own
18
+ * locale — a fallback page included, matching its chrome), else the site
19
+ * default. Merged over the English baseline per group, so a key a translation
20
+ * lacks still renders instead of coming out blank.
21
+ */
22
+ export const contentStrings = (
23
+ data: ContentStringsData,
24
+ currentLocale?: string
25
+ ): ContentStrings => {
26
+ const dictionary =
27
+ data.config.i18n && currentLocale
28
+ ? (data.uiByLocale[currentLocale] ?? data.ui)
29
+ : data.ui;
30
+ return {
31
+ actions: { ...EN_UI.actions, ...dictionary.actions },
32
+ content: { ...EN_UI.content, ...dictionary.content },
33
+ };
34
+ };
@@ -36,7 +36,7 @@ export interface DiffOptions {
36
36
  /** Path to a `.patch`/`.diff` file, resolved relative to {@link DiffOptions.root}. */
37
37
  src?: string;
38
38
  /**
39
- * Light/dark Shiki themes (`markdown.codeBlocks.theme`). Defaults to the same
39
+ * Light/dark Shiki themes (`markdown.code.theme`). Defaults to the same
40
40
  * github pair Blume's code blocks use, keeping diffs in lockstep.
41
41
  */
42
42
  theme?: CodeThemes;
@@ -23,7 +23,10 @@ const prefersDark = () => document.documentElement.dataset.theme === "dark";
23
23
 
24
24
  let counter = 0;
25
25
 
26
- class BlumeMermaid extends HTMLElement {
26
+ // Exported so this file is a module, not a script: `blume:features` lazy-loads
27
+ // it with `import()`, and `astro check` rejects a dynamic import of a file with
28
+ // no import or export of its own (ts(2306)) on every site with a diagram.
29
+ export class BlumeMermaid extends HTMLElement {
27
30
  #observer: MutationObserver | null = null;
28
31
  #renderToken = 0;
29
32
 
@@ -84,8 +87,16 @@ class BlumeMermaid extends HTMLElement {
84
87
  // Re-render on color-theme changes so the diagram tracks light and dark.
85
88
  // One observer per connection, disconnected on removal — otherwise every
86
89
  // DOM move stacks another observer that renders into detached DOM forever.
90
+ // The theme script rewrites `data-theme` after every client-router swap,
91
+ // usually to the value it already had, so only a real flip re-renders.
92
+ let dark = prefersDark();
87
93
  this.#observer?.disconnect();
88
- this.#observer = new MutationObserver(() => render());
94
+ this.#observer = new MutationObserver(() => {
95
+ if (prefersDark() !== dark) {
96
+ dark = prefersDark();
97
+ render();
98
+ }
99
+ });
89
100
  this.#observer.observe(document.documentElement, {
90
101
  attributeFilter: ["data-theme"],
91
102
  });
@@ -0,0 +1,292 @@
1
+ import { NodeType, parse } from "node-html-parser";
2
+ import type { HTMLElement, Node } from "node-html-parser";
3
+
4
+ /**
5
+ * A `<Prompt>`'s body as Markdown, for its copy button and "Open in Cursor"
6
+ * link. The component only ever sees its slot as rendered HTML, so this turns
7
+ * that HTML back into the Markdown a reader pastes into an AI tool — keeping
8
+ * link URLs, list markers, emphasis, and code fences that the element's plain
9
+ * `textContent` would drop.
10
+ */
11
+
12
+ /** Elements that carry no prompt text: chrome, media, and hidden content. */
13
+ const SKIPPED = new Set(["BUTTON", "SCRIPT", "STYLE", "SVG", "TEMPLATE"]);
14
+
15
+ const HEADING = /^H(?<level>[1-6])$/u;
16
+
17
+ /** Elements that start a block of their own rather than flowing inline. */
18
+ const BLOCKS = new Set([
19
+ "BLOCKQUOTE",
20
+ "DETAILS",
21
+ "DIV",
22
+ "FIGURE",
23
+ "H1",
24
+ "H2",
25
+ "H3",
26
+ "H4",
27
+ "H5",
28
+ "H6",
29
+ "HR",
30
+ "OL",
31
+ "P",
32
+ "PRE",
33
+ "SECTION",
34
+ "TABLE",
35
+ "UL",
36
+ ]);
37
+
38
+ const isElement = (node: Node): node is HTMLElement =>
39
+ node.nodeType === NodeType.ELEMENT_NODE;
40
+
41
+ const isSkipped = (element: HTMLElement): boolean =>
42
+ SKIPPED.has(element.tagName) ||
43
+ element.hasAttribute("hidden") ||
44
+ element.getAttribute("aria-hidden") === "true";
45
+
46
+ /** A backtick run one longer than any inside `text`, so it can't close early. */
47
+ const fenceFor = (text: string, minimum: number): string => {
48
+ const longest = Math.max(
49
+ 0,
50
+ ...(text.match(/`+/gu) ?? []).map((run) => run.length)
51
+ );
52
+ return "`".repeat(Math.max(minimum, longest + 1));
53
+ };
54
+
55
+ /** Wrap `inner` in `marker`, keeping edge spaces outside the markers. */
56
+ const wrap = (marker: string, inner: string): string => {
57
+ const trimmed = inner.trim();
58
+ if (!trimmed) {
59
+ return inner;
60
+ }
61
+ const lead = inner.startsWith(" ") ? " " : "";
62
+ const trail = inner.endsWith(" ") ? " " : "";
63
+ return `${lead}${marker}${trimmed}${marker}${trail}`;
64
+ };
65
+
66
+ const inlineCode = (text: string): string => {
67
+ const fence = fenceFor(text, 1);
68
+ const pad = text.startsWith("`") || text.endsWith("`") ? " " : "";
69
+ return `${fence}${pad}${text}${pad}${fence}`;
70
+ };
71
+
72
+ /**
73
+ * Finish an inline run: HTML collapses whitespace across element edges too, so
74
+ * the space a text node and an emphasis marker each kept becomes one.
75
+ */
76
+ const collapse = (text: string): string =>
77
+ text.replaceAll(/ {2,}/gu, " ").trim();
78
+
79
+ const inline = (node: Node): string => {
80
+ if (!isElement(node)) {
81
+ // HTML collapses runs of whitespace (source newlines included) to one space.
82
+ return node.text.replaceAll(/\s+/gu, " ");
83
+ }
84
+ if (isSkipped(node)) {
85
+ return "";
86
+ }
87
+ const children = () => node.childNodes.map(inline).join("");
88
+ switch (node.tagName) {
89
+ case "A": {
90
+ const href = node.getAttribute("href");
91
+ const label = children().trim();
92
+ if (!href) {
93
+ return label;
94
+ }
95
+ return label && label !== href ? `[${label}](${href})` : href;
96
+ }
97
+ case "B":
98
+ case "STRONG": {
99
+ return wrap("**", children());
100
+ }
101
+ case "BR": {
102
+ return "\n";
103
+ }
104
+ case "CODE": {
105
+ return inlineCode(node.text);
106
+ }
107
+ case "DEL":
108
+ case "S": {
109
+ return wrap("~~", children());
110
+ }
111
+ case "EM":
112
+ case "I": {
113
+ return wrap("_", children());
114
+ }
115
+ case "IMG": {
116
+ const src = node.getAttribute("src");
117
+ return src ? `![${node.getAttribute("alt") ?? ""}](${src})` : "";
118
+ }
119
+ default: {
120
+ return children();
121
+ }
122
+ }
123
+ };
124
+
125
+ /** A line-by-line indent, leaving blank lines blank. */
126
+ const indent = (text: string, prefix: string): string =>
127
+ text
128
+ .split("\n")
129
+ .map((line) => (line ? `${prefix}${line}` : line))
130
+ .join("\n");
131
+
132
+ const codeBlock = (pre: HTMLElement): string => {
133
+ const code = pre.querySelector("code");
134
+ const language =
135
+ pre.attributes["data-language"] ??
136
+ /\blanguage-(?<lang>\S+)/u.exec(code?.getAttribute("class") ?? "")?.groups
137
+ ?.lang ??
138
+ "";
139
+ const text = (code ?? pre).text.replace(/\n$/u, "");
140
+ const fence = fenceFor(text, 3);
141
+ return `${fence}${language}\n${text}\n${fence}`;
142
+ };
143
+
144
+ const listBlock = (list: HTMLElement): string => {
145
+ const ordered = list.tagName === "OL";
146
+ let number = Number(list.getAttribute("start") ?? "1") || 1;
147
+ const items: string[] = [];
148
+ for (const item of list.childNodes) {
149
+ if (!isElement(item) || item.tagName !== "LI") {
150
+ continue;
151
+ }
152
+ const marker = ordered ? `${number}.` : "-";
153
+ number += 1;
154
+ // A tight item (no paragraphs of its own) keeps its nested list on the
155
+ // next line; a loose one separates its blocks with a blank line.
156
+ const loose = item.childNodes.some(
157
+ (child) => isElement(child) && child.tagName === "P"
158
+ );
159
+ // oxlint-disable-next-line no-use-before-define -- mutual recursion: an item holds blocks, including nested lists
160
+ const body = blocks(item).join(loose ? "\n\n" : "\n");
161
+ const [first = "", ...rest] = body.split("\n");
162
+ const continuation = indent(rest.join("\n"), " ".repeat(marker.length + 1));
163
+ items.push(
164
+ continuation
165
+ ? `${marker} ${first}\n${continuation}`
166
+ : `${marker} ${first}`
167
+ );
168
+ }
169
+ return items.join("\n");
170
+ };
171
+
172
+ /** A GFM delimiter cell per column alignment; unaligned columns get `---`. */
173
+ const DELIMITERS = new Map([
174
+ ["center", ":---:"],
175
+ ["left", ":---"],
176
+ ["right", "---:"],
177
+ ]);
178
+
179
+ const TEXT_ALIGN = /text-align:\s*(?<align>center|left|right)/u;
180
+
181
+ /** A cell's alignment, from the `align` attribute or an inline style. */
182
+ const cellAlign = (cell: HTMLElement | undefined): string =>
183
+ cell?.getAttribute("align") ??
184
+ TEXT_ALIGN.exec(cell?.getAttribute("style") ?? "")?.groups?.align ??
185
+ "";
186
+
187
+ /** A cell's inline Markdown on one line, its pipes escaped. */
188
+ const tableCell = (cell: HTMLElement | undefined): string =>
189
+ cell
190
+ ? collapse(inline(cell).replaceAll("\n", " ")).replaceAll(
191
+ "|",
192
+ String.raw`\|`
193
+ )
194
+ : "";
195
+
196
+ const isCell = (node: Node): node is HTMLElement =>
197
+ isElement(node) && (node.tagName === "TD" || node.tagName === "TH");
198
+
199
+ /**
200
+ * A table as a GFM table: its first row as the header (GFM requires one), a
201
+ * delimiter row carrying each column's alignment, then the body rows, padded
202
+ * to the widest row.
203
+ */
204
+ const tableBlock = (table: HTMLElement): string => {
205
+ const rows = table
206
+ .querySelectorAll("tr")
207
+ .filter((row) => !isSkipped(row))
208
+ .map((row) => row.childNodes.filter(isCell));
209
+ const [head, ...body] = rows;
210
+ if (!head) {
211
+ return "";
212
+ }
213
+ const width = Math.max(...rows.map((row) => row.length));
214
+ const columns = Array.from({ length: width }, (_, index) => index);
215
+ const row = (cells: HTMLElement[]): string =>
216
+ `| ${columns.map((index) => tableCell(cells[index])).join(" | ")} |`;
217
+ const delimiter = `| ${columns
218
+ .map((index) => DELIMITERS.get(cellAlign(head[index])) ?? "---")
219
+ .join(" | ")} |`;
220
+ return [row(head), delimiter, ...body.map(row)].join("\n");
221
+ };
222
+
223
+ const block = (element: HTMLElement): string[] => {
224
+ const heading = HEADING.exec(element.tagName)?.groups?.level;
225
+ if (heading) {
226
+ return [`${"#".repeat(Number(heading))} ${collapse(inline(element))}`];
227
+ }
228
+ switch (element.tagName) {
229
+ case "BLOCKQUOTE": {
230
+ // Every line is quoted, blank ones included, so the paragraphs stay in
231
+ // one quote.
232
+ // oxlint-disable-next-line no-use-before-define -- mutual recursion: a quote holds blocks
233
+ const quoted = blocks(element)
234
+ .join("\n\n")
235
+ .split("\n")
236
+ .map((line) => (line ? `> ${line}` : ">"));
237
+ return [quoted.join("\n")];
238
+ }
239
+ case "HR": {
240
+ return ["---"];
241
+ }
242
+ case "OL":
243
+ case "UL": {
244
+ return [listBlock(element)];
245
+ }
246
+ case "P": {
247
+ return [collapse(inline(element))];
248
+ }
249
+ case "PRE": {
250
+ return [codeBlock(element)];
251
+ }
252
+ case "TABLE": {
253
+ return [tableBlock(element)];
254
+ }
255
+ default: {
256
+ // oxlint-disable-next-line no-use-before-define -- mutual recursion: a container holds blocks
257
+ return blocks(element);
258
+ }
259
+ }
260
+ };
261
+
262
+ /** A container's children as Markdown blocks, inline runs grouped into one. */
263
+ const blocks = (container: HTMLElement): string[] => {
264
+ const out: string[] = [];
265
+ let run = "";
266
+ const flush = () => {
267
+ const text = collapse(run);
268
+ if (text) {
269
+ out.push(text);
270
+ }
271
+ run = "";
272
+ };
273
+ for (const child of container.childNodes) {
274
+ if (isElement(child) && BLOCKS.has(child.tagName)) {
275
+ flush();
276
+ if (!isSkipped(child)) {
277
+ out.push(...block(child).filter(Boolean));
278
+ }
279
+ } else {
280
+ run += inline(child);
281
+ }
282
+ }
283
+ flush();
284
+ return out;
285
+ };
286
+
287
+ export const promptMarkdown = (html: string): string =>
288
+ // `pre` is parsed as elements (not raw text) so a code block's `<code>` and
289
+ // its language attribute are reachable.
290
+ blocks(parse(html, { blockTextElements: { script: true, style: true } }))
291
+ .join("\n\n")
292
+ .trim();
@@ -0,0 +1,41 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ /**
4
+ * Per-render bookkeeping for stable element ids, kept on the request's
5
+ * `Astro.locals` so every component in one page render — layout and MDX
6
+ * content alike — shares it, and concurrent page renders never see each
7
+ * other's.
8
+ */
9
+ export interface StableIdLocals {
10
+ /** Prefix + content digest → how many elements on this page carried it. */
11
+ blumeStableIds?: Map<string, number>;
12
+ }
13
+
14
+ /**
15
+ * An element id derived from what the element renders, not drawn at random,
16
+ * so rebuilding an unchanged page produces the same HTML. A second identical
17
+ * element on the same page gets a numbered suffix to keep ids unique;
18
+ * identical elements render identical markup, so which copy is numbered never
19
+ * changes the page's bytes.
20
+ */
21
+ export const stableId = (
22
+ locals: StableIdLocals,
23
+ prefix: string,
24
+ content: readonly (string | undefined)[]
25
+ ): string => {
26
+ const digest = createHash("sha256")
27
+ .update(JSON.stringify(content))
28
+ .digest("hex")
29
+ .slice(0, 12);
30
+ const base = `${prefix}-${digest}`;
31
+ locals.blumeStableIds ??= new Map();
32
+ const count = (locals.blumeStableIds.get(base) ?? 0) + 1;
33
+ locals.blumeStableIds.set(base, count);
34
+ return count === 1 ? base : `${base}-${count}`;
35
+ };
36
+
37
+ /** The element id a tooltip's panel and trigger pair on. */
38
+ export const tooltipId = (
39
+ locals: StableIdLocals,
40
+ content: readonly (string | undefined)[]
41
+ ): string => stableId(locals, "blume-tooltip", content);