blume 2.0.3 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +142 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
- package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
- package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
- package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
- package/dist/cli/chunk-313vnn40.js.map +10 -0
- package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
- package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
- package/dist/cli/chunk-3x6x3pph.js.map +10 -0
- package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
- package/dist/cli/chunk-42t4jxdx.js.map +12 -0
- package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
- package/dist/cli/chunk-54ztw1nj.js.map +10 -0
- package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
- package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
- package/dist/cli/chunk-66w9j7p6.js +322 -0
- package/dist/cli/chunk-66w9j7p6.js.map +14 -0
- package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
- package/dist/cli/chunk-7ppf1rva.js.map +10 -0
- package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
- package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
- package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
- package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
- package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
- package/dist/cli/chunk-cfyg47zg.js.map +10 -0
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
- package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
- package/dist/cli/chunk-e6atmn4h.js.map +36 -0
- package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
- package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
- package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
- package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
- package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
- package/dist/cli/chunk-ehweg4fr.js.map +218 -0
- package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
- package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
- package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
- package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
- package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
- package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
- package/dist/cli/chunk-gb420vvz.js.map +17 -0
- package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
- package/dist/cli/chunk-hebn0tpx.js.map +14 -0
- package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
- package/dist/cli/chunk-htrwgabr.js.map +15 -0
- package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
- package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
- package/dist/cli/chunk-j134vrp2.js +65 -0
- package/dist/cli/chunk-j134vrp2.js.map +10 -0
- package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
- package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
- package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
- package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
- package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
- package/dist/cli/chunk-ncj7w596.js.map +35 -0
- package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
- package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
- package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
- package/dist/cli/chunk-nrns10mj.js.map +10 -0
- package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
- package/dist/cli/chunk-t2m5j4pr.js +104 -0
- package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
- package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
- package/dist/cli/chunk-tphac74f.js +126 -0
- package/dist/cli/chunk-tphac74f.js.map +11 -0
- package/dist/cli/chunk-w1r4vase.js +18 -0
- package/dist/cli/chunk-w1r4vase.js.map +10 -0
- package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
- package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
- package/dist/cli/index.js +31 -20
- package/dist/cli/index.js.map +5 -5
- package/dist/types/ai/agent-surface.d.ts +8 -7
- package/dist/types/ai/ai-catalog.d.ts +7 -0
- package/dist/types/ai/ask-context.d.ts +26 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +16 -0
- package/dist/types/astro/integration.d.ts +9 -0
- package/dist/types/astro/markdown-negotiation.d.ts +3 -0
- package/dist/types/astro/pages.d.ts +10 -0
- package/dist/types/captcha/hcaptcha.d.ts +27 -0
- package/dist/types/captcha/index.d.ts +28 -0
- package/dist/types/captcha/schema.d.ts +29 -0
- package/dist/types/captcha/turnstile.d.ts +28 -0
- package/dist/types/cli/init/scaffold.d.ts +1 -1
- package/dist/types/components/content/api-field.d.ts +62 -0
- package/dist/types/components/content/api-page.d.ts +100 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/code-samples.d.ts +29 -0
- package/dist/types/components/openapi/helpers.d.ts +158 -0
- package/dist/types/components/openapi/security.d.ts +95 -0
- package/dist/types/components/openapi/snippets.d.ts +60 -0
- package/dist/types/consent/ethyca.d.ts +48 -0
- package/dist/types/consent/index.d.ts +37 -0
- package/dist/types/consent/native.d.ts +28 -0
- package/dist/types/consent/osano.d.ts +42 -0
- package/dist/types/consent/schema.d.ts +110 -0
- package/dist/types/core/changelog-index.d.ts +8 -0
- package/dist/types/core/config-input.d.ts +217 -23
- package/dist/types/core/data.d.ts +53 -4
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/i18n-ui.d.ts +88 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/links.d.ts +8 -0
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/probe.d.ts +2 -0
- package/dist/types/core/project-graph.d.ts +6 -0
- package/dist/types/core/redirect-patterns.d.ts +152 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +670 -56
- package/dist/types/core/sources/cache.d.ts +3 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
- package/dist/types/core/sources/contentful.d.ts +17 -1
- package/dist/types/core/sources/lexical.d.ts +5 -0
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/sources/remote.d.ts +37 -10
- package/dist/types/core/sources/sanity.d.ts +1 -1
- package/dist/types/core/types.d.ts +18 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/adapter-output.d.ts +2 -1
- package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
- package/dist/types/deploy/adapters/node.d.ts +58 -23
- package/dist/types/deploy/adapters/registry.d.ts +10 -0
- package/dist/types/deploy/adapters/types.d.ts +3 -2
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/node.d.ts +3 -1
- package/dist/types/deploy/platforms/types.d.ts +18 -7
- package/dist/types/deploy/platforms/vercel.d.ts +26 -1
- package/dist/types/deploy/redirects.d.ts +55 -11
- package/dist/types/deploy/sitemap.d.ts +2 -1
- package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/features.d.ts +3 -2
- package/dist/types/narration/build.d.ts +70 -0
- package/dist/types/narration/provider.d.ts +26 -0
- package/dist/types/narration/script.d.ts +154 -0
- package/dist/types/openapi/checks.d.ts +27 -0
- package/dist/types/openapi/graphql.d.ts +6 -0
- package/dist/types/openapi/model.d.ts +27 -10
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +16 -0
- package/dist/types/openapi/references.d.ts +30 -4
- package/dist/types/ratelimit/cloudflare.d.ts +39 -0
- package/dist/types/ratelimit/index.d.ts +27 -0
- package/dist/types/ratelimit/memory.d.ts +36 -0
- package/dist/types/ratelimit/schema.d.ts +119 -0
- package/dist/types/ratelimit/upstash.d.ts +46 -0
- package/dist/types/ratelimit/wrangler.d.ts +23 -0
- package/dist/types/reference/asyncapi.d.ts +10 -10
- package/dist/types/reference/graphql.d.ts +89 -11
- package/dist/types/reference/index.d.ts +1 -1
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +82 -6
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +144 -36
- package/dist/types/search/adapters/registry.d.ts +3 -0
- package/dist/types/search/adapters/typesense.d.ts +14 -4
- package/dist/types/search/build.d.ts +3 -1
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +13 -9
- package/dist/types/search/sync/algolia.d.ts +5 -2
- package/dist/types/search/sync/index.d.ts +3 -1
- package/dist/types/search/sync/typesense.d.ts +11 -7
- package/dist/types/seo/metatags.d.ts +20 -0
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +54 -0
- package/dist/types/sources/shared.d.ts +3 -0
- package/dist/types/sources/strapi.d.ts +2 -0
- package/docs/01-quickstart.mdx +4 -2
- package/docs/02-deployment.mdx +71 -17
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/advanced/changelog.mdx +13 -2
- package/docs/advanced/skills.mdx +15 -1
- package/docs/cli/audit.mdx +51 -8
- package/docs/cli/doctor.mdx +5 -1
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +1 -0
- package/docs/cli/translate.mdx +1 -0
- package/docs/cli/validate.mdx +4 -3
- package/docs/configuration/analytics.mdx +3 -1
- package/docs/configuration/assistant.mdx +194 -38
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +8 -6
- package/docs/configuration/export.mdx +5 -3
- package/docs/configuration/index.mdx +64 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +90 -0
- package/docs/configuration/search.mdx +63 -12
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +108 -2
- package/docs/content/frontmatter.mdx +80 -2
- package/docs/content/i18n.mdx +39 -4
- package/docs/content/includes.mdx +16 -0
- package/docs/content/meta.mdx +1 -0
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +32 -10
- package/docs/content/sources/contentful.mdx +35 -0
- package/docs/content/sources/custom.mdx +43 -0
- package/docs/content/sources/github-releases.mdx +39 -0
- package/docs/content/sources/index.mdx +91 -0
- package/docs/content/sources/meta.ts +16 -0
- package/docs/content/sources/notion.mdx +32 -0
- package/docs/content/sources/obsidian.mdx +37 -0
- package/docs/content/sources/payload.mdx +31 -0
- package/docs/content/sources/remote-mdx.mdx +44 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +32 -0
- package/docs/content/syntax.mdx +69 -4
- package/docs/content/variables.mdx +41 -0
- package/docs/discoverability/agent-discovery.mdx +29 -2
- package/docs/discoverability/index.mdx +2 -2
- package/docs/discoverability/json-api.mdx +2 -0
- package/docs/discoverability/llms-txt.mdx +2 -2
- package/docs/discoverability/markdown.mdx +3 -1
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +4 -2
- package/docs/references/graphql.mdx +14 -2
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +148 -7
- package/docs/references/scalar.mdx +3 -1
- package/package.json +43 -8
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +7 -7
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +10 -7
- package/skills/blume-migrate/references/starlight.md +11 -8
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +2 -1
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +6 -3
- package/src/ai/ask-context.ts +103 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-limits.ts +13 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/changelog-markdown.ts +11 -6
- package/src/ai/component-markdown.ts +76 -1
- package/src/ai/cors.ts +14 -3
- package/src/ai/index.ts +12 -0
- package/src/ai/llms.ts +6 -2
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/mcp/query.ts +14 -6
- package/src/ai/openapi-components.ts +36 -6
- package/src/ai/relative-links.ts +4 -38
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +35 -2
- package/src/ai/write-skill.ts +97 -0
- package/src/astro/generate.ts +210 -66
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +42 -4
- package/src/astro/markdown-negotiation.ts +3 -0
- package/src/astro/module-types.ts +9 -1
- package/src/astro/pages.ts +23 -0
- package/src/astro/templates.ts +406 -108
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +38 -3
- package/src/audit/checks/contrast.ts +183 -0
- package/src/audit/checks/i18n.ts +2 -3
- package/src/audit/checks/indexability.ts +2 -3
- package/src/audit/checks/links.ts +19 -13
- package/src/audit/checks/network.ts +110 -6
- package/src/audit/checks/redirects.ts +6 -4
- package/src/audit/checks/robots.ts +58 -2
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +5 -0
- package/src/audit/types.ts +4 -1
- package/src/audit/url.ts +14 -5
- package/src/blume-modules.d.ts +12 -1
- package/src/captcha/client.ts +152 -0
- package/src/captcha/hcaptcha.ts +36 -0
- package/src/captcha/index.ts +28 -0
- package/src/captcha/schema.ts +32 -0
- package/src/captcha/turnstile.ts +38 -0
- package/src/captcha/verify.ts +71 -0
- package/src/cli/args.ts +51 -0
- package/src/cli/build-failure.ts +23 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/audit.ts +10 -1
- package/src/cli/commands/dev.ts +18 -2
- package/src/cli/commands/doctor.ts +67 -28
- package/src/cli/commands/eval.ts +36 -4
- package/src/cli/commands/init.ts +6 -4
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/commands/validate.ts +10 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/init/scaffold.ts +3 -3
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +72 -30
- package/src/components/BlumePage.astro +2 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +66 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Color.astro +1 -0
- package/src/components/content/FileTree.astro +1 -0
- package/src/components/content/GithubInfo.astro +1 -0
- package/src/components/content/Panel.astro +1 -0
- package/src/components/content/ParamField.astro +25 -0
- package/src/components/content/RequestExample.astro +17 -0
- package/src/components/content/ResponseExample.astro +17 -0
- package/src/components/content/ResponseField.astro +32 -0
- package/src/components/content/Step.astro +1 -0
- package/src/components/content/Tile.astro +1 -0
- package/src/components/content/Tooltip.astro +1 -0
- package/src/components/content/Tree.astro +1 -0
- package/src/components/content/TypeTable.astro +4 -1
- package/src/components/content/View.astro +21 -0
- package/src/components/content/ViewSwitcher.astro +168 -0
- package/src/components/content/api-field.ts +103 -0
- package/src/components/content/api-page.ts +248 -0
- package/src/components/content/mermaid-element.ts +15 -1
- package/src/components/content/view-switcher.ts +71 -0
- package/src/components/index.ts +2 -0
- package/src/components/islands/Assistant.astro +10 -1
- package/src/components/islands/assistant.tsx +104 -14
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +136 -21
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +6 -2
- package/src/components/layout/ConsentBanner.astro +62 -0
- package/src/components/layout/ConsentHead.astro +38 -0
- package/src/components/layout/Directory.astro +94 -0
- package/src/components/layout/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +122 -80
- package/src/components/layout/LanguageSwitcher.astro +48 -15
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +33 -7
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +71 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +318 -47
- package/src/components/layout/Search.astro +47 -19
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/TableOfContents.astro +24 -17
- package/src/components/layout/consent/native.ts +79 -0
- package/src/components/layout/consent/types.ts +37 -0
- package/src/components/layout/footer-links.ts +53 -0
- package/src/components/layout/footer-socials.ts +87 -0
- package/src/components/layout/head-scripts.ts +6 -1
- package/src/components/layout/locale-redirect.ts +107 -0
- package/src/components/layout/nav-utils.ts +83 -0
- package/src/components/layout/page-feedback.ts +96 -0
- package/src/components/layout/search/algolia.ts +10 -1
- package/src/components/layout/search/analytics.ts +126 -0
- package/src/components/layout/search/endpoint.ts +48 -5
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/pagefind.ts +114 -5
- package/src/components/layout/search/types.ts +32 -0
- package/src/components/layout/search/typesense.ts +19 -3
- package/src/components/openapi/AsyncApiOperation.astro +14 -7
- package/src/components/openapi/Authorization.astro +10 -0
- package/src/components/openapi/GraphqlOperation.astro +5 -0
- package/src/components/openapi/Operation.astro +184 -13
- package/src/components/openapi/ParametersTable.astro +8 -4
- package/src/components/openapi/Playground.astro +7 -1
- package/src/components/openapi/RequestBody.astro +24 -5
- package/src/components/openapi/RequestPanel.astro +59 -7
- package/src/components/openapi/Responses.astro +7 -4
- package/src/components/openapi/SchemaTable.astro +15 -3
- package/src/components/openapi/async-snippets.ts +65 -9
- package/src/components/openapi/async.ts +123 -29
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/graphql-helpers.ts +35 -12
- package/src/components/openapi/helpers.ts +36 -2
- package/src/components/openapi/message-model.ts +54 -11
- package/src/components/openapi/message.ts +14 -4
- package/src/components/openapi/operation-model.ts +16 -7
- package/src/components/openapi/playground-client.ts +24 -5
- package/src/components/openapi/playground-schema.ts +1 -1
- package/src/components/openapi/schema-tree.ts +44 -14
- package/src/components/openapi/security.ts +16 -3
- package/src/components/openapi/snippets.ts +873 -10
- package/src/components/openapi/validate-json.ts +4 -3
- package/src/components/props.ts +6 -0
- package/src/consent/client.ts +95 -0
- package/src/consent/clients.ts +19 -0
- package/src/consent/ethyca.ts +71 -0
- package/src/consent/head.ts +24 -0
- package/src/consent/index.ts +37 -0
- package/src/consent/init.ts +29 -0
- package/src/consent/native.ts +36 -0
- package/src/consent/osano.ts +59 -0
- package/src/consent/schema.ts +30 -0
- package/src/core/builtin-tags.ts +5 -0
- package/src/core/changelog-index.ts +31 -1
- package/src/core/client-address.ts +19 -0
- package/src/core/component-diagnostics.ts +53 -0
- package/src/core/component-overrides.ts +32 -0
- package/src/core/config-input.ts +225 -23
- package/src/core/data.ts +46 -4
- package/src/core/diagnostics.ts +8 -2
- package/src/core/footer.ts +26 -0
- package/src/core/graph.ts +39 -36
- package/src/core/i18n-ui.ts +84 -2
- package/src/core/includes.ts +21 -4
- package/src/core/links.ts +63 -19
- package/src/core/localizable.ts +26 -0
- package/src/core/navigation.ts +43 -12
- package/src/core/page-modes.ts +56 -0
- package/src/core/probe.ts +26 -6
- package/src/core/project-graph.ts +163 -16
- package/src/core/redirect-patterns.ts +520 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +339 -66
- package/src/core/sources/cache.ts +6 -0
- package/src/core/sources/contentful-rich-text.ts +29 -6
- package/src/core/sources/contentful.ts +135 -25
- package/src/core/sources/filesystem.ts +26 -4
- package/src/core/sources/github-releases.ts +12 -1
- package/src/core/sources/lexical.ts +15 -10
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +228 -41
- package/src/core/sources/notion.ts +7 -1
- package/src/core/sources/obsidian.ts +16 -3
- package/src/core/sources/payload.ts +38 -15
- package/src/core/sources/read.ts +8 -3
- package/src/core/sources/remote.ts +72 -15
- package/src/core/sources/resolve.ts +11 -1
- package/src/core/sources/sanity.ts +43 -25
- package/src/core/sources/strapi.ts +2 -2
- package/src/core/types.ts +19 -1
- package/src/core/ui-packs/ar.ts +44 -0
- package/src/core/ui-packs/bg.ts +46 -0
- package/src/core/ui-packs/bn.ts +44 -0
- package/src/core/ui-packs/ca.ts +47 -0
- package/src/core/ui-packs/cs.ts +45 -0
- package/src/core/ui-packs/da.ts +46 -0
- package/src/core/ui-packs/de.ts +47 -0
- package/src/core/ui-packs/el.ts +46 -0
- package/src/core/ui-packs/es.ts +47 -0
- package/src/core/ui-packs/fa.ts +46 -0
- package/src/core/ui-packs/fi.ts +46 -0
- package/src/core/ui-packs/fr.ts +47 -0
- package/src/core/ui-packs/he.ts +44 -0
- package/src/core/ui-packs/hi.ts +45 -0
- package/src/core/ui-packs/hr.ts +46 -0
- package/src/core/ui-packs/hu.ts +45 -0
- package/src/core/ui-packs/id.ts +46 -0
- package/src/core/ui-packs/it.ts +46 -0
- package/src/core/ui-packs/ja.ts +46 -0
- package/src/core/ui-packs/ko.ts +45 -0
- package/src/core/ui-packs/nl.ts +47 -0
- package/src/core/ui-packs/no.ts +45 -0
- package/src/core/ui-packs/pl.ts +46 -0
- package/src/core/ui-packs/pt-br.ts +47 -0
- package/src/core/ui-packs/pt.ts +46 -0
- package/src/core/ui-packs/ro.ts +46 -0
- package/src/core/ui-packs/ru.ts +46 -0
- package/src/core/ui-packs/sk.ts +45 -0
- package/src/core/ui-packs/sr.ts +46 -0
- package/src/core/ui-packs/sv.ts +45 -0
- package/src/core/ui-packs/th.ts +44 -0
- package/src/core/ui-packs/tr.ts +46 -0
- package/src/core/ui-packs/uk.ts +46 -0
- package/src/core/ui-packs/vi.ts +46 -0
- package/src/core/ui-packs/zh-tw.ts +44 -0
- package/src/core/ui-packs/zh.ts +44 -0
- package/src/core/variables.ts +103 -0
- package/src/deploy/adapter-output.ts +7 -2
- package/src/deploy/adapters/cloudflare.ts +7 -5
- package/src/deploy/adapters/node.ts +47 -9
- package/src/deploy/adapters/types.ts +7 -3
- package/src/deploy/artifacts.ts +79 -9
- package/src/deploy/cloudflare-negotiation.ts +35 -5
- package/src/deploy/headers.ts +2 -1
- package/src/deploy/node-headers.ts +63 -9
- package/src/deploy/platforms/cloudflare.ts +45 -9
- package/src/deploy/platforms/netlify.ts +35 -2
- package/src/deploy/platforms/node.ts +12 -2
- package/src/deploy/platforms/types.ts +21 -7
- package/src/deploy/platforms/vercel.ts +149 -17
- package/src/deploy/redirects.ts +151 -24
- package/src/deploy/rss.ts +3 -1
- package/src/deploy/sitemap.ts +39 -5
- package/src/deploy/vercel-negotiation.ts +326 -102
- package/src/eval/agents.ts +18 -1
- package/src/eval/prompts.ts +6 -3
- package/src/eval/report.ts +34 -13
- package/src/eval/run.ts +5 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/features.ts +3 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +28 -5
- package/src/markdown/math.ts +4 -4
- package/src/markdown/relative-links.ts +3 -2
- package/src/markdown/variables.ts +56 -0
- package/src/markdown/views.ts +82 -0
- package/src/narration/build.ts +412 -0
- package/src/narration/player.ts +249 -0
- package/src/narration/provider.ts +29 -0
- package/src/narration/script.ts +592 -0
- package/src/og/card.ts +7 -6
- package/src/openapi/checks.ts +273 -0
- package/src/openapi/graphql-build.ts +21 -0
- package/src/openapi/graphql.ts +11 -0
- package/src/openapi/model.ts +72 -27
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +182 -4
- package/src/openapi/references.ts +64 -8
- package/src/openapi/render-mdx.ts +5 -1
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +40 -15
- package/src/ratelimit/cloudflare.ts +54 -0
- package/src/ratelimit/index.ts +30 -0
- package/src/ratelimit/memory.ts +45 -0
- package/src/ratelimit/runtime.ts +247 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +60 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +20 -3
- package/src/reference/index.ts +1 -0
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +80 -8
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +23 -5
- package/src/registry/registry.ts +7 -0
- package/src/search/adapters/locale-scope.ts +30 -0
- package/src/search/adapters/typesense.ts +14 -4
- package/src/search/build.ts +21 -3
- package/src/search/documents.ts +26 -2
- package/src/search/orama-index.ts +191 -34
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/source-pages.ts +29 -0
- package/src/search/sync/algolia.ts +111 -10
- package/src/search/sync/index.ts +52 -13
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +76 -26
- package/src/seo/metatags.ts +67 -0
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/shared.ts +3 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +85 -6
- package/src/theme/palette.ts +121 -45
- package/src/translate/prompts.ts +1 -0
- package/src/translate/validate.ts +31 -3
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
- package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
- package/dist/cli/chunk-35d4wj9f.js.map +0 -15
- package/dist/cli/chunk-364znk6q.js +0 -75
- package/dist/cli/chunk-364znk6q.js.map +0 -11
- package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
- package/dist/cli/chunk-8ktnccpt.js.map +0 -10
- package/dist/cli/chunk-9t7a85s3.js.map +0 -10
- package/dist/cli/chunk-b07cmahc.js +0 -145
- package/dist/cli/chunk-b07cmahc.js.map +0 -11
- package/dist/cli/chunk-c8chx29p.js.map +0 -36
- package/dist/cli/chunk-e04dxsz1.js +0 -39
- package/dist/cli/chunk-e04dxsz1.js.map +0 -10
- package/dist/cli/chunk-j85vccga.js.map +0 -36
- package/dist/cli/chunk-p3v96n38.js.map +0 -10
- package/dist/cli/chunk-pehfxfta.js.map +0 -10
- package/dist/cli/chunk-pv29h0wf.js.map +0 -190
- package/dist/cli/chunk-q58y5e6a.js.map +0 -10
- package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
- package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
- package/dist/cli/chunk-yfyb25rh.js.map +0 -14
- package/docs/content/sources.mdx +0 -334
- /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
- /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
- /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
- /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
- /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
- /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
- /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
- /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.js.map} +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Content sources
|
|
3
|
+
description: Pull docs from local files, a remote repository, a CMS, or any custom backend — and mix several sources into one static-first site read at build time.
|
|
4
|
+
sidebar:
|
|
5
|
+
hidden: true
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
By default Blume reads a folder of `.md`/`.mdx` files. **Content sources** let you pull pages from somewhere else — a remote repository, a CMS, or any custom backend — and mix several sources into a single site. Sources are read at build time; Blume stays static-first.
|
|
9
|
+
|
|
10
|
+
## The default
|
|
11
|
+
|
|
12
|
+
With no configuration, Blume scans your content root (`docs` by default) as one filesystem source. The top-level `content.root`, `content.include`, and `content.exclude` options are shorthand for that single source — nothing to import, nothing to change.
|
|
13
|
+
|
|
14
|
+
```ts blume.config.ts
|
|
15
|
+
import { defineConfig } from "blume";
|
|
16
|
+
|
|
17
|
+
export default defineConfig({
|
|
18
|
+
content: { root: "docs" },
|
|
19
|
+
});
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Adapters
|
|
23
|
+
|
|
24
|
+
Each entry in `content.sources` is an **adapter**: a factory imported from `blume/sources` that returns a plain descriptor Blume reads at build time. Add a `sources` array to compose sources. When `sources` is present it replaces the implicit default, so include a `filesystem()` entry for your local docs — and move `root`, `include`, or `exclude` into it. The shorthand and `sources` can't be combined; Blume reports which field to move.
|
|
25
|
+
|
|
26
|
+
```ts blume.config.ts
|
|
27
|
+
import { defineConfig } from "blume";
|
|
28
|
+
import { filesystem, mdxRemote } from "blume/sources";
|
|
29
|
+
|
|
30
|
+
export default defineConfig({
|
|
31
|
+
content: {
|
|
32
|
+
sources: [
|
|
33
|
+
// Local docs at the site root
|
|
34
|
+
filesystem({ root: "docs" }),
|
|
35
|
+
|
|
36
|
+
// Remote MDX from a GitHub repo, mounted under /sdk
|
|
37
|
+
mdxRemote({
|
|
38
|
+
prefix: "sdk",
|
|
39
|
+
github: { owner: "acme", repo: "sdk", ref: "main", path: "docs" },
|
|
40
|
+
}),
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Beyond `filesystem()`, each built-in adapter has its own page, and [`custom()`](/docs/content/sources/custom) plugs in any other backend:
|
|
47
|
+
|
|
48
|
+
| Adapter | Reads | Runtime dependency | Environment variable |
|
|
49
|
+
| --- | --- | --- | --- |
|
|
50
|
+
| [`obsidian()`](/docs/content/sources/obsidian) | An Obsidian vault, in place | — | — |
|
|
51
|
+
| [`mdxRemote()`](/docs/content/sources/remote-mdx) | `.md`/`.mdx` from a GitHub repo or a raw URL | — | `GITHUB_TOKEN` (private repos) |
|
|
52
|
+
| [`githubReleases()`](/docs/content/sources/github-releases) | A repo's releases, as changelog entries | — | `GITHUB_TOKEN` (private repos) |
|
|
53
|
+
| [`sanity()`](/docs/content/sources/sanity) | A GROQ query over a Sanity dataset | `@sanity/client` | `SANITY_TOKEN` (private datasets) |
|
|
54
|
+
| [`notion()`](/docs/content/sources/notion) | A Notion database | `@notionhq/client` | `NOTION_TOKEN` |
|
|
55
|
+
| [`contentful()`](/docs/content/sources/contentful) | One Contentful content type | — | `CONTENTFUL_ACCESS_TOKEN` |
|
|
56
|
+
| [`payload()`](/docs/content/sources/payload) | A Payload collection | — | `PAYLOAD_API_KEY` |
|
|
57
|
+
| [`strapi()`](/docs/content/sources/strapi) | A Strapi content type | — | `STRAPI_API_TOKEN` |
|
|
58
|
+
| [`custom()`](/docs/content/sources/custom) | Any `ContentSource` you implement | — | — |
|
|
59
|
+
|
|
60
|
+
Every adapter that takes an options object accepts two shared options:
|
|
61
|
+
|
|
62
|
+
- **`prefix`** namespaces the source's routes under `/<prefix>/…`, which also becomes the source's name in diagnostics and its cache directory. If two sources resolve to the same route, Blume reports a `BLUME_DUPLICATE_ROUTE` build error — give each source a distinct `prefix`.
|
|
63
|
+
- **`pollInterval`** (seconds) makes a remote source re-fetch on that interval in dev, reloading only when the content actually changes. Leave it unset to fetch once and freeze for the session. Local sources (`filesystem()`, `obsidian()`) watch the filesystem instead and ignore it.
|
|
64
|
+
|
|
65
|
+
An adapter's descriptor also declares the SDK it needs and the environment variables it reads, so the generated project declares that package, `blume dev`, `blume build`, and `blume doctor` warn when a variable is unset, and `blume doctor` lists the configured sources. The warning prints before any source fetches, so it isn't lost when the fetch then fails. `notion()` and `contentful()` can't read anything without their token, so with it unset they stop before their first request with a `BLUME_MISSING_SECRET` error, and a source whose SDK isn't installed stops the same way with `BLUME_SOURCE_SDK_MISSING`; either serves its cached snapshot instead when it has one. Options are validated when the config loads: a missing required option, an unknown key, or a leftover 1.x `{ type: "…" }` object fails with a message naming the fix.
|
|
66
|
+
|
|
67
|
+
A single `filesystem()` source roots the generated docs collection at its own directory. Several filesystem sources must share one root and partition it with `include` globs — a second source rooted elsewhere is reported as `BLUME_ENTRY_ID_MISMATCH` so its pages can't silently 404.
|
|
68
|
+
|
|
69
|
+
## Caching and offline builds
|
|
70
|
+
|
|
71
|
+
Each remote source keeps a snapshot under `.blume/cache/<source>/`. If a fetch fails — a network blip or a CMS outage — Blume serves the last-known-good snapshot with a warning rather than failing the build. Preview and published content get separate snapshots, and so does each set of source options, so a build never falls back to drafts fetched under `--preview`, and editing a source's `query` or `fields` fetches afresh. A [`custom()`](/docs/content/sources/custom) source is the exception: its snapshot is kept per preview mode only, so after editing its options run `blume sync`. The cache lives inside `.blume/` and is regenerated, never committed.
|
|
72
|
+
|
|
73
|
+
In dev, a remote source is served from its snapshot when it has one, so restarting the dev server doesn't refetch it. Run `blume sync` to pull the latest content (a running dev server hot-reloads), or `blume sync --force` to drop the snapshots first. Local filesystem sources hot-reload as usual. To poll a remote source for changes instead, set the shared `pollInterval` option (seconds) on it — the dev server re-fetches on that interval and reloads only when the content actually changes. Leave it unset to avoid hitting the API while you work.
|
|
74
|
+
|
|
75
|
+
## Preview and sync
|
|
76
|
+
|
|
77
|
+
Two flags control how remote content is fetched and what's included:
|
|
78
|
+
|
|
79
|
+
- **`--preview`** on `blume dev` or `blume build` renders drafts and pulls unpublished CMS content — Sanity switches to its `previewDrafts` perspective, Contentful reads through the Preview API, and Payload and Strapi request drafts. Notion always reads every page and stages the ones whose `Status` isn't published as drafts, so `blume dev` shows them with or without the flag, and `blume build --preview` renders them. Production builds without the flag exclude drafts as usual, so a preview build is a safe way to review unpublished work before it ships.
|
|
80
|
+
- **`blume sync`** re-fetches every remote source and regenerates the runtime. Dev is cache-first — a remote source is fetched once and served from `.blume/cache` on restart (fast and offline-tolerant), so `blume sync` is how you pull the latest CMS content without restarting the dev server (a running server hot-reloads). Add `--force` to drop the cache first, or set `pollInterval` on a source to refresh automatically.
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
blume dev --preview # author workflow: see drafts live
|
|
84
|
+
blume build --preview # render a full preview build
|
|
85
|
+
blume sync # refresh remote content now
|
|
86
|
+
blume sync --force # ...ignoring any cached snapshot
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Rendering and escaping
|
|
90
|
+
|
|
91
|
+
A source normalizes its native shape (Portable Text, Notion blocks, remote HTML) to Markdown/MDX text, so the same components and markdown features apply no matter where a page comes from. The built-in adapters escape rich text as they lower it, so what an author typed in the CMS — a `{`, a `<b>`, a paragraph starting with `import`, or `©` — renders as written. Links keep only `http(s)`, `mailto:`, `tel:`, and relative targets; any other scheme (`javascript:`, `data:`) renders as the link's text, and SVG images a source downloads are served sandboxed. Release notes from `githubReleases()` and files from `mdxRemote()` are treated as your own content: their raw HTML renders as written, so point them only at repositories you trust.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineMeta } from "blume";
|
|
2
|
+
|
|
3
|
+
export default defineMeta({
|
|
4
|
+
pages: [
|
|
5
|
+
"obsidian",
|
|
6
|
+
"remote-mdx",
|
|
7
|
+
"github-releases",
|
|
8
|
+
"sanity",
|
|
9
|
+
"notion",
|
|
10
|
+
"contentful",
|
|
11
|
+
"payload",
|
|
12
|
+
"strapi",
|
|
13
|
+
"custom",
|
|
14
|
+
],
|
|
15
|
+
title: "Content sources",
|
|
16
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Notion
|
|
3
|
+
description: Import a Notion database with the notion() source — rows become pages, properties become frontmatter, and blocks become Blume components.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The built-in `notion()` adapter turns a Notion database into a collection: each row becomes a page, its properties become frontmatter, and its block tree becomes MDX. Callouts, toggles, columns, and code blocks map to the matching Blume components, and the text you type in Notion renders as written: a `{`, `<`, or Markdown character in a page is escaped rather than read as MDX, JSX, or formatting. Video blocks become a `<YouTube>` embed when they hold a YouTube link and a `<video>` player otherwise, with the block's caption as a `<Frame>` caption either way. A link to a video page rather than a media file (a Vimeo or Loom URL, say) is reported as a build warning, and its `<video>` player keeps pointing at the page, which it can't play — link to that video from the text instead. The adapter declares `@notionhq/client` (v5 or later) as its runtime dependency — an optional peer; Blume reads the database through its first data source.
|
|
7
|
+
|
|
8
|
+
```ts blume.config.ts
|
|
9
|
+
import { defineConfig } from "blume";
|
|
10
|
+
import { filesystem, notion } from "blume/sources";
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
content: {
|
|
14
|
+
sources: [
|
|
15
|
+
filesystem({ root: "docs" }),
|
|
16
|
+
notion({
|
|
17
|
+
prefix: "handbook",
|
|
18
|
+
database: "8f2c1e0a4b7d4f3c9e6a5d2b1c0f9e8d", // the id in the database URL
|
|
19
|
+
// Property names default to the title-typed prop / Description / Slug / Order / Status
|
|
20
|
+
// Pages whose Status isn't publishedValue (default "Published") import as drafts
|
|
21
|
+
publishedValue: "Done",
|
|
22
|
+
}),
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The integration token comes from the `NOTION_TOKEN` environment variable (share the database with your integration). Without it, the source stops before calling Notion with a `BLUME_MISSING_SECRET` error naming the variable, unless it has a [cached snapshot](/docs/content/sources#caching-and-offline-builds) to serve instead.
|
|
29
|
+
|
|
30
|
+
The `Status` property is a publish gate by default. A page whose Status (a status or select property) holds any value other than `publishedValue`, which defaults to `Published`, imports with `draft: true`, and production builds drop drafts. A page with no Status value is published, and a database without the property publishes every page. Notion's default status options are Not started, In progress, and Done, so a database that uses them has no `Published` value and publishes nothing until you set `publishedValue: "Done"` (or whichever option means published). `properties.status` names a differently named property; to import every page whatever its status, point it at a property the database doesn't have.
|
|
31
|
+
|
|
32
|
+
**Notion image and video URLs are signed and expire**, so the adapter downloads them at build time into the site's assets and rewrites the references — a CMS asset never rots a static build. Only a file the server reports as an image or video is saved (or, when the response doesn't say, one whose URL names an image or video extension); anything else keeps its original URL with a build warning, so nothing but media is ever served from your site's origin. API calls are paced through a small request pool (3 at a time, matching Notion's per-integration rate limit) so databases with hundreds of pages import without tripping `429` responses; set `concurrency` on the source to tune it.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Obsidian
|
|
3
|
+
description: Publish an Obsidian vault in place with the obsidian() source — wikilinks, properties, and vault images resolve at build time, with no export step.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The built-in `obsidian()` adapter reads an [Obsidian](https://obsidian.md) vault in place. There is no export step and nothing generated into your repo: the vault stays the source of truth, and Blume lowers Obsidian's dialect to Markdown as it loads.
|
|
7
|
+
|
|
8
|
+
```ts blume.config.ts
|
|
9
|
+
import { defineConfig } from "blume";
|
|
10
|
+
import { filesystem, obsidian } from "blume/sources";
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
content: {
|
|
14
|
+
sources: [
|
|
15
|
+
filesystem({ root: "docs" }),
|
|
16
|
+
obsidian({
|
|
17
|
+
prefix: "notes",
|
|
18
|
+
vault: "vault",
|
|
19
|
+
// Vault folder names to skip at any depth, on top of dot-folders
|
|
20
|
+
exclude: ["Templates", "Daily"],
|
|
21
|
+
}),
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`[[Wikilinks]]` become route links, addressed by note name across the whole vault rather than by path, the way Obsidian addresses notes. Custom link text (`[[Note|label]]`), heading anchors (`[[Note#Install]]`), full paths (`[[folder/Note]]` and `[[folder/Note.md]]`), the partial paths Obsidian's default "shortest path when possible" setting writes (`[[guides/Note]]`), and the `[[Note\|label]]` form Obsidian writes inside a table cell all work, and a note that sets `slug` in its frontmatter is linked at the route that slug publishes. When two notes share a name, a note whose full vault path is exactly that name wins — Obsidian resolves a link as a path before a name — then the first in vault order (folders before notes, case-insensitively, like Obsidian's file explorer). Blume warns only when a wikilink actually resolves through such a collision; write a longer path to disambiguate. A block reference (`[[Note#^id]]`) links to its note without an anchor: blocks render with no id to land on. A heading anchor resolves against the target note's real headings, matched the way Obsidian's autocomplete writes them (with `**bold**`, `` `code` ``, and link syntax stripped) and slugged by the same `extractHeadings` pass that fills the page manifest — so a link to `#Install` lands on the heading rather than on an id no page emits. `[[#Install]]` addresses a heading in the note you are writing. A link to a heading that doesn't exist keeps the page link, drops the anchor, and warns.
|
|
28
|
+
|
|
29
|
+
Frontmatter keeps what Blume's [page schema](/docs/content/frontmatter) accepts plus any key you declare in [`frontmatter.extend`](/docs/content/frontmatter#custom-keys) (or, for notes of that `type`, a content type's `frontmatter`); every other Obsidian property — Dataview fields, Templater dates, `publish`, and Obsidian's own `tags`, `aliases`, and `cssclasses` — is dropped when a note is lowered, so a vault written with the Properties UI builds without frontmatter errors. `aliases` is dropped rather than resolved — alias link targets are not supported yet. A relative Markdown image beside a note (``) is served from the vault, and when the vault lives inside your git repository, vault pages get git-derived ["Last updated" dates](/docs/configuration#last-modified) like any other page. "Edit this page" links resolve through `github.dir`, so a vault that sits beside the docs app in a monorepo still links to its file; a vault outside the repository gets no link.
|
|
30
|
+
|
|
31
|
+
Locale directories and version snapshots inside the vault are read the same way the filesystem source reads them: `fr/Note.md` publishes under `/fr/` with [i18n](/docs/content/i18n) configured, `v1.0/Note.md` under `/v1.0/` with [versions](/docs/content/versioning), and wikilinks to those notes point at the route each one publishes.
|
|
32
|
+
|
|
33
|
+
A link to an `index` note lands on its folder's route rather than a phantom `/index`. **An unresolved wikilink degrades to plain text with a build warning instead of failing the build**, so a vault mid-refactor still publishes. Single-line `%%comments%%` are stripped, a wikilink inside an HTML comment (`<!-- [[Draft]] -->`) is left alone since Obsidian hides it too, and a note with no `title` in its frontmatter is titled by its filename — the same rule Obsidian itself applies. An `index` note is the one exception: it names a route rather than a note, so its title falls through to Blume's usual derivation (first heading, then the humanized segment). Fenced, indented, and inline code passes through verbatim, so a note documenting the syntax survives.
|
|
34
|
+
|
|
35
|
+
Dot-folders are skipped, including Obsidian's own `.obsidian` config directory and `.trash` — which the dev watcher also ignores, so moving a pane in the app doesn't rebuild your site. Editing a note does, and so does deleting one to the trash, since the note leaves the vault. The directories no content scan reads (`node_modules`, `dist`, `.git`, …) are skipped too, so a vault rooted at the project itself doesn't publish dependency READMEs. A note with `#` or `?` in its path is left out with an error, the way a [content file](/docs/content#files-and-routes) is: Astro can't load its copy, so rename it. Symlinks inside the vault are followed, the way the filesystem source follows them, so a shared folder linked into the vault publishes with it. A vault that sits inside the filesystem source's root must be excluded from it (`filesystem({ root: "docs", exclude: ["**/_*", "**/.*", "vault/**"] })` — an `exclude` replaces the default `["**/_*", "**/.*"]` rather than adding to it, so keep those two to leave `_`-prefixed partials and dot-files unpublished); [`blume version <id>`](/docs/cli/version) then leaves it out of the snapshot, since the vault keeps publishing its own notes as current.
|
|
36
|
+
|
|
37
|
+
Not yet lowered: callouts (`> [!note]`) render as plain blockquotes, embeds (`![[image.png]]`) pass through untouched, multi-line `%%comments%%` are left in place, and there is no backlink graph.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Payload
|
|
3
|
+
description: Read a Payload collection through its REST API with the payload() source, lowering Lexical rich text bodies to Markdown with nothing to install.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The built-in `payload()` adapter reads a collection through the Payload REST API (`/api/<collection>`) and lowers each document's Lexical body to Markdown: paragraphs, headings, bullet, numbered, and check lists, quotes, links, uploads, and horizontal rules. A body held in a text field passes through as Markdown, except that a link that isn't a web, mail, phone, or relative address keeps only its label. Nothing to install.
|
|
7
|
+
|
|
8
|
+
```ts blume.config.ts
|
|
9
|
+
import { defineConfig } from "blume";
|
|
10
|
+
import { filesystem, payload } from "blume/sources";
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
content: {
|
|
14
|
+
sources: [
|
|
15
|
+
filesystem({ root: "docs" }),
|
|
16
|
+
payload({
|
|
17
|
+
prefix: "handbook",
|
|
18
|
+
url: "https://cms.example.com",
|
|
19
|
+
collection: "docs",
|
|
20
|
+
// Field paths default to title / description / slug / content /
|
|
21
|
+
// updatedAt; order (no default) sets the sidebar order
|
|
22
|
+
fields: { body: "richText" },
|
|
23
|
+
// Extra query parameters: where[...], sort
|
|
24
|
+
params: { sort: "title" },
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The API key comes from the `PAYLOAD_API_KEY` environment variable and is sent as `users API-Key <key>`; set `authCollection` when the key belongs to another auth-enabled collection. Only published documents are imported — `--preview` requests drafts and stages them with `draft: true`. Documents are fetched with `depth: 1` so uploads carry their URLs, and a relative upload path (`/media/x.png`) resolves against `url`. Uploads are referenced at that URL rather than downloaded, since it doesn't expire the way Notion's do, so readers' browsers load them from your Payload server or its storage; to have Blume download and optimize them at build instead, authorize the host in [`image.domains`](/docs/configuration#images). A `block` or `inlineBlock` node maps to a Blume component through the engine's `serializers` option, keyed by `blockType`, when you construct `payloadSource` directly and pass it to [`custom()`](/docs/content/sources/custom). Setting `serializers` writes the source's pages as MDX so the returned components render; a body held in a Markdown text field stays Markdown. A node with no Markdown equivalent, or a block with no serializer, is left out as a comment, and the source warns with `BLUME_SOURCE_UNSUPPORTED_NODE` naming it and the page.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Remote MDX
|
|
3
|
+
description: Fetch Markdown and MDX over HTTP from a GitHub repository or a raw URL with the mdxRemote() source, rendered with every Blume component.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The built-in `mdxRemote()` adapter fetches raw `.md`/`.mdx` over HTTP. Enumerate files either from a GitHub repo subtree (`github`) or explicitly against a raw base URL (`url` + `files`):
|
|
7
|
+
|
|
8
|
+
```ts blume.config.ts
|
|
9
|
+
import { defineConfig } from "blume";
|
|
10
|
+
import { filesystem, mdxRemote } from "blume/sources";
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
content: {
|
|
14
|
+
sources: [
|
|
15
|
+
filesystem({ root: "docs" }),
|
|
16
|
+
// The docs/ subtree of acme/sdk, mounted under /sdk
|
|
17
|
+
mdxRemote({
|
|
18
|
+
prefix: "sdk",
|
|
19
|
+
github: { owner: "acme", repo: "sdk", ref: "main", path: "docs" },
|
|
20
|
+
}),
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
To list the files yourself, point `url` at a raw base URL:
|
|
27
|
+
|
|
28
|
+
```ts blume.config.ts
|
|
29
|
+
mdxRemote({
|
|
30
|
+
prefix: "sdk",
|
|
31
|
+
url: "https://raw.githubusercontent.com/acme/sdk/main/docs",
|
|
32
|
+
files: ["intro.mdx", "guide.mdx"],
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`include` (default `["**/*.{md,mdx}"]`) filters the files by their path under `path`, the way a `filesystem()` source's `include` does: a pattern starting with `!` excludes what it matches (`["**/*.mdx", "!drafts/**"]`). With `github`, the source lists the repository's whole tree at `ref` and keeps the files under `path`. If nothing is under `path` at that ref, the source reads no pages and warns with `BLUME_SOURCE_PATH_MISSING`. GitHub caps the listing (100,000 entries or 7 MB for the whole repository, whatever `path` is), and past it the source warns with `BLUME_SOURCE_TRUNCATED`: list the files with `url` and `files` instead.
|
|
37
|
+
|
|
38
|
+
A relative link between remote files (`[Errors](./02-errors.mdx)`) lands on the page the linked file publishes at, with its ordering prefix dropped from the route, and `blume validate` checks it the same way.
|
|
39
|
+
|
|
40
|
+
A private repo's token is read from the `GITHUB_TOKEN` environment variable — the adapter declares it, so `blume dev` and `blume build` warn when it's unset. It is never inlined into your config or generated output, and it is only ever sent to GitHub's own hosts (`api.github.com`, `raw.githubusercontent.com`), never to a custom `url` base. A public repo works without it.
|
|
41
|
+
|
|
42
|
+
Remote pages are rendered with full MDX-plus-component fidelity: their bodies are materialized into a hidden staging directory and rendered through Astro alongside your local docs, so callouts, tabs, and every other Blume component keep working.
|
|
43
|
+
|
|
44
|
+
Like every remote source, fetched pages are cached for offline builds and refreshed with `blume sync` — see [Caching and offline builds](/docs/content/sources#caching-and-offline-builds).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Sanity
|
|
3
|
+
description: Pull documents from a Sanity dataset with the sanity() source — a GROQ query picks the documents and their Portable Text bodies become Markdown.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The built-in `sanity()` adapter runs a GROQ query and maps each document's fields to frontmatter and its Portable Text body to Markdown. A body held in a Markdown string field passes through as written, except that a link that isn't a web, mail, phone, or relative address (a `javascript:` URL, say) keeps only its label. The adapter declares `@sanity/client` as its runtime dependency — an optional peer, so install it only if you use this source.
|
|
7
|
+
|
|
8
|
+
```ts blume.config.ts
|
|
9
|
+
import { defineConfig } from "blume";
|
|
10
|
+
import { filesystem, sanity } from "blume/sources";
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
content: {
|
|
14
|
+
sources: [
|
|
15
|
+
filesystem({ root: "docs" }),
|
|
16
|
+
sanity({
|
|
17
|
+
prefix: "guides",
|
|
18
|
+
projectId: "abc123",
|
|
19
|
+
dataset: "production",
|
|
20
|
+
query: `*[_type == "guide"]`,
|
|
21
|
+
// Field paths default to title / slug.current / body / _updatedAt
|
|
22
|
+
fields: { slug: "slug.current", body: "content" },
|
|
23
|
+
}),
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
A read token for a private dataset comes from the `SANITY_TOKEN` environment variable. The adapter declares it, so `blume dev` and `blume build` warn when it's unset; a public dataset works without it. Sanity answers a private dataset's query without a token with no documents rather than an error, so when a query finds nothing and the token is unset, the source adds a `BLUME_MISSING_SECRET` warning saying so. Under `--preview` the adapter reads drafts with the `previewDrafts` perspective, which `@sanity/client` 8 reports as renamed to `drafts`; the old name still works, and `@sanity/client` 6 accepts only the old one. Custom Portable Text block types map to Blume components through the engine's `serializers` option, available when you construct `sanitySource` directly and pass it to [`custom()`](/docs/content/sources/custom). Setting `serializers` writes the source's pages as MDX, so a component or directive a serializer returns renders.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Strapi
|
|
3
|
+
description: Read a Strapi content type through its REST API with the strapi() source, lowering Blocks bodies to Markdown on both Strapi 4 and Strapi 5.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The built-in `strapi()` adapter reads a content type through the Strapi REST API (`/api/<pluralApiId>`) and lowers each entry's Blocks body to Markdown: paragraphs, headings, lists, quotes, code blocks, images, and links. A Markdown rich text field passes through as written, except that a link that isn't a web, mail, phone, or relative address keeps only its label. Strapi 5 responses are read as-is, and the Strapi 4 `attributes` envelope is flattened so the same field paths apply. Nothing to install.
|
|
7
|
+
|
|
8
|
+
```ts blume.config.ts
|
|
9
|
+
import { defineConfig } from "blume";
|
|
10
|
+
import { filesystem, strapi } from "blume/sources";
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
content: {
|
|
14
|
+
sources: [
|
|
15
|
+
filesystem({ root: "docs" }),
|
|
16
|
+
strapi({
|
|
17
|
+
prefix: "guides",
|
|
18
|
+
url: "https://cms.example.com",
|
|
19
|
+
contentType: "guides",
|
|
20
|
+
// locale: "en"
|
|
21
|
+
// Field paths default to title / description / slug / content /
|
|
22
|
+
// updatedAt; order (no default) sets the sidebar order
|
|
23
|
+
fields: { body: "body" },
|
|
24
|
+
// Extra query parameters: filters[...], sort
|
|
25
|
+
params: { "filters[section][$eq]": "sdk" },
|
|
26
|
+
}),
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The API token comes from the `STRAPI_API_TOKEN` environment variable, sent as a bearer token. Entries are fetched with `populate=*` so images carry their URLs (set `populate` to narrow it), and a relative upload path (`/uploads/x.png`) in a Blocks field resolves against `url`. A Markdown field passes through as written, so a relative path there stays relative to your docs site and breaks: use absolute image URLs in Markdown fields, as Strapi's Markdown editor inserts them. Only published entries are imported — `--preview` requests drafts (`status=draft` on Strapi 5, `publicationState=preview` on Strapi 4) and stages each document that has never been published with `draft: true`; a published document previews its latest draft.
|
package/docs/content/syntax.mdx
CHANGED
|
@@ -27,7 +27,7 @@ Anchor ids are generated from the heading text, so a reworded heading gets a new
|
|
|
27
27
|
|
|
28
28
|
Link to it as `/page#setup`. The syntax matches Fumadocs, so migrated content works verbatim.
|
|
29
29
|
|
|
30
|
-
The `{#custom-id}` form used by Pandoc, kramdown, and Markdown-based specification toolchains is accepted as an equivalent in `.md` files. In `.mdx`, a bare `{…}` is a JSX expression and the page fails to compile — `blume check` reports
|
|
30
|
+
The `{#custom-id}` form used by Pandoc, kramdown, and Markdown-based specification toolchains is accepted as an equivalent in `.md` files. Only that unspaced spelling pins an anchor: the spaced `{ #custom-id }` and kramdown's `{: #custom-id }` (both from MkDocs' `attr_list`) stay in the heading text. In `.mdx`, a bare `{…}` is a JSX expression and the page fails to compile — `blume check` reports all three spellings as `BLUME_MDX_CURLY_ANCHOR` — so write `[#custom-id]` there, or escape the braces. The escaped form pins the same anchor in both formats, which makes it the right spelling for a partial that `.mdx` pages [include](/docs/content/includes):
|
|
31
31
|
|
|
32
32
|
```md
|
|
33
33
|
## Getting started \{#setup\}
|
|
@@ -248,6 +248,65 @@ createServer().listen(3000);
|
|
|
248
248
|
```
|
|
249
249
|
````
|
|
250
250
|
|
|
251
|
+
### Long lines and long blocks
|
|
252
|
+
|
|
253
|
+
Append `wrap` to wrap one block's long lines instead of scrolling them sideways:
|
|
254
|
+
|
|
255
|
+
```ts client.ts wrap
|
|
256
|
+
const client = createClient({
|
|
257
|
+
baseUrl: "https://api.example.com/v1",
|
|
258
|
+
retries: 3,
|
|
259
|
+
timeout: 10_000,
|
|
260
|
+
headers: { "x-client": "docs" },
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
````md
|
|
265
|
+
```ts client.ts wrap
|
|
266
|
+
const client = createClient({
|
|
267
|
+
baseUrl: "https://api.example.com/v1",
|
|
268
|
+
retries: 3,
|
|
269
|
+
timeout: 10_000,
|
|
270
|
+
headers: { "x-client": "docs" },
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
````
|
|
274
|
+
|
|
275
|
+
Append `expandable` to a long block to show its first lines with a **Show more** toggle under them. Opened, the block shows in full, with no scrolling inside it. A block under 16 lines renders as usual, since there's little to hide.
|
|
276
|
+
|
|
277
|
+
```ts routes.ts expandable
|
|
278
|
+
import { defineRoutes } from "./router";
|
|
279
|
+
|
|
280
|
+
export default defineRoutes({
|
|
281
|
+
home: "/",
|
|
282
|
+
docs: "/docs",
|
|
283
|
+
guides: "/docs/guides",
|
|
284
|
+
reference: "/docs/reference",
|
|
285
|
+
changelog: "/changelog",
|
|
286
|
+
blog: "/blog",
|
|
287
|
+
pricing: "/pricing",
|
|
288
|
+
about: "/about",
|
|
289
|
+
careers: "/careers",
|
|
290
|
+
contact: "/contact",
|
|
291
|
+
privacy: "/legal/privacy",
|
|
292
|
+
terms: "/legal/terms",
|
|
293
|
+
security: "/security",
|
|
294
|
+
status: "https://status.example.com",
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
````md
|
|
299
|
+
```ts routes.ts expandable
|
|
300
|
+
import { defineRoutes } from "./router";
|
|
301
|
+
|
|
302
|
+
export default defineRoutes({
|
|
303
|
+
// …every route
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
````
|
|
307
|
+
|
|
308
|
+
Both work alongside a title and `lineNumbers`. To wrap every block, set `markdown.code.wrap` instead.
|
|
309
|
+
|
|
251
310
|
### Highlighting
|
|
252
311
|
|
|
253
312
|
Annotate code with GitHub-style comments to draw attention to lines, words, and changes. The comments are stripped from the rendered output, so the code stays copy-paste clean. All four are on by default — no configuration.
|
|
@@ -398,7 +457,7 @@ flowchart LR
|
|
|
398
457
|
```
|
|
399
458
|
````
|
|
400
459
|
|
|
401
|
-
Diagrams render on the client, so this is an MDX-only feature, and the Mermaid library loads only on pages that include one; a site with no diagram doesn't ship it at all. Diagrams use Mermaid's dagre layout and classic look by default; opt a single diagram into another layout or look through Mermaid front matter (a `config:` block with `layout: elk` or `look: neo`), and the ELK engine loads only for diagrams that ask for it. The rest of this section is a gallery of common types — see the [Mermaid docs](https://mermaid.js.org/intro/) for the full list.
|
|
460
|
+
Diagrams render on the client, so this is an MDX-only feature, and the Mermaid library loads only on pages that include one; a site with no diagram doesn't ship it at all. Diagrams use Mermaid's dagre layout and classic look by default; opt a single diagram into another layout or look through Mermaid front matter (a `config:` block with `layout: elk` or `look: neo`), and the ELK engine loads only for diagrams that ask for it. A diagram Mermaid can't parse shows "Could not render this diagram." in its place; Mermaid's parser error, with the line it stopped on, goes to the browser console, and `blume dev` also prints it under the message. The rest of this section is a gallery of common types — see the [Mermaid docs](https://mermaid.js.org/intro/) for the full list.
|
|
402
461
|
|
|
403
462
|
### Flowchart
|
|
404
463
|
|
|
@@ -625,7 +684,7 @@ Commit `blume.config.ts`, not `.blume/`.
|
|
|
625
684
|
|
|
626
685
|
## Math
|
|
627
686
|
|
|
628
|
-
Render LaTeX with KaTeX
|
|
687
|
+
Render LaTeX with KaTeX, useful for math-heavy or scientific docs. Put `$$…$$` on lines of its own for a centered block:
|
|
629
688
|
|
|
630
689
|
$$
|
|
631
690
|
\int_0^\infty e^{-x^2}\,dx = \frac{\sqrt{\pi}}{2}
|
|
@@ -637,8 +696,14 @@ a^2 + b^2 = c^2
|
|
|
637
696
|
$$
|
|
638
697
|
```
|
|
639
698
|
|
|
699
|
+
Or write `$$…$$` inside a sentence for inline math, like Euler's identity $$e^{i\pi} + 1 = 0$$:
|
|
700
|
+
|
|
701
|
+
```md
|
|
702
|
+
Like Euler's identity $$e^{i\pi} + 1 = 0$$.
|
|
703
|
+
```
|
|
704
|
+
|
|
640
705
|
:::note
|
|
641
|
-
Math is
|
|
706
|
+
Math is on automatically: write `$$…$$` and it renders; write none and KaTeX's stylesheet never ships. Both block and inline math use two dollar signs. A single `$` (currency, shell variables, code) is always literal text, so "$5 and $10" never turns into math, and there's no delimiter to escape and no setting to toggle. Math is an MDX-only feature. The class names inside the rendered markup (`.katex-html`, `.katex-base`, …) are KaTeX's own internals, not a styling contract Blume maintains — they can change when KaTeX upgrades, so target the `.katex-display` wrapper for custom styles.
|
|
642
707
|
:::
|
|
643
708
|
|
|
644
709
|
## Smart punctuation
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Variables
|
|
3
|
+
description: Define a value once in blume.config.ts and write {{name}} anywhere a page needs it, in prose, code, links, and component props.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Define a value once and use it across every page. A version number, an API host, or a product name lives in `blume.config.ts`, and `{{name}}` in a page reads its value:
|
|
7
|
+
|
|
8
|
+
```ts blume.config.ts lineNumbers
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
variables: {
|
|
11
|
+
version: "2.1.0",
|
|
12
|
+
"api-url": "https://api.example.com",
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```mdx docs/quickstart.mdx
|
|
18
|
+
Install version {{version}}, then call {{api-url}}.
|
|
19
|
+
|
|
20
|
+
## What's new in {{version}}
|
|
21
|
+
|
|
22
|
+
<Card title="Release {{version}}" href="{{api-url}}/changelog" />
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
References work in prose, headings, links, code blocks, inline code, and component props, in `.md` and `.mdx` pages and in the files they [include](/docs/content/includes). Spaces inside the braces are fine (`{{ version }}`). Change the value in the config and every page picks it up on the next build.
|
|
26
|
+
|
|
27
|
+
Names take letters, digits, `_`, and `-`. Values are plain text on one line.
|
|
28
|
+
|
|
29
|
+
## Where they apply
|
|
30
|
+
|
|
31
|
+
A variable is replaced before anything reads the page, so the rendered HTML, [search](/docs/configuration/search), the page's [`.md` mirror](/docs/discoverability/markdown), and `llms-full.txt` all show the value.
|
|
32
|
+
|
|
33
|
+
Front matter is left as written: a `title` or `description` with `{{version}}` in it shows the braces.
|
|
34
|
+
|
|
35
|
+
## Undefined names
|
|
36
|
+
|
|
37
|
+
A `{{name}}` that isn't defined in prose is a build error, `BLUME_UNDEFINED_VARIABLE`, reported at its line, so a typo never reaches readers. Inside a code block or inline code, an undefined name is left as written, since templating examples like a Handlebars `{{title}}` are common there.
|
|
38
|
+
|
|
39
|
+
To show a reference in prose without defining it, put it in inline code: `` `{{name}}` ``.
|
|
40
|
+
|
|
41
|
+
A site that defines no variables is unaffected: `{{…}}` in its pages stays as written.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Agent discovery
|
|
3
|
-
description: How agents find your machine-readable surface without guessing — the agent-readability manifest, Link headers, the RFC 9727 API catalog, WebMCP, published skills, DNS-based discovery, and Web Bot Auth keys.
|
|
3
|
+
description: How agents find your machine-readable surface without guessing — the agent-readability manifest, Link headers, the RFC 9727 API catalog, WebMCP, your site's generated skill and published skills, DNS-based discovery, and Web Bot Auth keys.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Publishing `llms.txt`, Markdown mirrors, a JSON API, and an MCP server is only half the job — an agent still has to find them. Blume advertises the whole surface through the conventions agents actually probe: a manifest at the site root, `Link` headers and `<link>` tags, well-known files, and the browser's own model context. Everything here is on by default and derived from what you've already enabled.
|
|
@@ -228,6 +228,33 @@ agents: {
|
|
|
228
228
|
}
|
|
229
229
|
```
|
|
230
230
|
|
|
231
|
+
## Your site's skill
|
|
232
|
+
|
|
233
|
+
Every build writes an [agent skill](https://agentskills.io) for your docs, a `SKILL.md` a coding agent can install to work with your product. It's served at `/skill.md` and listed in the [skills index](#skills-discovery). Blume builds it from what it already knows about the site, without calling a model, so it costs nothing and changes whenever your docs do. It holds:
|
|
234
|
+
|
|
235
|
+
- the site's title and description, and when an agent should use the skill
|
|
236
|
+
- how to read any page as Markdown, plus `llms.txt`, `llms-full.txt`, the [MCP server](/docs/discoverability/mcp), the JSON API, and the changelog, when the site serves them
|
|
237
|
+
- your API references
|
|
238
|
+
- a map of the docs in sidebar order, linking each page's Markdown with its one-line description
|
|
239
|
+
|
|
240
|
+
The skill is named after your site's `title` (`Acme Docs` becomes `acme-docs`). It covers the current version in the default language, leaves out API operation pages and changelog entries (each has one line of its own above the map), skips the pages `llms.txt` does (drafts, hidden and `noindex` pages, and pages with [`ai.exclude`](/docs/discoverability/llms-txt#excluding-a-page)), and lists up to 200 pages, pointing at `llms.txt` for the rest. The links are absolute, so the skill needs [`deployment.site`](/docs/deployment); a build without one skips it.
|
|
241
|
+
|
|
242
|
+
The generated skill is a guide to your docs, not a summary of your product. For one that teaches an agent your product — setup, core concepts, common tasks, and gotchas — have your coding agent write it from the docs:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
blume skill --claude # or --codex
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
`blume skill` opens Claude Code or Codex on the [`blume-write-skill`](/docs/advanced/skills#writing-your-sites-skill) skill, which writes a `SKILL.md` under your [`agents.skills`](#skills-discovery) folder (`./skills` when it isn't set, adding it to your config), named after your site so it replaces the generated one. You review and commit it like any other file; it costs your agent's tokens once, not on every build. Run it again after a big docs change, since a hand-written skill doesn't update itself. Without a flag, `blume skill` prints where the skill would go and how to point another agent at it.
|
|
249
|
+
|
|
250
|
+
Any skill of the same name in `agents.skills`, however you write it, replaces the generated one in the index, and at `/skill.md` too when it's a lone `SKILL.md`. A `public/skill.md` you ship wins over both. To turn the skill off:
|
|
251
|
+
|
|
252
|
+
```ts blume.config.ts lineNumbers
|
|
253
|
+
agents: {
|
|
254
|
+
skillMd: false,
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
231
258
|
## Skills discovery
|
|
232
259
|
|
|
233
260
|
If your project ships [agent skills](https://agentskills.io) — the [Blume repo itself does](/docs/advanced/skills) — point `agents.skills` at the directory that holds them, and the build publishes them for discovery per the [Agent Skills Discovery RFC](https://github.com/cloudflare/agent-skills-discovery-rfc):
|
|
@@ -240,7 +267,7 @@ agents: {
|
|
|
240
267
|
|
|
241
268
|
The path resolves against your project root, and each subdirectory with a `SKILL.md` becomes a published skill. A skill that's a lone `SKILL.md` is copied verbatim to `/.well-known/agent-skills/<name>/SKILL.md` (`type: "skill-md"`); a skill with supporting resources (`scripts/`, `references/`, `assets/`) is bundled into a deterministic `.tar.gz` (`type: "archive"`) so its relative references resolve after unpacking, with script execute bits preserved. The discovery index at `/.well-known/agent-skills/index.json` carries the v0.2.0 `$schema` and, per skill, its name, type, description (from the `SKILL.md` frontmatter), artifact URL, and the SHA-256 digest clients verify downloads against.
|
|
242
269
|
|
|
243
|
-
Skills with a missing or spec-invalid `name`/`description` are skipped with a build warning rather than published broken, and a `public/.well-known/agent-skills/index.json` you ship yourself takes over the whole surface. Published skills are also listed in [`llms.txt`](/docs/discoverability/llms-txt#generated-sections).
|
|
270
|
+
Skills with a missing or spec-invalid `name`/`description` are skipped with a build warning rather than published broken, and a `public/.well-known/agent-skills/index.json` you ship yourself takes over the whole surface. Published skills, [your site's own](#your-sites-skill) included, are also listed in [`llms.txt`](/docs/discoverability/llms-txt#generated-sections).
|
|
244
271
|
|
|
245
272
|
## DNS-based discovery (DNS-AID)
|
|
246
273
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: SEO and
|
|
2
|
+
title: SEO and GEO
|
|
3
3
|
description: How a Blume site gets found — by search engines and social platforms on one side, coding agents and AI assistants on the other — and where each surface is configured.
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -46,4 +46,4 @@ The in-page **assistant** is the one AI feature documented elsewhere: it's a rea
|
|
|
46
46
|
|
|
47
47
|
## Checking your work
|
|
48
48
|
|
|
49
|
-
[`blume audit`](/docs/cli/audit) crawls the built site and reports on titles, descriptions, canonicals, Open Graph and X cards, hreflang, the sitemap, `robots.txt`, and structured data. Point it at a deployment with `--url` to also check response headers and [DNS-based agent discovery](/docs/discoverability/agent-discovery#dns-based-discovery-dns-aid).
|
|
49
|
+
[`blume audit`](/docs/cli/audit) crawls the built site and reports on titles, descriptions, canonicals, Open Graph and X cards, hreflang, the sitemap, `robots.txt`, and structured data. Point it at a deployment with `--url` to also check response headers, configured redirects, and [DNS-based agent discovery](/docs/discoverability/agent-discovery#dns-based-discovery-dns-aid).
|
|
@@ -13,6 +13,8 @@ Every Blume site also serves its docs as a small read-only **JSON API** — the
|
|
|
13
13
|
| `/api/docs/search?q=` | Full-text search, with the same `limit`, `contentTypes`, `locale`, `version`, and `filters[key]` scoping as `search_docs`. Server output only. |
|
|
14
14
|
| `/openapi.json` | The OpenAPI 3.1 description of the whole machine-readable surface. |
|
|
15
15
|
|
|
16
|
+
The page index leaves out [hidden pages](/docs/content/navigation#hidden-pages), which get no per-page document either; `get_page` and the page's `.md` mirror still serve one, since hidden isn't private. Pages with `seo.noindex`, `ai.exclude`, or `search.exclude` are listed like any other. A page document's `markdown` is the page's source as agents read it, with its frontmatter block kept at the top.
|
|
17
|
+
|
|
16
18
|
The page index, per-page documents, and navigation are prerendered, so a static site serves them as files from any host. Search is a live endpoint and exists only under [server output](/docs/deployment#server-rendering), where it runs the same index `search_docs` does.
|
|
17
19
|
|
|
18
20
|
## Errors
|
|
@@ -44,7 +44,7 @@ agents: {
|
|
|
44
44
|
|
|
45
45
|
## Generated sections
|
|
46
46
|
|
|
47
|
-
`llms.txt` closes with two generated sections that need no configuration. **Agent skills** lists each skill published through [`agents.skills`](/docs/discoverability/agent-discovery#skills-discovery) with its description (where a skill says when to use it). **Agent resources** links every machine-readable artifact the build emits — `llms-full.txt`, the per-page [raw Markdown](/docs/discoverability/markdown) mirror, the [MCP server](/docs/discoverability/mcp) and its discovery document, the skills index, the [API catalog](/docs/discoverability/agent-discovery#api-catalog), the [AI catalog](/docs/discoverability/agent-discovery#ai-catalog), [`agent-readability.json`](/docs/discoverability/agent-discovery#agent-readability), and the [sitemap](/docs/discoverability/sitemap-and-robots#sitemap) — each only when it exists, so an agent that reads nothing but `llms.txt` still finds the whole surface.
|
|
47
|
+
`llms.txt` closes with two generated sections that need no configuration. **Agent skills** lists [your site's own skill](/docs/discoverability/agent-discovery#your-sites-skill) and each skill published through [`agents.skills`](/docs/discoverability/agent-discovery#skills-discovery) with its description (where a skill says when to use it). **Agent resources** links every machine-readable artifact the build emits — `llms-full.txt`, the per-page [raw Markdown](/docs/discoverability/markdown) mirror, the [MCP server](/docs/discoverability/mcp) and its discovery document, the skills index, the [API catalog](/docs/discoverability/agent-discovery#api-catalog), the [AI catalog](/docs/discoverability/agent-discovery#ai-catalog), [`agent-readability.json`](/docs/discoverability/agent-discovery#agent-readability), and the [sitemap](/docs/discoverability/sitemap-and-robots#sitemap) — each only when it exists, so an agent that reads nothing but `llms.txt` still finds the whole surface.
|
|
48
48
|
|
|
49
49
|
## Excluding a page
|
|
50
50
|
|
|
@@ -58,7 +58,7 @@ ai:
|
|
|
58
58
|
---
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
The page still renders, stays in search, and keeps its place in the sitemap — only the `llms.txt` files skip it.
|
|
61
|
+
The page still renders, stays in search, and keeps its place in the sitemap — only the `llms.txt` files and the page map in your [site's skill](/docs/discoverability/agent-discovery#your-sites-skill) skip it.
|
|
62
62
|
|
|
63
63
|
## Bringing your own
|
|
64
64
|
|
|
@@ -17,7 +17,7 @@ Append `.md` or `.mdx` to any page's URL to fetch its raw Markdown source — pe
|
|
|
17
17
|
|
|
18
18
|
Nested routes work the same way (`/content/syntax.md`), and the home page is served at `/index.md`.
|
|
19
19
|
|
|
20
|
-
The `.md` variant _downlevels_ components to plain Markdown for consumers that can't interpret JSX: `<TypeTable>` becomes a Markdown table, `<Callout>` a labeled blockquote, `<Steps>` an ordered list, `<Tabs>` bold-labeled sections, `<Card>` its title as a link over its body (and `<CardGroup>` the cards it holds), `<Accordion>` bold questions over their answers, `<FileTree>` its list, `<CodeGroup>` its titled code blocks, `<YouTube>` a link, and every other built-in component — Columns, Frame, Expandable, Badge, Tooltip, and the rest — its readable content. `<AutoTypeTable>`, which needs the type checker, stays as written, as do a `<Diff>` that reads its sides from files (`src`, or `before` and `after`) and a `<GithubInfo>` without `owner` and `repo`. The components a generated [API reference](/docs/references/openapi) page is made of downlevel too: `<Operation>` becomes the endpoint in its spec's own notation (`GET /pets/{id}`, `SEND user/signup`, `query pets`) with a deprecation marker, `<ApiTagOperations>` a list of those endpoints linked to their pages with their summaries, and `<ApiOverview>` the API's version and base URLs — so an agent reading a reference page knows what to call, and site search matches an endpoint's path. Props are read as literal data and never executed — strings, numbers, booleans, arrays, objects, and template strings, plus references to the page's `frontmatter`, so a prop like `title={frontmatter.status}` resolves to the same value the rendered page shows. Anything that can't be converted faithfully — a custom component, or a prop computed by a function call or from an import — is left as-is, and component markup inside code, fenced or inline, is never touched. The same conversion applies to [`llms-full.txt`](/docs/discoverability/llms-txt) and the [MCP server](/docs/discoverability/mcp)'s `get_page` tool, so every agent-facing surface reads clean Markdown.
|
|
20
|
+
The `.md` variant _downlevels_ components to plain Markdown for consumers that can't interpret JSX: `<TypeTable>` becomes a Markdown table, `<Callout>` a labeled blockquote, `<Steps>` an ordered list, `<Tabs>` bold-labeled sections, `<Card>` its title as a link over its body (and `<CardGroup>` the cards it holds), `<Accordion>` bold questions over their answers, `<FileTree>` its list, `<CodeGroup>` its titled code blocks, `<YouTube>` a link, and every other built-in component — Columns, Frame, Expandable, Badge, Tooltip, and the rest — its readable content. `<AutoTypeTable>`, which needs the type checker, stays as written, as do a `<Diff>` that reads its sides from files (`src`, or `before` and `after`) and a `<GithubInfo>` without `owner` and `repo`. The components a generated [API reference](/docs/references/openapi) page is made of downlevel too: `<Operation>` becomes the endpoint in its spec's own notation (`GET /pets/{id}`, `SEND user/signup`, `query pets`) with a deprecation marker, `<ApiTagOperations>` a list of those endpoints linked to their pages with their summaries, and `<ApiOverview>` the API's version and base URLs — so an agent reading a reference page knows what to call, and site search matches an endpoint's path. Props are read as literal data and never executed — strings, numbers, booleans, arrays, objects, and template strings, plus references to the page's `frontmatter`, so a prop like `title={frontmatter.status}` resolves to the same value the rendered page shows. Only props resolve: an expression in the page's own text, like `Owned by {frontmatter.owner}`, stays as written in the Markdown copy. For a value agents should read too, write it into the text, or, when it's the same on every page, make it a [content variable](/docs/content/variables), which every surface replaces. Anything that can't be converted faithfully — a custom component, or a prop computed by a function call or from an import — is left as-is, and component markup inside code, fenced or inline, is never touched. The same conversion applies to [`llms-full.txt`](/docs/discoverability/llms-txt) and the [MCP server](/docs/discoverability/mcp)'s `get_page` tool, so every agent-facing surface reads clean Markdown.
|
|
21
21
|
|
|
22
22
|
When you want the MDX itself, use the `.mdx` variant: its components stay as written, and the rest is prepared for an agent reading it by URL, as in the `.md` variant. [Includes](/docs/content/includes) are spliced in, [`<Visibility>`](/docs/content/components#visibility) resolves for agents (`for="web"` content is removed, `for="agents"` content kept), relative images point at their served URLs, relative page links point at the routes they mean, and root-relative links (`/guides/install`) gain the site's `deployment.base` and `basePath` and, on a translated page, move into the page's locale, the way the rendered page's links do. Root-relative images and links to files in `public/` (`/spec.pdf`) gain `deployment.base` alone, since that's where those files are served.
|
|
23
23
|
|
|
@@ -25,6 +25,8 @@ When you want the MDX itself, use the `.mdx` variant: its components stay as wri
|
|
|
25
25
|
|
|
26
26
|
Agents don't need to know the `.md` convention: requesting a page's own URL with an [`Accept: text/markdown`](https://acceptmarkdown.com) header serves the Markdown variant at the same address, with `Vary: Accept` so caches keep the two apart. The dev server honors the header out of the box, and a [Vercel or Cloudflare server build](/docs/deployment#server-rendering) wires the same negotiation into the deploy automatically — routing rules on Vercel, a generated Worker on Cloudflare — no configuration needed. The homepage always negotiates, even when it's a custom landing page rather than a content page: its Markdown mirror falls back to the [`llms.txt`](/docs/discoverability/llms-txt) index, so an agent asking the site root for Markdown gets the machine-readable map of the site. Markdown responses also carry an `x-markdown-tokens` header — an estimated token count (~4 characters per token), following the convention of [Cloudflare's Markdown for Agents](https://developers.cloudflare.com/fundamentals/reference/markdown-for-agents/) — on every surface where Blume controls response headers: the dev server, server-rendered responses, and the negotiated homepage on Vercel and Cloudflare. Other deploy targets serve prerendered pages from a static layer with no request-time hook, so agents there fetch the `.md` URL directly; the [agent readability manifest](/docs/discoverability/agent-discovery#agent-readability) advertises `contentNegotiation` only on deployments that honor the header.
|
|
27
27
|
|
|
28
|
+
A client gets Markdown when its `Accept` header lists `text/markdown` (or `text/x-markdown`, in any case) with a q-value above zero and at least as high as `text/html`'s: `text/markdown` and `text/markdown, text/html` get Markdown, `text/html, text/markdown;q=0.9` gets HTML. Vercel's routing rules can't compare two q-values, so when both types carry one below 1 (`text/markdown;q=0.9, text/html;q=0.8`), Vercel serves HTML where the dev server and Cloudflare serve Markdown. Send `text/markdown` without a q-value to get Markdown everywhere.
|
|
29
|
+
|
|
28
30
|
Missing pages negotiate too. The default [404 page](/docs/advanced/custom-pages#404-page) has a Markdown twin at `/404.md` — the not-found message followed by recovery links to every top-level section, the sitemap, and `llms.txt` — and on a Vercel or Cloudflare server build a request for a nonexistent URL that prefers Markdown gets that body with a real `404` status rather than the HTML shell. On Vercel the same goes for any `.md` URL with no page behind it. A 404 page of your own (a `pages/404.astro`, or a content page at `/404`) replaces the default along with its `/404.md` twin, so missing pages then answer with your HTML page.
|
|
29
31
|
|
|
30
32
|
### Custom component serializers
|