blume 1.7.3 → 2.0.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 (690) hide show
  1. package/AGENTS.md +19 -0
  2. package/CHANGELOG.md +245 -0
  3. package/README.md +34 -21
  4. package/dist/cli/{chunk-vacwm2hv.js → chunk-27g6wdth.js} +2 -2
  5. package/dist/cli/{chunk-ps4m1xh4.js → chunk-2hn4b8z7.js} +513 -550
  6. package/dist/cli/chunk-2hn4b8z7.js.map +12 -0
  7. package/dist/cli/chunk-5shv93fd.js +39 -0
  8. package/dist/cli/chunk-5shv93fd.js.map +10 -0
  9. package/dist/cli/chunk-6crbhc3x.js +361 -0
  10. package/dist/cli/chunk-6crbhc3x.js.map +14 -0
  11. package/dist/cli/{chunk-8cjtbafj.js → chunk-6hsn950k.js} +109 -383
  12. package/dist/cli/chunk-6hsn950k.js.map +10 -0
  13. package/dist/cli/chunk-6vm74dry.js +148 -0
  14. package/dist/cli/chunk-6vm74dry.js.map +10 -0
  15. package/dist/cli/{chunk-yg63d42r.js → chunk-79jhk4py.js} +87 -58
  16. package/dist/cli/chunk-79jhk4py.js.map +35 -0
  17. package/dist/cli/chunk-82bbrxdn.js +51 -0
  18. package/dist/cli/chunk-82bbrxdn.js.map +10 -0
  19. package/dist/cli/chunk-abh8yjkn.js +31 -0
  20. package/dist/cli/chunk-abh8yjkn.js.map +10 -0
  21. package/dist/cli/chunk-ah61y8py.js +75 -0
  22. package/dist/cli/chunk-ah61y8py.js.map +11 -0
  23. package/dist/cli/{chunk-dwgcp5sm.js → chunk-ce574jw2.js} +1 -1
  24. package/dist/cli/chunk-ch6g3ar0.js +102 -0
  25. package/dist/cli/chunk-ch6g3ar0.js.map +10 -0
  26. package/dist/cli/chunk-dh8cwk36.js +279 -0
  27. package/dist/cli/chunk-dh8cwk36.js.map +10 -0
  28. package/dist/cli/{chunk-rqy0s5wh.js → chunk-epjnccmv.js} +17 -16
  29. package/dist/cli/{chunk-rqy0s5wh.js.map → chunk-epjnccmv.js.map} +3 -3
  30. package/dist/cli/chunk-f2z5v128.js +97 -0
  31. package/dist/cli/chunk-f2z5v128.js.map +10 -0
  32. package/dist/cli/{chunk-2z47ypj8.js → chunk-fa25z98p.js} +16 -3
  33. package/dist/cli/chunk-fa25z98p.js.map +11 -0
  34. package/dist/cli/{chunk-1jefwnfs.js → chunk-fs23ddbb.js} +1076 -2592
  35. package/dist/cli/chunk-fs23ddbb.js.map +35 -0
  36. package/dist/cli/{chunk-e7f42gdj.js → chunk-fxypxtvm.js} +2 -2
  37. package/dist/cli/{chunk-bvwwhd84.js → chunk-fz5wtpmh.js} +15 -15
  38. package/dist/cli/{chunk-bvwwhd84.js.map → chunk-fz5wtpmh.js.map} +1 -1
  39. package/dist/cli/chunk-hdpx1tax.js +91 -0
  40. package/dist/cli/chunk-hdpx1tax.js.map +10 -0
  41. package/dist/cli/{chunk-ct47dqpx.js → chunk-jts8mvcz.js} +67 -7
  42. package/dist/cli/{chunk-2mzebbbz.js.map → chunk-jts8mvcz.js.map} +6 -4
  43. package/dist/cli/{chunk-ahnw3kxw.js → chunk-jwyddg7y.js} +27 -22
  44. package/dist/cli/chunk-jwyddg7y.js.map +15 -0
  45. package/dist/cli/{chunk-cjtn640a.js → chunk-kdp5q7ke.js} +43 -20
  46. package/dist/cli/chunk-kdp5q7ke.js.map +10 -0
  47. package/dist/cli/{chunk-5g0w1e2c.js → chunk-kpf8rrjc.js} +28 -16
  48. package/dist/cli/{chunk-5g0w1e2c.js.map → chunk-kpf8rrjc.js.map} +4 -4
  49. package/dist/cli/chunk-m3vmjgmq.js +133 -0
  50. package/dist/cli/chunk-m3vmjgmq.js.map +10 -0
  51. package/dist/cli/{chunk-b27xqwn9.js → chunk-mb2919y2.js} +9 -5
  52. package/dist/cli/chunk-mb2919y2.js.map +10 -0
  53. package/dist/cli/{chunk-5qk08vmp.js → chunk-q5163e60.js} +133 -54
  54. package/dist/cli/chunk-q5163e60.js.map +11 -0
  55. package/dist/cli/chunk-qkqwkpte.js +12437 -0
  56. package/dist/cli/chunk-qkqwkpte.js.map +182 -0
  57. package/dist/cli/{chunk-4x36ddpw.js → chunk-qs4q5p4e.js} +81 -87
  58. package/dist/cli/chunk-qs4q5p4e.js.map +10 -0
  59. package/dist/cli/{chunk-0xjyb285.js → chunk-qwsrynx5.js} +15 -5
  60. package/dist/cli/{chunk-0xjyb285.js.map → chunk-qwsrynx5.js.map} +4 -4
  61. package/dist/cli/chunk-s1p84fyh.js +261 -0
  62. package/dist/cli/chunk-s1p84fyh.js.map +10 -0
  63. package/dist/cli/chunk-s6jhgk0q.js +176 -0
  64. package/dist/cli/chunk-s6jhgk0q.js.map +11 -0
  65. package/dist/cli/chunk-vtk4a6dg.js +374 -0
  66. package/dist/cli/chunk-vtk4a6dg.js.map +10 -0
  67. package/dist/cli/{chunk-k79xp7av.js → chunk-wgm7m9qk.js} +230 -700
  68. package/dist/cli/chunk-wgm7m9qk.js.map +36 -0
  69. package/dist/cli/chunk-wm7js3j9.js +145 -0
  70. package/dist/cli/chunk-wm7js3j9.js.map +11 -0
  71. package/dist/cli/chunk-yt5n7ppj.js +79 -0
  72. package/dist/cli/chunk-yt5n7ppj.js.map +10 -0
  73. package/dist/cli/{chunk-3r45185y.js → chunk-yw7dm696.js} +9 -11
  74. package/dist/cli/{chunk-3r45185y.js.map → chunk-yw7dm696.js.map} +3 -3
  75. package/dist/cli/{chunk-nn13znc2.js → chunk-zxcczpyx.js} +1 -1
  76. package/dist/cli/chunk-zxh4d9vy.js +122 -0
  77. package/dist/cli/chunk-zxh4d9vy.js.map +11 -0
  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-context.d.ts +7 -7
  85. package/dist/types/ai/ask.d.ts +368 -0
  86. package/dist/types/ai/changelog-markdown.d.ts +2 -0
  87. package/dist/types/ai/component-markdown.d.ts +2 -2
  88. package/dist/types/ai/index.d.ts +24 -0
  89. package/dist/types/ai/link-headers.d.ts +24 -0
  90. package/dist/types/ai/llms.d.ts +25 -0
  91. package/dist/types/ai/markdown.d.ts +45 -0
  92. package/dist/types/ai/mcp/discovery.d.ts +68 -0
  93. package/dist/types/ai/mcp/tools.d.ts +16 -0
  94. package/dist/types/ai/openapi-components.d.ts +43 -0
  95. package/dist/types/ai/relative-links.d.ts +26 -0
  96. package/dist/types/ai/serializers.d.ts +15 -0
  97. package/dist/types/ai/skills.d.ts +42 -0
  98. package/dist/types/ai/tar.d.ts +25 -0
  99. package/dist/types/ai/visibility.d.ts +17 -0
  100. package/dist/types/ai/web-bot-auth.d.ts +16 -0
  101. package/dist/types/analytics/adobe.d.ts +35 -0
  102. package/dist/types/analytics/amplitude.d.ts +50 -0
  103. package/dist/types/analytics/clarity.d.ts +31 -0
  104. package/dist/types/analytics/clearbit.d.ts +29 -0
  105. package/dist/types/analytics/cloudflare.d.ts +41 -0
  106. package/dist/types/analytics/fathom.d.ts +41 -0
  107. package/dist/types/analytics/google-analytics.d.ts +44 -0
  108. package/dist/types/analytics/google-tag-manager.d.ts +40 -0
  109. package/dist/types/analytics/head.d.ts +30 -0
  110. package/dist/types/analytics/heap.d.ts +40 -0
  111. package/dist/types/analytics/hightouch.d.ts +44 -0
  112. package/dist/types/analytics/hotjar.d.ts +33 -0
  113. package/dist/types/analytics/index.d.ts +61 -0
  114. package/dist/types/analytics/inline.d.ts +17 -0
  115. package/dist/types/analytics/logrocket.d.ts +44 -0
  116. package/dist/types/analytics/mixpanel.d.ts +67 -0
  117. package/dist/types/analytics/pirsch.d.ts +42 -0
  118. package/dist/types/analytics/plausible.d.ts +56 -0
  119. package/dist/types/analytics/posthog.d.ts +45 -0
  120. package/dist/types/analytics/schema.d.ts +320 -0
  121. package/dist/types/analytics/script.d.ts +46 -0
  122. package/dist/types/analytics/segment.d.ts +50 -0
  123. package/dist/types/analytics/vercel.d.ts +48 -0
  124. package/dist/types/astro/integration.d.ts +76 -0
  125. package/dist/types/astro/markdown-negotiation.d.ts +23 -0
  126. package/dist/types/astro/module-types.d.ts +14 -0
  127. package/dist/types/astro/pages.d.ts +44 -0
  128. package/dist/types/cli/env.d.ts +12 -0
  129. package/dist/types/cli/init/scaffold.d.ts +154 -0
  130. package/dist/types/components/layout/nav-utils.d.ts +11 -0
  131. package/dist/types/core/adapter.d.ts +47 -0
  132. package/dist/types/core/api-name.d.ts +7 -0
  133. package/dist/types/core/changelog-index.d.ts +13 -0
  134. package/dist/types/core/config-input.d.ts +197 -526
  135. package/dist/types/core/config.d.ts +61 -35
  136. package/dist/types/core/content-assets.d.ts +76 -0
  137. package/dist/types/core/custom-pages.d.ts +33 -0
  138. package/dist/types/core/data.d.ts +30 -15
  139. package/dist/types/core/define-components.d.ts +12 -9
  140. package/dist/types/core/deployment-env.d.ts +6 -11
  141. package/dist/types/core/frontmatter.d.ts +10 -0
  142. package/dist/types/core/graph.d.ts +18 -0
  143. package/dist/types/core/heading-markers.d.ts +54 -0
  144. package/dist/types/core/i18n-ui.d.ts +12 -10
  145. package/dist/types/core/i18n.d.ts +87 -0
  146. package/dist/types/core/includes.d.ts +138 -0
  147. package/dist/types/core/last-modified.d.ts +47 -0
  148. package/dist/types/core/links.d.ts +95 -0
  149. package/dist/types/core/locale-links.d.ts +60 -0
  150. package/dist/types/core/manifest.d.ts +17 -0
  151. package/dist/types/core/meta.d.ts +38 -0
  152. package/dist/types/core/nav-diagnostics.d.ts +26 -0
  153. package/dist/types/core/navigation.d.ts +6 -0
  154. package/dist/types/core/node-require.d.ts +19 -0
  155. package/dist/types/core/package-json.d.ts +13 -0
  156. package/dist/types/core/probe.d.ts +42 -0
  157. package/dist/types/core/project-graph.d.ts +51 -0
  158. package/dist/types/core/project.d.ts +2 -0
  159. package/dist/types/core/safe-href.d.ts +2 -0
  160. package/dist/types/core/safe-links.d.ts +26 -0
  161. package/dist/types/core/schema.d.ts +2284 -454
  162. package/dist/types/core/site-url.d.ts +16 -0
  163. package/dist/types/core/sources/assets.d.ts +36 -0
  164. package/dist/types/core/sources/cache.d.ts +37 -0
  165. package/dist/types/core/sources/collection.d.ts +28 -0
  166. package/dist/types/core/sources/contentful-rich-text.d.ts +31 -0
  167. package/dist/types/core/sources/contentful.d.ts +40 -0
  168. package/dist/types/core/sources/filesystem.d.ts +24 -0
  169. package/dist/types/core/sources/github-releases.d.ts +31 -0
  170. package/dist/types/core/sources/json.d.ts +30 -0
  171. package/dist/types/core/sources/lexical.d.ts +19 -0
  172. package/dist/types/core/sources/lower.d.ts +75 -0
  173. package/dist/types/core/sources/mdx-remote.d.ts +28 -0
  174. package/dist/types/core/sources/normalize.d.ts +147 -0
  175. package/dist/types/core/sources/notion.d.ts +131 -0
  176. package/dist/types/core/sources/obsidian.d.ts +46 -0
  177. package/dist/types/core/sources/payload.d.ts +39 -0
  178. package/dist/types/core/sources/portable-text.d.ts +42 -0
  179. package/dist/types/core/sources/read.d.ts +23 -0
  180. package/dist/types/core/sources/remote.d.ts +74 -0
  181. package/dist/types/core/sources/resolve.d.ts +19 -0
  182. package/dist/types/core/sources/sanity.d.ts +43 -0
  183. package/dist/types/core/sources/strapi-blocks.d.ts +12 -0
  184. package/dist/types/core/sources/strapi.d.ts +33 -0
  185. package/dist/types/core/sources/types.d.ts +7 -0
  186. package/dist/types/core/sources/watch.d.ts +45 -0
  187. package/dist/types/core/text-width.d.ts +11 -0
  188. package/dist/types/core/types.d.ts +15 -1
  189. package/dist/types/core/unrecognized-keys.d.ts +7 -0
  190. package/dist/types/core/versions.d.ts +72 -0
  191. package/dist/types/core/yaml.d.ts +9 -0
  192. package/dist/types/deploy/adapter-output.d.ts +45 -0
  193. package/dist/types/deploy/adapters/cloudflare.d.ts +40 -0
  194. package/dist/types/deploy/adapters/index.d.ts +29 -0
  195. package/dist/types/deploy/adapters/netlify.d.ts +37 -0
  196. package/dist/types/deploy/adapters/node.d.ts +37 -0
  197. package/dist/types/deploy/adapters/registry.d.ts +133 -0
  198. package/dist/types/deploy/adapters/types.d.ts +71 -0
  199. package/dist/types/deploy/adapters/vercel.d.ts +38 -0
  200. package/dist/types/deploy/artifacts.d.ts +65 -0
  201. package/dist/types/deploy/cloudflare-negotiation.d.ts +196 -0
  202. package/dist/types/deploy/function-bundle.d.ts +80 -0
  203. package/dist/types/deploy/headers.d.ts +50 -0
  204. package/dist/types/deploy/node-headers.d.ts +42 -0
  205. package/dist/types/deploy/platforms/cloudflare.d.ts +40 -0
  206. package/dist/types/deploy/platforms/index.d.ts +18 -0
  207. package/dist/types/deploy/platforms/netlify.d.ts +13 -0
  208. package/dist/types/deploy/platforms/node.d.ts +11 -0
  209. package/dist/types/deploy/platforms/paths.d.ts +27 -0
  210. package/dist/types/deploy/platforms/static.d.ts +10 -0
  211. package/dist/types/deploy/platforms/types.d.ts +104 -0
  212. package/dist/types/deploy/platforms/vercel.d.ts +32 -0
  213. package/dist/types/deploy/redirects.d.ts +53 -0
  214. package/dist/types/deploy/robots.d.ts +8 -0
  215. package/dist/types/deploy/rss.d.ts +31 -0
  216. package/dist/types/deploy/sitemap.d.ts +21 -0
  217. package/dist/types/deploy/vercel-negotiation.d.ts +109 -0
  218. package/dist/types/markdown/code-title.d.ts +32 -0
  219. package/dist/types/markdown/fence-meta.d.ts +23 -0
  220. package/dist/types/markdown/themes.d.ts +3 -3
  221. package/dist/types/openapi/asyncapi.d.ts +129 -0
  222. package/dist/types/openapi/graphql-build.d.ts +8 -0
  223. package/dist/types/openapi/graphql.d.ts +122 -0
  224. package/dist/types/openapi/model.d.ts +158 -0
  225. package/dist/types/openapi/parse.d.ts +57 -0
  226. package/dist/types/openapi/references.d.ts +37 -25
  227. package/dist/types/openapi/render-mdx.d.ts +33 -0
  228. package/dist/types/openapi/sentence.d.ts +7 -0
  229. package/dist/types/openapi/signature.d.ts +10 -0
  230. package/dist/types/openapi/source.d.ts +22 -0
  231. package/dist/types/openapi/spec-dependency-error.d.ts +10 -0
  232. package/dist/types/reference/asyncapi.d.ts +166 -0
  233. package/dist/types/reference/graphql.d.ts +181 -0
  234. package/dist/types/reference/index.d.ts +32 -0
  235. package/dist/types/reference/openapi.d.ts +165 -0
  236. package/dist/types/reference/options.d.ts +157 -0
  237. package/dist/types/reference/scalar.d.ts +136 -0
  238. package/dist/types/reference/schema.d.ts +630 -0
  239. package/dist/types/search/adapters/algolia.d.ts +32 -0
  240. package/dist/types/search/adapters/flexsearch.d.ts +12 -0
  241. package/dist/types/search/adapters/index.d.ts +31 -0
  242. package/dist/types/search/adapters/mixedbread.d.ts +22 -0
  243. package/dist/types/search/adapters/orama-cloud.d.ts +33 -0
  244. package/dist/types/search/adapters/orama.d.ts +13 -0
  245. package/dist/types/search/adapters/pagefind.d.ts +12 -0
  246. package/dist/types/search/adapters/registry.d.ts +228 -0
  247. package/dist/types/search/adapters/types.d.ts +34 -0
  248. package/dist/types/search/adapters/typesense.d.ts +42 -0
  249. package/dist/types/search/build.d.ts +23 -0
  250. package/dist/types/search/documents.d.ts +90 -0
  251. package/dist/types/search/facets.d.ts +3 -0
  252. package/dist/types/search/orama-index.d.ts +1 -1
  253. package/dist/types/search/sync/algolia.d.ts +14 -0
  254. package/dist/types/search/sync/index.d.ts +14 -0
  255. package/dist/types/search/sync/orama-cloud.d.ts +10 -0
  256. package/dist/types/search/sync/typesense.d.ts +14 -0
  257. package/dist/types/sources/contentful.d.ts +68 -0
  258. package/dist/types/sources/custom.d.ts +20 -0
  259. package/dist/types/sources/filesystem.d.ts +42 -0
  260. package/dist/types/sources/github-releases.d.ts +46 -0
  261. package/dist/types/sources/index.d.ts +48 -0
  262. package/dist/types/sources/mdx-remote.d.ts +63 -0
  263. package/dist/types/sources/notion.d.ts +65 -0
  264. package/dist/types/sources/obsidian.d.ts +34 -0
  265. package/dist/types/sources/payload.d.ts +68 -0
  266. package/dist/types/sources/registry.d.ts +1414 -0
  267. package/dist/types/sources/sanity.d.ts +69 -0
  268. package/dist/types/sources/shared.d.ts +46 -0
  269. package/dist/types/sources/strapi.d.ts +66 -0
  270. package/dist/types/theme/icon-kind.d.ts +11 -0
  271. package/dist/types/theme/icons.d.ts +20 -0
  272. package/docs/01-quickstart.mdx +18 -18
  273. package/docs/02-deployment.mdx +52 -28
  274. package/docs/03-upgrading.mdx +364 -0
  275. package/docs/04-migrating.mdx +58 -0
  276. package/docs/08-faq.mdx +5 -5
  277. package/docs/advanced/blog.mdx +13 -6
  278. package/docs/advanced/changelog.mdx +23 -35
  279. package/docs/advanced/custom-pages.mdx +22 -10
  280. package/docs/advanced/meta.ts +1 -8
  281. package/docs/advanced/skills.mdx +8 -0
  282. package/docs/cli/audit.mdx +646 -0
  283. package/docs/cli/doctor.mdx +29 -0
  284. package/docs/{reference/eval.mdx → cli/evals.mdx} +12 -11
  285. package/docs/cli/index.mdx +105 -0
  286. package/docs/cli/meta.ts +7 -0
  287. package/docs/{reference → cli}/translate.mdx +9 -9
  288. package/docs/cli/validate.mdx +41 -0
  289. package/docs/cli/version.mdx +40 -0
  290. package/docs/configuration/analytics.mdx +350 -59
  291. package/docs/configuration/assistant.mdx +357 -0
  292. package/docs/configuration/customization.mdx +16 -10
  293. package/docs/configuration/index.mdx +50 -31
  294. package/docs/configuration/meta.ts +1 -1
  295. package/docs/configuration/search.mdx +76 -55
  296. package/docs/configuration/theming.mdx +24 -15
  297. package/docs/content/components.mdx +21 -5
  298. package/docs/{reference → content}/frontmatter.mdx +35 -1
  299. package/docs/content/i18n.mdx +9 -7
  300. package/docs/content/includes.mdx +2 -4
  301. package/docs/content/index.mdx +1 -1
  302. package/docs/content/islands.mdx +11 -6
  303. package/docs/content/meta.mdx +1 -1
  304. package/docs/content/meta.ts +1 -0
  305. package/docs/content/navigation.mdx +9 -7
  306. package/docs/content/sources.mdx +145 -50
  307. package/docs/content/syntax.mdx +16 -12
  308. package/docs/content/versioning.mdx +3 -3
  309. package/docs/discoverability/agent-discovery.mdx +12 -12
  310. package/docs/discoverability/index.mdx +4 -4
  311. package/docs/discoverability/json-api.mdx +4 -4
  312. package/docs/discoverability/llms-txt.mdx +6 -6
  313. package/docs/discoverability/markdown.mdx +4 -4
  314. package/docs/discoverability/mcp.mdx +11 -11
  315. package/docs/discoverability/sitemap-and-robots.mdx +3 -3
  316. package/docs/index.mdx +4 -4
  317. package/docs/references/asyncapi.mdx +59 -0
  318. package/docs/{advanced → references}/graphql.mdx +45 -32
  319. package/docs/{reference → references}/meta.ts +2 -2
  320. package/docs/references/openapi.mdx +171 -0
  321. package/docs/references/scalar.mdx +64 -0
  322. package/package.json +42 -8
  323. package/skills/blume/SKILL.md +23 -10
  324. package/skills/blume-migrate/SKILL.md +22 -21
  325. package/skills/blume-migrate/assets/oxfmt@0.67.0.patch +49 -0
  326. package/skills/blume-migrate/references/docusaurus.md +5 -4
  327. package/skills/blume-migrate/references/fumadocs.md +4 -4
  328. package/skills/blume-migrate/references/mintlify.md +23 -8
  329. package/skills/blume-migrate/references/monorepo.md +6 -6
  330. package/skills/blume-migrate/references/starlight.md +4 -4
  331. package/src/ai/agent-readability.ts +25 -26
  332. package/src/ai/ai-catalog.ts +50 -32
  333. package/src/ai/api/handlers.ts +46 -11
  334. package/src/ai/api/paths.ts +1 -1
  335. package/src/ai/api-catalog.ts +8 -8
  336. package/src/ai/ask-context.ts +7 -7
  337. package/src/ai/ask-data.ts +3 -3
  338. package/src/ai/ask.ts +637 -100
  339. package/src/ai/changelog-markdown.ts +91 -0
  340. package/src/ai/component-markdown.ts +328 -12
  341. package/src/ai/cors.ts +3 -3
  342. package/src/ai/index.ts +45 -0
  343. package/src/ai/link-headers.ts +7 -6
  344. package/src/ai/llms.ts +20 -15
  345. package/src/ai/markdown.ts +35 -5
  346. package/src/ai/mcp/data.ts +9 -5
  347. package/src/ai/openapi-components.ts +5 -2
  348. package/src/ai/relative-links.ts +170 -0
  349. package/src/ai/serializers.ts +3 -3
  350. package/src/ai/skills.ts +1 -1
  351. package/src/ai/visibility.ts +1 -1
  352. package/src/ai/web-bot-auth.ts +2 -2
  353. package/src/analytics/adobe.ts +46 -0
  354. package/src/analytics/amplitude.ts +79 -0
  355. package/src/analytics/clarity.ts +46 -0
  356. package/src/analytics/clearbit.ts +47 -0
  357. package/src/analytics/cloudflare.ts +67 -0
  358. package/src/analytics/fathom.ts +64 -0
  359. package/src/analytics/google-analytics.ts +84 -0
  360. package/src/analytics/google-tag-manager.ts +61 -0
  361. package/src/analytics/head.ts +130 -0
  362. package/src/analytics/heap.ts +65 -0
  363. package/src/analytics/hightouch.ts +77 -0
  364. package/src/analytics/hotjar.ts +47 -0
  365. package/src/analytics/index.ts +71 -0
  366. package/src/analytics/inline.ts +21 -0
  367. package/src/analytics/logrocket.ts +71 -0
  368. package/src/analytics/mixpanel.ts +92 -0
  369. package/src/analytics/pirsch.ts +66 -0
  370. package/src/analytics/plausible.ts +83 -0
  371. package/src/analytics/posthog.ts +78 -0
  372. package/src/analytics/schema.ts +60 -0
  373. package/src/analytics/script.ts +60 -0
  374. package/src/analytics/segment.ts +85 -0
  375. package/src/analytics/vercel.ts +50 -0
  376. package/src/astro/adapter-root.ts +7 -9
  377. package/src/astro/component-slots.ts +131 -91
  378. package/src/astro/generate.ts +129 -361
  379. package/src/astro/integration.ts +2 -6
  380. package/src/astro/module-types.ts +1 -1
  381. package/src/astro/pages.ts +13 -101
  382. package/src/astro/render-deps.ts +379 -0
  383. package/src/astro/runtime-deps.ts +201 -0
  384. package/src/astro/templates.ts +575 -562
  385. package/src/audit/agent.ts +24 -0
  386. package/src/audit/catalog.ts +2 -2
  387. package/src/audit/checks/assets.ts +2 -2
  388. package/src/audit/checks/dns-aid.ts +1 -1
  389. package/src/audit/checks/duplicates.ts +3 -1
  390. package/src/audit/checks/i18n.ts +1 -1
  391. package/src/audit/checks/indexability.ts +7 -7
  392. package/src/audit/checks/links.ts +2 -2
  393. package/src/audit/checks/llms.ts +6 -6
  394. package/src/audit/checks/network.ts +3 -3
  395. package/src/audit/checks/og-image.ts +2 -2
  396. package/src/audit/checks/robots.ts +1 -1
  397. package/src/audit/checks/sitemap.ts +2 -2
  398. package/src/audit/checks/social.ts +1 -1
  399. package/src/audit/run.ts +4 -3
  400. package/src/audit/terms.ts +31 -0
  401. package/src/audit/url.ts +13 -13
  402. package/src/blume-modules.d.ts +2 -2
  403. package/src/cli/command-meta.ts +10 -0
  404. package/src/cli/commands/audit.ts +40 -21
  405. package/src/cli/commands/build.ts +71 -316
  406. package/src/cli/commands/check.ts +1 -0
  407. package/src/cli/commands/dev.ts +40 -1
  408. package/src/cli/commands/doctor.ts +92 -14
  409. package/src/cli/commands/eject.ts +44 -7
  410. package/src/cli/commands/eval.ts +5 -5
  411. package/src/cli/commands/init.ts +161 -41
  412. package/src/cli/commands/migrate.ts +121 -0
  413. package/src/cli/commands/preview.ts +7 -1
  414. package/src/cli/commands/translate.ts +5 -5
  415. package/src/cli/commands/upgrade.ts +141 -0
  416. package/src/cli/commands/version.ts +57 -44
  417. package/src/cli/eject-scripts.ts +121 -6
  418. package/src/cli/index.ts +11 -1
  419. package/src/cli/init/install.ts +70 -0
  420. package/src/cli/init/questions.ts +7 -0
  421. package/src/cli/init/scaffold.ts +459 -75
  422. package/src/cli/lazy-command.ts +37 -1
  423. package/src/cli/prepare.ts +40 -6
  424. package/src/cli/required-secrets.ts +39 -12
  425. package/src/cli/unknown-flags.ts +266 -0
  426. package/src/cli/yarn-pnp.ts +52 -0
  427. package/src/components/content/AccordionItem.astro +7 -1
  428. package/src/components/content/Card.astro +4 -3
  429. package/src/components/content/ColorItem.astro +22 -4
  430. package/src/components/content/GithubInfo.astro +2 -2
  431. package/src/components/content/Prompt.astro +25 -25
  432. package/src/components/content/Tabs.astro +3 -1
  433. package/src/components/content/Tile.astro +2 -3
  434. package/src/components/content/Tooltip.astro +57 -9
  435. package/src/components/content/content-strings.ts +34 -0
  436. package/src/components/content/diff.ts +1 -1
  437. package/src/components/content/mermaid-element.ts +13 -2
  438. package/src/components/content/prompt-markdown.ts +292 -0
  439. package/src/components/content/tooltip-id.ts +41 -0
  440. package/src/components/copy-feedback.ts +1 -1
  441. package/src/components/islands/{AskAI.astro → Assistant.astro} +10 -10
  442. package/src/components/islands/{ask-ai.tsx → assistant.tsx} +23 -23
  443. package/src/components/islands/hooks.ts +36 -11
  444. package/src/components/layout/Analytics.astro +21 -79
  445. package/src/components/layout/Banner.astro +3 -1
  446. package/src/components/layout/DiscoveryLinks.astro +69 -0
  447. package/src/components/layout/Header.astro +93 -30
  448. package/src/components/layout/LanguageSwitcher.astro +4 -1
  449. package/src/components/layout/Logo.astro +23 -2
  450. package/src/components/layout/NavSelector.astro +13 -2
  451. package/src/components/layout/NavTree.astro +12 -3
  452. package/src/components/layout/NavTreeScript.astro +17 -3
  453. package/src/components/layout/PageActions.astro +3 -3
  454. package/src/components/layout/PageFeedback.astro +11 -1
  455. package/src/components/layout/PageLayout.astro +58 -11
  456. package/src/components/layout/Pagination.astro +7 -7
  457. package/src/components/layout/ReferenceLayout.astro +22 -13
  458. package/src/components/layout/RootLayout.astro +75 -72
  459. package/src/components/layout/Search.astro +43 -19
  460. package/src/components/layout/WebMcp.astro +1 -1
  461. package/src/components/layout/analytics-client.ts +73 -16
  462. package/src/components/layout/drawer-inert.ts +113 -15
  463. package/src/components/layout/dropdown-clamp.ts +105 -0
  464. package/src/components/layout/head-scripts.ts +15 -6
  465. package/src/components/layout/nav-utils.ts +17 -0
  466. package/src/components/layout/search/algolia.ts +8 -8
  467. package/src/components/layout/search/orama-cloud.ts +9 -7
  468. package/src/components/layout/search/typesense.ts +11 -17
  469. package/src/components/openapi/MessageComposer.astro +2 -2
  470. package/src/components/openapi/Playground.astro +2 -2
  471. package/src/components/openapi/description.ts +2 -2
  472. package/src/components/openapi/playground-client.ts +79 -10
  473. package/src/core/changelog-index.ts +24 -0
  474. package/src/core/code-fences.ts +1 -1
  475. package/src/core/component-overrides.ts +399 -154
  476. package/src/core/config-input.ts +201 -566
  477. package/src/core/config.ts +131 -42
  478. package/src/core/custom-pages.ts +105 -0
  479. package/src/core/data.ts +34 -15
  480. package/src/core/define-components.ts +12 -9
  481. package/src/core/deployment-env.ts +18 -74
  482. package/src/core/diagnostics.ts +14 -7
  483. package/src/core/graph.ts +69 -25
  484. package/src/core/i18n-ui.ts +41 -11
  485. package/src/core/i18n.ts +17 -0
  486. package/src/core/includes.ts +156 -38
  487. package/src/core/last-modified.ts +6 -11
  488. package/src/core/links.ts +166 -2
  489. package/src/core/manifest.ts +10 -3
  490. package/src/core/navigation.ts +115 -16
  491. package/src/core/new-tab.ts +35 -0
  492. package/src/core/node-require.ts +21 -0
  493. package/src/core/project-graph.ts +42 -26
  494. package/src/core/project.ts +9 -4
  495. package/src/core/request-body.ts +61 -0
  496. package/src/core/safe-href.ts +28 -0
  497. package/src/core/safe-links.ts +68 -0
  498. package/src/core/schema.ts +528 -745
  499. package/src/core/server-features.ts +10 -11
  500. package/src/core/sources/assets.ts +47 -11
  501. package/src/core/sources/collection.ts +67 -0
  502. package/src/core/sources/contentful-rich-text.ts +285 -0
  503. package/src/core/sources/contentful.ts +173 -0
  504. package/src/core/sources/github-releases.ts +51 -1
  505. package/src/core/sources/json.ts +71 -0
  506. package/src/core/sources/lexical.ts +195 -0
  507. package/src/core/sources/lower.ts +226 -0
  508. package/src/core/sources/normalize.ts +52 -2
  509. package/src/core/sources/notion.ts +39 -28
  510. package/src/core/sources/payload.ts +135 -0
  511. package/src/core/sources/portable-text.ts +11 -16
  512. package/src/core/sources/remote.ts +226 -0
  513. package/src/core/sources/resolve.ts +104 -166
  514. package/src/core/sources/sanity.ts +16 -49
  515. package/src/core/sources/strapi-blocks.ts +124 -0
  516. package/src/core/sources/strapi.ts +191 -0
  517. package/src/core/sources/types.ts +12 -1
  518. package/src/core/types.ts +15 -1
  519. package/src/core/ui-packs/ar.ts +10 -7
  520. package/src/core/ui-packs/bg.ts +10 -7
  521. package/src/core/ui-packs/bn.ts +10 -7
  522. package/src/core/ui-packs/ca.ts +7 -6
  523. package/src/core/ui-packs/cs.ts +10 -7
  524. package/src/core/ui-packs/da.ts +10 -7
  525. package/src/core/ui-packs/de.ts +10 -7
  526. package/src/core/ui-packs/el.ts +7 -6
  527. package/src/core/ui-packs/es.ts +7 -6
  528. package/src/core/ui-packs/fa.ts +10 -7
  529. package/src/core/ui-packs/fi.ts +10 -7
  530. package/src/core/ui-packs/fr.ts +7 -6
  531. package/src/core/ui-packs/he.ts +10 -7
  532. package/src/core/ui-packs/hi.ts +10 -7
  533. package/src/core/ui-packs/hr.ts +10 -7
  534. package/src/core/ui-packs/hu.ts +10 -7
  535. package/src/core/ui-packs/id.ts +10 -7
  536. package/src/core/ui-packs/it.ts +7 -6
  537. package/src/core/ui-packs/ja.ts +7 -6
  538. package/src/core/ui-packs/ko.ts +7 -6
  539. package/src/core/ui-packs/nl.ts +10 -7
  540. package/src/core/ui-packs/no.ts +10 -7
  541. package/src/core/ui-packs/pl.ts +10 -7
  542. package/src/core/ui-packs/pt-br.ts +7 -6
  543. package/src/core/ui-packs/pt.ts +7 -6
  544. package/src/core/ui-packs/ro.ts +10 -7
  545. package/src/core/ui-packs/ru.ts +10 -7
  546. package/src/core/ui-packs/sk.ts +10 -7
  547. package/src/core/ui-packs/sr.ts +10 -7
  548. package/src/core/ui-packs/sv.ts +10 -7
  549. package/src/core/ui-packs/th.ts +7 -6
  550. package/src/core/ui-packs/tr.ts +10 -7
  551. package/src/core/ui-packs/uk.ts +10 -7
  552. package/src/core/ui-packs/vi.ts +7 -6
  553. package/src/core/ui-packs/zh-tw.ts +7 -6
  554. package/src/core/ui-packs/zh.ts +7 -6
  555. package/src/core/unrecognized-keys.ts +10 -0
  556. package/src/core/version-cut.ts +116 -8
  557. package/src/deploy/adapter-output.ts +57 -97
  558. package/src/deploy/adapters/cloudflare.ts +39 -0
  559. package/src/deploy/adapters/index.ts +41 -0
  560. package/src/deploy/adapters/netlify.ts +34 -0
  561. package/src/deploy/adapters/node.ts +34 -0
  562. package/src/deploy/adapters/registry.ts +127 -0
  563. package/src/deploy/adapters/types.ts +92 -0
  564. package/src/deploy/adapters/vercel.ts +35 -0
  565. package/src/deploy/artifacts.ts +55 -27
  566. package/src/deploy/cloudflare-negotiation.ts +179 -100
  567. package/src/deploy/function-bundle.ts +18 -3
  568. package/src/deploy/headers.ts +124 -23
  569. package/src/deploy/node-headers.ts +198 -0
  570. package/src/deploy/platforms/cloudflare.ts +312 -0
  571. package/src/deploy/platforms/index.ts +67 -0
  572. package/src/deploy/platforms/netlify.ts +52 -0
  573. package/src/deploy/platforms/node.ts +40 -0
  574. package/src/deploy/platforms/paths.ts +42 -0
  575. package/src/deploy/platforms/static.ts +29 -0
  576. package/src/deploy/platforms/types.ts +112 -0
  577. package/src/deploy/platforms/vercel.ts +193 -0
  578. package/src/deploy/redirects.ts +30 -18
  579. package/src/deploy/robots.ts +3 -3
  580. package/src/deploy/rss.ts +2 -2
  581. package/src/deploy/sitemap.ts +2 -2
  582. package/src/deploy/vercel-negotiation.ts +2 -2
  583. package/src/eval/agents.ts +32 -1
  584. package/src/eval/findings.ts +19 -11
  585. package/src/eval/report.ts +10 -2
  586. package/src/markdown/external-links.ts +65 -0
  587. package/src/markdown/include.ts +45 -27
  588. package/src/markdown/index.ts +34 -9
  589. package/src/markdown/inline-code.ts +12 -6
  590. package/src/markdown/relative-links.ts +324 -0
  591. package/src/markdown/themes.ts +3 -3
  592. package/src/migrate/migrate.ts +149 -0
  593. package/src/openapi/parse.ts +64 -16
  594. package/src/openapi/proxy.ts +62 -10
  595. package/src/openapi/references.ts +147 -147
  596. package/src/openapi/render-mdx.ts +32 -10
  597. package/src/openapi/scalar.ts +15 -13
  598. package/src/openapi/sentence.ts +14 -0
  599. package/src/openapi/source.ts +37 -21
  600. package/src/openapi/spec-dependency-error.ts +15 -0
  601. package/src/reference/asyncapi.ts +83 -0
  602. package/src/reference/graphql.ts +89 -0
  603. package/src/reference/index.ts +40 -0
  604. package/src/reference/openapi.ts +83 -0
  605. package/src/reference/options.ts +201 -0
  606. package/src/reference/scalar.ts +136 -0
  607. package/src/reference/schema.ts +88 -0
  608. package/src/registry/eject.ts +109 -53
  609. package/src/search/adapters/algolia.ts +46 -0
  610. package/src/search/adapters/flexsearch.ts +29 -0
  611. package/src/search/adapters/index.ts +39 -0
  612. package/src/search/adapters/mixedbread.ts +39 -0
  613. package/src/search/adapters/orama-cloud.ts +51 -0
  614. package/src/search/adapters/orama.ts +24 -0
  615. package/src/search/adapters/pagefind.ts +27 -0
  616. package/src/search/adapters/registry.ts +131 -0
  617. package/src/search/adapters/types.ts +46 -0
  618. package/src/search/adapters/typesense.ts +57 -0
  619. package/src/search/build.ts +8 -4
  620. package/src/search/documents.ts +8 -2
  621. package/src/search/orama-index.ts +1 -1
  622. package/src/search/sync/algolia.ts +12 -11
  623. package/src/search/sync/index.ts +35 -20
  624. package/src/search/sync/orama-cloud.ts +12 -9
  625. package/src/search/sync/typesense.ts +15 -13
  626. package/src/sources/contentful.ts +63 -0
  627. package/src/sources/custom.ts +38 -0
  628. package/src/sources/filesystem.ts +51 -0
  629. package/src/sources/github-releases.ts +52 -0
  630. package/src/sources/index.ts +60 -0
  631. package/src/sources/mdx-remote.ts +76 -0
  632. package/src/sources/notion.ts +63 -0
  633. package/src/sources/obsidian.ts +38 -0
  634. package/src/sources/payload.ts +60 -0
  635. package/src/sources/registry.ts +182 -0
  636. package/src/sources/sanity.ts +66 -0
  637. package/src/sources/shared.ts +52 -0
  638. package/src/sources/strapi.ts +58 -0
  639. package/src/theme/entry.ts +24 -2
  640. package/src/translate/report.ts +40 -7
  641. package/src/upgrade/upgrade.ts +499 -0
  642. package/dist/cli/chunk-0qymqwzz.js +0 -164
  643. package/dist/cli/chunk-0qymqwzz.js.map +0 -15
  644. package/dist/cli/chunk-1jefwnfs.js.map +0 -48
  645. package/dist/cli/chunk-2mzebbbz.js +0 -69
  646. package/dist/cli/chunk-2z47ypj8.js.map +0 -11
  647. package/dist/cli/chunk-4x36ddpw.js.map +0 -11
  648. package/dist/cli/chunk-5093q3n7.js +0 -68
  649. package/dist/cli/chunk-5093q3n7.js.map +0 -10
  650. package/dist/cli/chunk-5qk08vmp.js.map +0 -11
  651. package/dist/cli/chunk-7s8hm3b6.js +0 -5347
  652. package/dist/cli/chunk-7s8hm3b6.js.map +0 -58
  653. package/dist/cli/chunk-8cjtbafj.js.map +0 -13
  654. package/dist/cli/chunk-97r59kpr.js +0 -381
  655. package/dist/cli/chunk-97r59kpr.js.map +0 -12
  656. package/dist/cli/chunk-ahnw3kxw.js.map +0 -15
  657. package/dist/cli/chunk-b27xqwn9.js.map +0 -10
  658. package/dist/cli/chunk-bf6bt1xt.js +0 -185
  659. package/dist/cli/chunk-bf6bt1xt.js.map +0 -11
  660. package/dist/cli/chunk-cjtn640a.js.map +0 -10
  661. package/dist/cli/chunk-ct47dqpx.js.map +0 -11
  662. package/dist/cli/chunk-esphfr8p.js +0 -107
  663. package/dist/cli/chunk-esphfr8p.js.map +0 -11
  664. package/dist/cli/chunk-ex56aa81.js +0 -1016
  665. package/dist/cli/chunk-ex56aa81.js.map +0 -13
  666. package/dist/cli/chunk-garjf5z9.js +0 -30
  667. package/dist/cli/chunk-garjf5z9.js.map +0 -10
  668. package/dist/cli/chunk-js7saxwm.js +0 -1045
  669. package/dist/cli/chunk-js7saxwm.js.map +0 -22
  670. package/dist/cli/chunk-k79xp7av.js.map +0 -39
  671. package/dist/cli/chunk-ps4m1xh4.js.map +0 -15
  672. package/dist/cli/chunk-q4rae3bg.js +0 -60
  673. package/dist/cli/chunk-q4rae3bg.js.map +0 -10
  674. package/dist/cli/chunk-rz9jmfhz.js +0 -108
  675. package/dist/cli/chunk-rz9jmfhz.js.map +0 -10
  676. package/dist/cli/chunk-vh9w1sgp.js +0 -73
  677. package/dist/cli/chunk-vh9w1sgp.js.map +0 -10
  678. package/dist/cli/chunk-vrfp10qk.js +0 -81
  679. package/dist/cli/chunk-vrfp10qk.js.map +0 -10
  680. package/dist/cli/chunk-yg63d42r.js.map +0 -34
  681. package/docs/advanced/api-reference.mdx +0 -240
  682. package/docs/configuration/ask-ai.mdx +0 -256
  683. package/docs/reference/cli.mdx +0 -197
  684. package/skills/blume-migrate/assets/oxfmt@0.55.0.patch +0 -20
  685. package/src/components/content/changelog-element.ts +0 -69
  686. package/src/search/providers.ts +0 -91
  687. /package/dist/cli/{chunk-vacwm2hv.js.map → chunk-27g6wdth.js.map} +0 -0
  688. /package/dist/cli/{chunk-dwgcp5sm.js.map → chunk-ce574jw2.js.map} +0 -0
  689. /package/dist/cli/{chunk-e7f42gdj.js.map → chunk-fxypxtvm.js.map} +0 -0
  690. /package/dist/cli/{chunk-nn13znc2.js.map → chunk-zxcczpyx.js.map} +0 -0
@@ -6,6 +6,7 @@ import { join } from "pathe";
6
6
  import { parseYouTubeId } from "../../components/content/youtube.ts";
7
7
  import { BlumeError } from "../diagnostics.ts";
8
8
  import matter from "../frontmatter.ts";
9
+ import { nodeRequire } from "../node-require.ts";
9
10
  import type { Diagnostic } from "../types.ts";
10
11
  import { materializeAssets } from "./assets.ts";
11
12
  import {
@@ -14,6 +15,7 @@ import {
14
15
  pollingWatch,
15
16
  snapshotCache,
16
17
  } from "./cache.ts";
18
+ import { codeFence, image, renderInline, renderLink } from "./lower.ts";
17
19
  import { slugifyPath } from "./normalize.ts";
18
20
  import type {
19
21
  ContentSource,
@@ -152,24 +154,25 @@ interface NotionFrontmatter {
152
154
  [key: string]: boolean | string | { order: number } | undefined;
153
155
  }
154
156
 
157
+ /**
158
+ * Rich text as Markdown for an MDX body. Each run goes through the shared
159
+ * lowering, so a literal `{`, `<`, `*`, or `[` typed in Notion renders as
160
+ * itself instead of opening a JSX expression, a tag, or emphasis, and a code
161
+ * run keeps its text verbatim inside a long-enough code span.
162
+ */
155
163
  const richToMarkdown = (rich: NotionRichText[] = []): string =>
156
164
  rich
157
- .map((node) => {
158
- let text = node.plain_text;
159
- if (node.annotations?.code) {
160
- text = `\`${text}\``;
161
- }
162
- if (node.annotations?.bold) {
163
- text = `**${text}**`;
164
- }
165
- if (node.annotations?.italic) {
166
- text = `*${text}*`;
167
- }
168
- if (node.annotations?.strikethrough) {
169
- text = `~~${text}~~`;
170
- }
171
- return node.href ? `[${text}](${node.href})` : text;
172
- })
165
+ .map(({ annotations = {}, href, plain_text: text }) =>
166
+ renderLink(
167
+ renderInline(text, {
168
+ bold: annotations.bold,
169
+ code: annotations.code,
170
+ italic: annotations.italic,
171
+ strike: annotations.strikethrough,
172
+ }),
173
+ href ?? undefined
174
+ )
175
+ )
173
176
  .join("");
174
177
 
175
178
  const isBlockPayload = (
@@ -334,11 +337,12 @@ const renderLeaf = (block: NotionBlock): string | null => {
334
337
  return "---";
335
338
  }
336
339
  case "code": {
337
- return `\`\`\`${data.language ?? ""}\n${text}\n\`\`\``;
340
+ // The code's own text, verbatim: escapes would show inside the fence.
341
+ return codeFence(richToPlain(blockField(block)), data.language ?? "");
338
342
  }
339
343
  case "image": {
340
344
  const url = data.external?.url ?? data.file?.url;
341
- return url ? `![${richToMarkdown(data.caption)}](${url})` : "";
345
+ return url ? image(richToPlain(data.caption), url) : "";
342
346
  }
343
347
  case "video": {
344
348
  return renderVideo(data);
@@ -369,6 +373,8 @@ export const notionSource = (
369
373
  // limited API, and a slow video must not hold API slots. One gate per source
370
374
  // bounds the fan-out across every page, not just within one.
371
375
  const downloads = pLimit(ASSET_DOWNLOAD_CONCURRENCY);
376
+ // Shared with the gate so two pages naming one asset share one download.
377
+ const inFlight = new Map<string, Promise<string>>();
372
378
  // Every Notion API call goes through the limiter, inside the retry — so a
373
379
  // call sleeping through a backoff doesn't hold a slot while it waits.
374
380
  const notionCall = <T>(call: () => Promise<T>): Promise<T> =>
@@ -381,16 +387,18 @@ export const notionSource = (
381
387
  const assetsBaseUrl = ctx?.assetsBaseUrl ?? `/blume-assets/${options.name}`;
382
388
  let snapshot = new Map<string, SourceEntry>();
383
389
 
384
- const resolveClient = async (): Promise<NotionClientLike> => {
390
+ const resolveClient = (): NotionClientLike => {
385
391
  if (options.client) {
386
392
  return options.client;
387
393
  }
388
394
  let Client: new (config: { auth?: string }) => NotionClientLike;
389
395
  try {
390
- // The module is widened first because the SDK's response unions are
391
- // broader than the NotionClientLike slice, so a direct assertion is
392
- // rejected as non-overlapping.
393
- const sdk: unknown = await import("@notionhq/client");
396
+ // `require`, not `import()`: an ejected app scans in
397
+ // `astro:build:done` (see `core/node-require.ts`). The module is
398
+ // widened first because the SDK's response unions are broader than the
399
+ // NotionClientLike slice, so a direct assertion is rejected as
400
+ // non-overlapping.
401
+ const sdk: unknown = nodeRequire("@notionhq/client");
394
402
  // SAFETY: `@notionhq/client` exports a `Client` class constructable with
395
403
  // an `auth` token whose instances cover the NotionClientLike slice; the
396
404
  // local type keeps the SDK mockable without importing its types.
@@ -438,7 +446,8 @@ export const notionSource = (
438
446
  return `<Callout>\n${body}\n</Callout>`;
439
447
  }
440
448
  if (block.type === "toggle") {
441
- const title = jsxString(richToMarkdown(blockField(block)));
449
+ // The item's title renders as text, not Markdown.
450
+ const title = jsxString(richToPlain(blockField(block)));
442
451
  return `<Accordion>\n<AccordionItem title=${title}>\n${await children(block)}\n</AccordionItem>\n</Accordion>`;
443
452
  }
444
453
  if (block.type === "column_list") {
@@ -532,11 +541,12 @@ export const notionSource = (
532
541
 
533
542
  const frontmatter = (page: NotionPage) => {
534
543
  const data: NotionFrontmatter = {};
535
- const title = richToMarkdown(titleProperty(page)?.title);
544
+ // Frontmatter holds plain text: Markdown marks or escapes would show.
545
+ const title = richToPlain(titleProperty(page)?.title);
536
546
  if (title) {
537
547
  data.title = title;
538
548
  }
539
- const description = richToMarkdown(
549
+ const description = richToPlain(
540
550
  page.properties[props.description ?? "Description"]?.rich_text
541
551
  );
542
552
  if (description) {
@@ -549,7 +559,7 @@ export const notionSource = (
549
559
  if (order !== undefined) {
550
560
  data.sidebar = { order };
551
561
  }
552
- const slugProp = richToMarkdown(
562
+ const slugProp = richToPlain(
553
563
  page.properties[props.slug ?? "Slug"]?.rich_text
554
564
  );
555
565
  // Path-aware: a `guides/setup` slug keeps its `/` (per-segment slugging)
@@ -568,6 +578,7 @@ export const notionSource = (
568
578
  assetsBaseUrl,
569
579
  assetsDir,
570
580
  fetchImpl: options.fetchImpl,
581
+ inFlight,
571
582
  limit: downloads,
572
583
  });
573
584
  const raw = matter.stringify(assets.markdown, data);
@@ -625,7 +636,7 @@ export const notionSource = (
625
636
  options.name,
626
637
  cache,
627
638
  async () => {
628
- const client = await resolveClient();
639
+ const client = resolveClient();
629
640
  const dataSourceId = await resolveDataSource(client);
630
641
  const pages = await collectAll((cursor) =>
631
642
  queryDataSource(client, dataSourceId, cursor)
@@ -0,0 +1,135 @@
1
+ import type { JsonObject } from "./json.ts";
2
+ import { asObject, asString, isJsonObject, objectsIn } from "./json.ts";
3
+ import { lexicalToMarkdown } from "./lexical.ts";
4
+ import { writesMdx } from "./lower.ts";
5
+ import type { RemoteFieldMap, RestClient } from "./remote.ts";
6
+ import {
7
+ documentEntry,
8
+ fetchJson,
9
+ queryString,
10
+ remoteSource,
11
+ } from "./remote.ts";
12
+ import type { ContentSource, SourceContext, SourceEntry } from "./types.ts";
13
+
14
+ export interface PayloadSourceOptions {
15
+ name: string;
16
+ prefix?: string;
17
+ /** The Payload app's origin (`https://cms.acme.dev`); its REST API is at `/api`. */
18
+ url: string;
19
+ /** The collection slug whose documents become pages. */
20
+ collection: string;
21
+ /**
22
+ * The auth-enabled collection the API key belongs to; default `users`. It
23
+ * names the scheme in the `Authorization` header (`users API-Key <key>`).
24
+ */
25
+ authCollection?: string;
26
+ /** Relationship depth to populate; default `1`, enough for upload URLs. */
27
+ depth?: number;
28
+ /**
29
+ * Field paths mapping a document onto Blume meta + body. Defaults:
30
+ * `title`, `description`, `slug`, `content`, `updatedAt`.
31
+ */
32
+ fields?: RemoteFieldMap;
33
+ /** Extra query parameters for the collection request (`where[...]`, `sort`). */
34
+ params?: Record<string, string>;
35
+ /** Serializers for `block`/`inlineBlock` nodes, keyed by `blockType`. */
36
+ serializers?: Record<string, (fields: JsonObject) => string>;
37
+ /** API key; defaults to `PAYLOAD_API_KEY`. */
38
+ token?: string;
39
+ /** Opt-in dev polling interval (seconds); omit to freeze for the session. */
40
+ pollInterval?: number;
41
+ /** Injected for tests; defaults to the global `fetch`. */
42
+ fetchImpl?: typeof fetch;
43
+ }
44
+
45
+ const PAGE_SIZE = 100;
46
+
47
+ const DEFAULT_FIELDS: Required<RemoteFieldMap> = {
48
+ body: "content",
49
+ description: "description",
50
+ lastModified: "updatedAt",
51
+ slug: "slug",
52
+ title: "title",
53
+ };
54
+
55
+ /**
56
+ * Payload content source. Pages through a collection's REST endpoint, maps
57
+ * each document's fields to frontmatter, and lowers its Lexical body to
58
+ * Markdown. Published documents only, unless `--preview` asks for drafts.
59
+ */
60
+ export const payloadSource = (
61
+ options: PayloadSourceOptions,
62
+ ctx?: SourceContext
63
+ ): ContentSource => {
64
+ const fields = { ...DEFAULT_FIELDS, ...options.fields };
65
+ const origin = options.url.replace(/\/+$/u, "");
66
+
67
+ const lower = (body: JsonObject): string =>
68
+ lexicalToMarkdown(body, {
69
+ baseUrl: origin,
70
+ serializers: options.serializers,
71
+ });
72
+
73
+ const fetchEntries = async (): Promise<SourceEntry[]> => {
74
+ const preview = ctx?.preview ?? false;
75
+ const token = options.token ?? process.env.PAYLOAD_API_KEY;
76
+ const client: RestClient = {
77
+ fetchImpl: options.fetchImpl,
78
+ headers: token
79
+ ? {
80
+ authorization: `${options.authCollection ?? "users"} API-Key ${token}`,
81
+ }
82
+ : {},
83
+ };
84
+ const base = `${origin}/api/${options.collection}`;
85
+ const entries: SourceEntry[] = [];
86
+ let page = 1;
87
+ let more = true;
88
+ while (more) {
89
+ // The user's params go first so the paging controls always win — a
90
+ // `params` key that shadowed them would refetch the same page forever.
91
+ const query = queryString({
92
+ ...options.params,
93
+ depth: String(options.depth ?? 1),
94
+ draft: preview ? "true" : undefined,
95
+ limit: String(PAGE_SIZE),
96
+ page: String(page),
97
+ });
98
+ // oxlint-disable-next-line no-await-in-loop -- pages are sequential: each response says whether another exists.
99
+ const result = asObject(await fetchJson(`${base}?${query}`, client));
100
+ if (!result) {
101
+ throw new Error("Payload returned a non-object response");
102
+ }
103
+ for (const doc of objectsIn(result.docs)) {
104
+ const draft = asString(doc._status) === "draft";
105
+ if (draft && !preview) {
106
+ continue;
107
+ }
108
+ const id = asString(doc.id) ?? String(doc.id ?? "");
109
+ entries.push(
110
+ documentEntry(
111
+ doc,
112
+ fields,
113
+ id,
114
+ (body) => (isJsonObject(body) ? lower(body) : ""),
115
+ draft,
116
+ writesMdx(options.serializers)
117
+ )
118
+ );
119
+ }
120
+ more = result.hasNextPage === true;
121
+ page += 1;
122
+ }
123
+ return entries;
124
+ };
125
+
126
+ return remoteSource(
127
+ {
128
+ fetchEntries,
129
+ name: options.name,
130
+ pollInterval: options.pollInterval,
131
+ prefix: options.prefix,
132
+ },
133
+ ctx
134
+ );
135
+ };
@@ -4,6 +4,7 @@
4
4
  * user-supplied serializer or are skipped with a noted comment. Output is
5
5
  * Markdown text that flows through Blume's normal pipeline.
6
6
  */
7
+ import { escapeMarkdownText, image, unsupported, writesMdx } from "./lower.ts";
7
8
 
8
9
  /**
9
10
  * A field value on a Portable Text node: the arbitrary JSON the CMS query
@@ -49,7 +50,10 @@ interface PortableTextMarkDef {
49
50
  export interface PortableTextOptions {
50
51
  /** Resolve an image block to a URL (the adapter knows project/dataset). */
51
52
  imageUrl?: (block: PortableTextBlock) => string | null;
52
- /** Custom block-type serializers, keyed by `_type`; return Markdown/MDX. */
53
+ /**
54
+ * Custom block-type serializers, keyed by `_type`; return Markdown or MDX.
55
+ * Setting any writes the source's entries as MDX.
56
+ */
53
57
  serializers?: Record<string, (block: PortableTextBlock) => string>;
54
58
  }
55
59
 
@@ -62,18 +66,6 @@ const HEADING_STYLES = new Map([
62
66
  ["h6", "###### "],
63
67
  ]);
64
68
 
65
- // Markdown/raw-HTML structure characters. Portable Text spans are *plain
66
- // text* — formatting arrives as marks, never as syntax in the text — so a
67
- // literal `*`, `_`, `[`, backtick, `~`, or `<` typed in the CMS must render
68
- // as itself. Unescaped, it opened emphasis or a code span mid-paragraph, and
69
- // `<` let CMS prose inject raw HTML into the rendered page. CommonMark
70
- // backslash-escapes every ASCII punctuation character, so `\*` is always the
71
- // literal asterisk.
72
- const MARKDOWN_SPECIALS = /[\\`*_[\]~<]/gu;
73
-
74
- const escapeText = (text: string): string =>
75
- text.replaceAll(MARKDOWN_SPECIALS, String.raw`\$&`);
76
-
77
69
  /** Wrap a span's text in Markdown for its marks (decorators + link defs). */
78
70
  const renderSpan = (
79
71
  span: PortableTextSpan,
@@ -82,7 +74,7 @@ const renderSpan = (
82
74
  // Code spans stay verbatim: their text is literal inside the backticks,
83
75
  // and backslash escapes would render as backslashes.
84
76
  const isCode = span.marks?.includes("code") ?? false;
85
- let text = isCode ? (span.text ?? "") : escapeText(span.text ?? "");
77
+ let text = isCode ? (span.text ?? "") : escapeMarkdownText(span.text ?? "");
86
78
  if (!span.marks || span.marks.length === 0) {
87
79
  return text;
88
80
  }
@@ -140,10 +132,13 @@ const renderBlock = (
140
132
  if (block._type === "image") {
141
133
  const url = options.imageUrl?.(block);
142
134
  const alt = isAltText(block.alt) ? block.alt : "";
143
- return url ? `![${alt}](${url})` : "";
135
+ return url ? image(alt, url) : "";
144
136
  }
145
137
  if (block._type !== "block") {
146
- return `<!-- unsupported Portable Text block: ${block._type} -->`;
138
+ return unsupported(
139
+ `Portable Text block: ${block._type}`,
140
+ writesMdx(options.serializers)
141
+ );
147
142
  }
148
143
 
149
144
  const inline = renderChildren(block);
@@ -0,0 +1,226 @@
1
+ import { join } from "pathe";
2
+
3
+ import matter from "../frontmatter.ts";
4
+ import {
5
+ hashText,
6
+ loadWithCache,
7
+ pollingWatch,
8
+ snapshotCache,
9
+ } from "./cache.ts";
10
+ import type { JsonObject, JsonValue } from "./json.ts";
11
+ import { asString, getPath, isStringValue } from "./json.ts";
12
+ import { slugify, slugifyPath } from "./normalize.ts";
13
+ import type {
14
+ ContentSource,
15
+ SourceContext,
16
+ SourceEntry,
17
+ SourceLoadResult,
18
+ } from "./types.ts";
19
+
20
+ /** What every REST-backed CMS source needs to be a staged, cached source. */
21
+ export interface RemoteSourceOptions {
22
+ /** Pull every entry from the API; called on refresh and on each poll. */
23
+ fetchEntries: () => Promise<SourceEntry[]>;
24
+ name: string;
25
+ /** Opt-in dev polling interval (seconds); omit to freeze for the session. */
26
+ pollInterval?: number;
27
+ prefix?: string;
28
+ }
29
+
30
+ /**
31
+ * The staged-source scaffolding a CMS adapter shares: a snapshot cache under
32
+ * `.blume/cache/<source>/` (or a name-derived dir when constructed directly
33
+ * as a custom source, without a context), cache-first dev loads, offline
34
+ * fallback, `read()` for raw export, and an opt-in polling `watch`.
35
+ */
36
+ export const remoteSource = (
37
+ options: RemoteSourceOptions,
38
+ ctx?: SourceContext
39
+ ): ContentSource => {
40
+ const cache = snapshotCache(
41
+ ctx?.cacheDir ?? join(".blume", "cache", options.name)
42
+ );
43
+ let snapshot = new Map<string, SourceEntry>();
44
+
45
+ const load = async (
46
+ refresh = ctx?.refresh ?? true
47
+ ): Promise<SourceLoadResult> => {
48
+ const result = await loadWithCache(
49
+ options.name,
50
+ cache,
51
+ options.fetchEntries,
52
+ refresh
53
+ );
54
+ snapshot = new Map(result.entries.map((entry) => [entry.ref, entry]));
55
+ return result;
56
+ };
57
+
58
+ const read = async (ref: string): Promise<string> => {
59
+ const cached = snapshot.get(ref);
60
+ if (cached) {
61
+ return cached.raw ?? cached.body.text;
62
+ }
63
+ const all = await cache.read();
64
+ return all.find((entry) => entry.ref === ref)?.raw ?? "";
65
+ };
66
+
67
+ return {
68
+ load,
69
+ name: options.name,
70
+ prefix: options.prefix,
71
+ read,
72
+ staged: true,
73
+ watch: options.pollInterval
74
+ ? pollingWatch(
75
+ () => load(true),
76
+ options.pollInterval,
77
+ () => load()
78
+ )
79
+ : undefined,
80
+ };
81
+ };
82
+
83
+ /** The frontmatter a CMS document maps to. */
84
+ export interface RemoteFrontmatter {
85
+ description?: string;
86
+ draft?: boolean;
87
+ title?: string;
88
+ }
89
+
90
+ /**
91
+ * A staged entry: Markdown body plus the frontmatter it was mapped from,
92
+ * written as `.mdx` when the body carries serializer output (see
93
+ * `writesMdx`).
94
+ */
95
+ export const stagedEntry = (
96
+ slug: string,
97
+ data: RemoteFrontmatter,
98
+ markdown: string,
99
+ lastModified: string | undefined,
100
+ format: "md" | "mdx" = "md"
101
+ ): SourceEntry => {
102
+ const raw = matter.stringify(markdown, data);
103
+ return {
104
+ body: { format, text: markdown },
105
+ // Spread into a fresh literal: `SourceEntry.data` wants an
106
+ // index-signature type, which the named interface lacks.
107
+ data: { ...data },
108
+ hash: hashText(raw),
109
+ lastModified,
110
+ raw,
111
+ ref: `${slug}.${format}`,
112
+ };
113
+ };
114
+
115
+ /** How a source calls its CMS: the API's auth headers and an injectable fetch. */
116
+ export interface RestClient {
117
+ /** Injected for tests; defaults to the global `fetch`. */
118
+ fetchImpl?: typeof fetch;
119
+ headers?: Record<string, string>;
120
+ }
121
+
122
+ /**
123
+ * How long one CMS request may take before the source gives up on it. A
124
+ * stalled CMS would otherwise hold `scanProject()` — and every `blume dev`
125
+ * rescan — indefinitely, and the cache fallback can only kick in once the
126
+ * request rejects.
127
+ */
128
+ export const REMOTE_TIMEOUT_MS = 30_000;
129
+
130
+ /**
131
+ * GET a JSON endpoint. A non-2xx response is an error naming the status, so
132
+ * the source's cache fallback reports why (`401 Unauthorized`) instead of a
133
+ * parse failure on an error body; a request past {@link REMOTE_TIMEOUT_MS}
134
+ * rejects with a `TimeoutError`.
135
+ */
136
+ export const fetchJson = async (
137
+ url: string,
138
+ client: RestClient
139
+ ): Promise<JsonValue> => {
140
+ const doFetch = client.fetchImpl ?? globalThis.fetch;
141
+ const res = await doFetch(url, {
142
+ headers: { accept: "application/json", ...client.headers },
143
+ signal: AbortSignal.timeout(REMOTE_TIMEOUT_MS),
144
+ });
145
+ if (!res.ok) {
146
+ throw new Error(`${url} responded ${res.status} ${res.statusText}`.trim());
147
+ }
148
+ // SAFETY: the endpoint answered 2xx with a JSON body; whatever shape it
149
+ // holds is narrowed by the caller's predicates before use.
150
+ return (await res.json()) as JsonValue;
151
+ };
152
+
153
+ /** A query string from the fixed params plus a user's extra ones. */
154
+ export const queryString = (
155
+ params: Record<string, string | undefined>
156
+ ): string => {
157
+ const search = new URLSearchParams();
158
+ for (const [key, value] of Object.entries(params)) {
159
+ if (value !== undefined) {
160
+ search.set(key, value);
161
+ }
162
+ }
163
+ return search.toString();
164
+ };
165
+
166
+ /** Field paths mapping a CMS document onto Blume meta + body. */
167
+ export interface RemoteFieldMap {
168
+ /** Field holding the renderable body (rich text, or a Markdown string). */
169
+ body?: string;
170
+ /** Field holding the page description. */
171
+ description?: string;
172
+ /** Field holding the last-modified ISO date. */
173
+ lastModified?: string;
174
+ /** Field holding the route slug. */
175
+ slug?: string;
176
+ /** Field holding the page title. */
177
+ title?: string;
178
+ }
179
+
180
+ /**
181
+ * Map a document to a staged entry. The slug falls back to the document's id
182
+ * when the slug field is missing or slugifies to nothing (pure punctuation),
183
+ * so distinct documents never collapse onto one `untitled.md`; a slashed
184
+ * slug keeps its segments. A string body is Markdown and passes through as
185
+ * `.md`; any other shape goes to the CMS's lowerer, and is written as `.mdx`
186
+ * when `lowersToMdx` (the source has serializers, see `writesMdx`).
187
+ */
188
+ export const documentEntry = (
189
+ doc: JsonObject,
190
+ fields: Required<RemoteFieldMap>,
191
+ id: string,
192
+ lower: (body: JsonValue) => string,
193
+ draft = false,
194
+ lowersToMdx = false
195
+ ): SourceEntry => {
196
+ const slugValue = asString(getPath(doc, fields.slug)) ?? id;
197
+ const slug = slugifyPath(slugValue) || slugify(id) || "untitled";
198
+ const data: RemoteFrontmatter = {};
199
+ const title = asString(getPath(doc, fields.title));
200
+ const description = asString(getPath(doc, fields.description));
201
+ if (title) {
202
+ data.title = title;
203
+ }
204
+ if (description) {
205
+ data.description = description;
206
+ }
207
+ if (draft) {
208
+ data.draft = true;
209
+ }
210
+ const body = getPath(doc, fields.body);
211
+ let markdown = "";
212
+ let format: "md" | "mdx" = "md";
213
+ if (isStringValue(body)) {
214
+ markdown = `${body.trimEnd()}\n`;
215
+ } else if (body !== undefined) {
216
+ markdown = lower(body);
217
+ format = lowersToMdx ? "mdx" : "md";
218
+ }
219
+ return stagedEntry(
220
+ slug,
221
+ data,
222
+ markdown,
223
+ asString(getPath(doc, fields.lastModified)),
224
+ format
225
+ );
226
+ };