blume 2.1.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +110 -0
- 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-43zcf4gz.js → chunk-0pmb4tr4.js} +541 -368
- package/dist/cli/chunk-0pmb4tr4.js.map +35 -0
- package/dist/cli/{chunk-9geymqns.js → chunk-0w6hs479.js} +15 -15
- package/dist/cli/{chunk-xkz5xbtv.js → chunk-124fvmzq.js} +2802 -1422
- package/dist/cli/chunk-124fvmzq.js.map +220 -0
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-y4ykbark.js → chunk-1f882900.js} +2 -2
- package/dist/cli/{chunk-5ffywsmb.js → chunk-297ajdcv.js} +8 -6
- package/dist/cli/{chunk-5ffywsmb.js.map → chunk-297ajdcv.js.map} +3 -3
- package/dist/cli/{chunk-h2a48yhd.js → chunk-32khwcb6.js} +120 -16
- package/dist/cli/{chunk-h2a48yhd.js.map → chunk-32khwcb6.js.map} +10 -10
- package/dist/cli/{chunk-5cg2rzgf.js → chunk-36bxs9c7.js} +20 -49
- package/dist/cli/{chunk-5cg2rzgf.js.map → chunk-36bxs9c7.js.map} +4 -5
- package/dist/cli/{chunk-py62fewh.js → chunk-53jqw8z0.js} +3 -3
- package/dist/cli/{chunk-5wj2qwn2.js → chunk-58bt3hag.js} +4 -4
- package/dist/cli/{chunk-e7vvk5ya.js → chunk-5cmts6dv.js} +3 -3
- package/dist/cli/{chunk-y5h4r2y0.js → chunk-60hz265r.js} +15 -5
- package/dist/cli/chunk-60hz265r.js.map +10 -0
- package/dist/cli/chunk-74wfhv79.js +65 -0
- package/dist/cli/chunk-74wfhv79.js.map +10 -0
- package/dist/cli/{chunk-g2z9x01v.js → chunk-9qzgg6mj.js} +3 -3
- package/dist/cli/{chunk-q3wxxq39.js → chunk-a57yh0h9.js} +5 -5
- package/dist/cli/{chunk-713mngdq.js → chunk-ave1wcbr.js} +76 -10
- package/dist/cli/chunk-ave1wcbr.js.map +14 -0
- package/dist/cli/{chunk-2n4ps1b3.js → chunk-bqxaqn5p.js} +40 -22
- package/dist/cli/chunk-bqxaqn5p.js.map +15 -0
- package/dist/cli/{chunk-jnwj5kjj.js → chunk-bxwhtvw8.js} +20 -7
- package/dist/cli/{chunk-jnwj5kjj.js.map → chunk-bxwhtvw8.js.map} +3 -3
- package/dist/cli/chunk-ckrcm08h.js +324 -0
- package/dist/cli/chunk-ckrcm08h.js.map +14 -0
- package/dist/cli/{chunk-2f3ndkpw.js → chunk-desvm72z.js} +3 -3
- package/dist/cli/{chunk-gp84za0h.js → chunk-dhwtqnnd.js} +2 -2
- package/dist/cli/{chunk-4h8z9vv5.js → chunk-dpy8qdjf.js} +93 -47
- package/dist/cli/chunk-dpy8qdjf.js.map +17 -0
- package/dist/cli/{chunk-2f7n4qzt.js → chunk-dqhg54mr.js} +1 -1
- package/dist/cli/{chunk-0gz36akr.js → chunk-dv2z0rzf.js} +21 -5
- package/dist/cli/chunk-dv2z0rzf.js.map +12 -0
- package/dist/cli/{chunk-cm89scdv.js → chunk-es8h0v3j.js} +9 -11
- package/dist/cli/{chunk-cm89scdv.js.map → chunk-es8h0v3j.js.map} +3 -3
- package/dist/cli/{chunk-zhvd6adm.js → chunk-gfc5fqvf.js} +14 -14
- package/dist/cli/{chunk-nd1821sk.js → chunk-gxtg6ed2.js} +33 -19
- package/dist/cli/chunk-gxtg6ed2.js.map +10 -0
- package/dist/cli/{chunk-p804f3pe.js → chunk-hvcxng5f.js} +6 -6
- package/dist/cli/{chunk-ta27feev.js → chunk-j1x92mx9.js} +21 -2
- package/dist/cli/chunk-j1x92mx9.js.map +10 -0
- package/dist/cli/{chunk-rekqz4qg.js → chunk-k3gr1nm9.js} +19 -16
- package/dist/cli/chunk-k3gr1nm9.js.map +10 -0
- package/dist/cli/{chunk-1n228xqb.js → chunk-kdpzw38a.js} +2 -2
- package/dist/cli/{chunk-cy5bm0j0.js → chunk-ms9z66nz.js} +2 -2
- package/dist/cli/{chunk-cy5bm0j0.js.map → chunk-ms9z66nz.js.map} +2 -2
- package/dist/cli/{chunk-zf748avv.js → chunk-nbyvgnnm.js} +193 -286
- package/dist/cli/chunk-nbyvgnnm.js.map +36 -0
- package/dist/cli/{chunk-6bm0xpgd.js → chunk-s0bdnc7v.js} +2 -2
- package/dist/cli/{chunk-yxmk4pec.js → chunk-sc93apfs.js} +17 -16
- package/dist/cli/{chunk-yxmk4pec.js.map → chunk-sc93apfs.js.map} +3 -3
- package/dist/cli/{chunk-cmtcnh9f.js → chunk-tfycddbt.js} +2 -2
- package/dist/cli/{chunk-9xr4dgee.js → chunk-twy7psdz.js} +29 -16
- package/dist/cli/chunk-twy7psdz.js.map +10 -0
- package/dist/cli/{chunk-ntv4qrt7.js → chunk-y4msrwm9.js} +15 -15
- package/dist/cli/{chunk-yj17vs39.js → chunk-ydp3065p.js} +5 -5
- package/dist/cli/index.js +24 -19
- package/dist/cli/index.js.map +3 -3
- package/dist/types/ai/ask-context.d.ts +6 -2
- package/dist/types/ai/ask.d.ts +24 -5
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/analytics/clics.d.ts +37 -0
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/schema.d.ts +18 -0
- package/dist/types/astro/integration.d.ts +11 -4
- package/dist/types/astro/markdown-negotiation.d.ts +3 -0
- package/dist/types/astro/pages.d.ts +10 -0
- package/dist/types/cli/init/scaffold.d.ts +1 -1
- package/dist/types/components/content/api-field.d.ts +4 -1
- package/dist/types/components/content/api-page.d.ts +6 -1
- package/dist/types/components/openapi/code-samples.d.ts +29 -0
- package/dist/types/components/openapi/helpers.d.ts +22 -1
- package/dist/types/components/openapi/security.d.ts +10 -0
- package/dist/types/components/openapi/snippets.d.ts +60 -0
- package/dist/types/core/changelog-index.d.ts +8 -0
- package/dist/types/core/config-input.d.ts +37 -6
- package/dist/types/core/data.d.ts +4 -0
- package/dist/types/core/i18n-ui.d.ts +2 -0
- package/dist/types/core/links.d.ts +8 -0
- package/dist/types/core/powered-by.d.ts +12 -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 +11 -3
- package/dist/types/core/schema.d.ts +228 -3
- 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/lower.d.ts +10 -2
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/notion.d.ts +8 -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 +17 -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/cloudflare-negotiation.d.ts +5 -2
- package/dist/types/deploy/node-headers.d.ts +12 -4
- package/dist/types/deploy/platforms/cloudflare.d.ts +10 -7
- 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 +21 -2
- package/dist/types/deploy/redirects.d.ts +17 -1
- package/dist/types/deploy/sitemap.d.ts +2 -1
- package/dist/types/deploy/vercel-negotiation.d.ts +44 -21
- package/dist/types/narration/build.d.ts +34 -12
- package/dist/types/narration/provider.d.ts +96 -8
- 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 +15 -4
- package/dist/types/openapi/parse.d.ts +3 -0
- package/dist/types/openapi/references.d.ts +16 -0
- package/dist/types/openapi/sentence.d.ts +11 -1
- package/dist/types/ratelimit/index.d.ts +1 -1
- package/dist/types/ratelimit/schema.d.ts +8 -0
- package/dist/types/ratelimit/upstash.d.ts +39 -14
- package/dist/types/reference/graphql.d.ts +76 -1
- package/dist/types/reference/index.d.ts +1 -1
- package/dist/types/reference/openapi.d.ts +2 -2
- package/dist/types/reference/options.d.ts +37 -1
- package/dist/types/reference/schema.d.ts +84 -0
- 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/orama-index.d.ts +9 -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/jsonld.d.ts +11 -6
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/notion.d.ts +8 -0
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +63 -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 +59 -13
- package/docs/03-upgrading.mdx +2 -1
- package/docs/04-migrating.mdx +9 -9
- package/docs/08-faq.mdx +12 -12
- package/docs/advanced/changelog.mdx +30 -2
- package/docs/advanced/custom-pages.mdx +1 -1
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +30 -7
- package/docs/cli/doctor.mdx +6 -2
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/translate.mdx +1 -0
- package/docs/cli/validate.mdx +4 -3
- package/docs/configuration/analytics.mdx +19 -1
- package/docs/configuration/assistant.mdx +6 -2
- package/docs/configuration/customization.mdx +4 -2
- package/docs/configuration/export.mdx +5 -3
- package/docs/configuration/index.mdx +4 -2
- package/docs/configuration/narration.mdx +43 -6
- package/docs/configuration/rate-limiting.mdx +23 -2
- package/docs/configuration/search.mdx +37 -14
- package/docs/content/components.mdx +2 -2
- package/docs/content/frontmatter.mdx +5 -3
- package/docs/content/i18n.mdx +2 -2
- package/docs/content/includes.mdx +1 -1
- package/docs/content/navigation.mdx +8 -6
- package/docs/content/sources/contentful.mdx +9 -4
- package/docs/content/sources/custom.mdx +7 -3
- package/docs/content/sources/github-releases.mdx +12 -2
- package/docs/content/sources/index.mdx +3 -3
- package/docs/content/sources/notion.mdx +17 -2
- package/docs/content/sources/obsidian.mdx +3 -1
- package/docs/content/sources/payload.mdx +5 -2
- package/docs/content/sources/remote-mdx.mdx +6 -0
- package/docs/content/sources/sanity.mdx +4 -2
- package/docs/content/sources/strapi.mdx +5 -2
- package/docs/content/syntax.mdx +2 -2
- package/docs/discoverability/agent-discovery.mdx +1 -1
- package/docs/discoverability/index.mdx +1 -1
- package/docs/discoverability/json-api.mdx +2 -0
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/markdown.mdx +3 -1
- package/docs/discoverability/mcp.mdx +6 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/discoverability/structured-data.mdx +8 -6
- package/docs/references/api-pages.mdx +1 -1
- package/docs/references/asyncapi.mdx +5 -1
- package/docs/references/graphql.mdx +15 -1
- package/docs/references/openapi.mdx +64 -8
- package/package.json +9 -9
- package/skills/blume/SKILL.md +1 -1
- package/skills/blume-migrate/SKILL.md +2 -2
- package/skills/blume-migrate/assets/{oxfmt@0.67.0.patch → oxfmt@0.71.0.patch} +7 -7
- package/skills/blume-migrate/references/docusaurus.md +4 -4
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/monorepo.md +5 -5
- package/skills/blume-migrate/references/nextra.md +8 -5
- package/skills/blume-migrate/references/starlight.md +9 -7
- package/src/ai/ask-context.ts +33 -3
- package/src/ai/ask-limits.ts +13 -0
- package/src/ai/ask.ts +24 -6
- package/src/ai/changelog-markdown.ts +11 -6
- package/src/ai/component-markdown.ts +1 -1
- package/src/ai/cors.ts +12 -3
- package/src/ai/mcp/query.ts +14 -6
- package/src/ai/openapi-components.ts +28 -4
- package/src/ai/relative-links.ts +4 -38
- package/src/analytics/clics.ts +58 -0
- package/src/analytics/head.ts +5 -0
- package/src/analytics/index.ts +2 -0
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +91 -56
- package/src/astro/integration.ts +72 -22
- package/src/astro/markdown-negotiation.ts +3 -0
- package/src/astro/module-types.ts +3 -1
- package/src/astro/pages.ts +23 -0
- package/src/astro/render-deps.ts +10 -5
- package/src/astro/runtime-deps.ts +23 -2
- package/src/astro/templates.ts +129 -81
- package/src/audit/catalog.ts +19 -3
- package/src/audit/checks/links.ts +14 -1
- 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/run.ts +3 -0
- package/src/audit/types.ts +2 -0
- package/src/audit/url.ts +14 -5
- package/src/blume-modules.d.ts +5 -1
- package/src/cli/args.ts +51 -0
- package/src/cli/build-failure.ts +23 -0
- package/src/cli/commands/audit.ts +10 -1
- package/src/cli/commands/dev.ts +18 -2
- package/src/cli/commands/doctor.ts +45 -12
- package/src/cli/commands/eval.ts +36 -4
- package/src/cli/commands/init.ts +6 -4
- package/src/cli/commands/validate.ts +10 -1
- package/src/cli/init/scaffold.ts +9 -6
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +3 -2
- package/src/components/content/ApiPlayground.astro +6 -2
- package/src/components/content/api-field.ts +4 -1
- package/src/components/content/api-page.ts +31 -7
- package/src/components/content/mermaid-element.ts +15 -1
- package/src/components/content/view-switcher.ts +7 -4
- package/src/components/islands/hooks.ts +27 -1
- package/src/components/layout/NavTree.astro +49 -5
- package/src/components/layout/NavTreeScript.astro +18 -0
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/PageLayout.astro +13 -3
- package/src/components/layout/RootLayout.astro +27 -14
- package/src/components/layout/Search.astro +17 -3
- package/src/components/layout/TableOfContents.astro +24 -17
- package/src/components/layout/analytics-client.ts +8 -8
- package/src/components/layout/head-scripts.ts +6 -1
- package/src/components/layout/search/algolia.ts +10 -1
- package/src/components/layout/search/analytics.ts +42 -14
- package/src/components/layout/search/endpoint.ts +48 -5
- package/src/components/layout/search/pagefind.ts +114 -5
- package/src/components/layout/search/types.ts +12 -0
- package/src/components/layout/search/typesense.ts +18 -6
- 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 +24 -1
- package/src/components/openapi/ParametersTable.astro +8 -4
- package/src/components/openapi/Playground.astro +7 -1
- package/src/components/openapi/RequestBody.astro +19 -2
- package/src/components/openapi/Responses.astro +1 -0
- package/src/components/openapi/SchemaTable.astro +15 -3
- package/src/components/openapi/async-snippets.ts +61 -5
- package/src/components/openapi/async.ts +123 -29
- 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 +77 -58
- package/src/components/openapi/playground-schema.ts +1 -1
- package/src/components/openapi/schema-tree.ts +44 -14
- package/src/components/openapi/security.ts +10 -0
- package/src/components/openapi/snippets.ts +5 -3
- package/src/components/openapi/validate-json.ts +4 -3
- package/src/components/powered-by-middleware.ts +33 -0
- package/src/core/changelog-index.ts +31 -1
- package/src/core/component-diagnostics.ts +53 -0
- package/src/core/component-overrides.ts +32 -0
- package/src/core/config-input.ts +42 -6
- package/src/core/data.ts +2 -0
- package/src/core/diagnostics.ts +5 -0
- package/src/core/i18n-ui.ts +2 -0
- package/src/core/includes.ts +1 -1
- package/src/core/links.ts +47 -17
- package/src/core/powered-by.ts +12 -0
- package/src/core/probe.ts +26 -6
- package/src/core/project-graph.ts +59 -18
- package/src/core/redirect-patterns.ts +36 -7
- package/src/core/schema.ts +26 -6
- 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/lower.ts +19 -3
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +227 -41
- package/src/core/sources/notion.ts +34 -10
- package/src/core/sources/obsidian.ts +16 -3
- package/src/core/sources/payload.ts +38 -15
- 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 +18 -0
- package/src/core/ui-packs/ar.ts +1 -0
- package/src/core/ui-packs/bg.ts +1 -0
- package/src/core/ui-packs/bn.ts +1 -0
- package/src/core/ui-packs/ca.ts +1 -0
- package/src/core/ui-packs/cs.ts +1 -0
- package/src/core/ui-packs/da.ts +1 -0
- package/src/core/ui-packs/de.ts +1 -0
- package/src/core/ui-packs/el.ts +1 -0
- package/src/core/ui-packs/es.ts +1 -0
- package/src/core/ui-packs/fa.ts +1 -0
- package/src/core/ui-packs/fi.ts +1 -0
- package/src/core/ui-packs/fr.ts +1 -0
- package/src/core/ui-packs/he.ts +1 -0
- package/src/core/ui-packs/hi.ts +1 -0
- package/src/core/ui-packs/hr.ts +1 -0
- package/src/core/ui-packs/hu.ts +1 -0
- package/src/core/ui-packs/id.ts +1 -0
- package/src/core/ui-packs/it.ts +1 -0
- package/src/core/ui-packs/ja.ts +1 -0
- package/src/core/ui-packs/ko.ts +1 -0
- package/src/core/ui-packs/nl.ts +1 -0
- package/src/core/ui-packs/no.ts +1 -0
- package/src/core/ui-packs/pl.ts +1 -0
- package/src/core/ui-packs/pt-br.ts +1 -0
- package/src/core/ui-packs/pt.ts +1 -0
- package/src/core/ui-packs/ro.ts +1 -0
- package/src/core/ui-packs/ru.ts +1 -0
- package/src/core/ui-packs/sk.ts +1 -0
- package/src/core/ui-packs/sr.ts +1 -0
- package/src/core/ui-packs/sv.ts +1 -0
- package/src/core/ui-packs/th.ts +1 -0
- package/src/core/ui-packs/tr.ts +1 -0
- package/src/core/ui-packs/uk.ts +1 -0
- package/src/core/ui-packs/vi.ts +1 -0
- package/src/core/ui-packs/zh-tw.ts +1 -0
- package/src/core/ui-packs/zh.ts +1 -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 +2 -1
- package/src/deploy/cloudflare-negotiation.ts +36 -7
- package/src/deploy/headers.ts +15 -1
- package/src/deploy/node-headers.ts +32 -20
- package/src/deploy/platforms/cloudflare.ts +14 -9
- package/src/deploy/platforms/netlify.ts +2 -1
- package/src/deploy/platforms/node.ts +12 -2
- package/src/deploy/platforms/types.ts +21 -7
- package/src/deploy/platforms/vercel.ts +115 -17
- package/src/deploy/redirects.ts +66 -6
- package/src/deploy/rss.ts +3 -1
- package/src/deploy/sitemap.ts +39 -5
- package/src/deploy/vercel-negotiation.ts +325 -103
- 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/base-links.ts +15 -14
- package/src/markdown/package-commands.ts +9 -8
- package/src/markdown/relative-links.ts +3 -2
- package/src/narration/build.ts +218 -40
- package/src/narration/provider.ts +89 -9
- 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 +15 -3
- package/src/openapi/parse.ts +127 -2
- package/src/openapi/references.ts +43 -3
- package/src/openapi/render-mdx.ts +68 -8
- package/src/openapi/sentence.ts +29 -2
- package/src/openapi/source.ts +39 -14
- package/src/ratelimit/index.ts +1 -1
- package/src/ratelimit/runtime.ts +37 -19
- package/src/ratelimit/upstash.ts +40 -10
- package/src/reference/graphql.ts +15 -1
- package/src/reference/index.ts +1 -0
- package/src/reference/openapi.ts +2 -2
- package/src/reference/options.ts +29 -1
- package/src/registry/eject.ts +8 -2
- 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/orama-index.ts +163 -31
- package/src/search/source-pages.ts +29 -0
- package/src/search/sync/algolia.ts +99 -9
- package/src/search/sync/index.ts +52 -13
- package/src/search/sync/typesense.ts +72 -27
- package/src/seo/jsonld.ts +38 -20
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/notion.ts +7 -0
- package/src/sources/shared.ts +3 -0
- package/src/theme/color.ts +9 -10
- package/src/theme/entry.ts +43 -6
- package/src/translate/validate.ts +23 -1
- package/dist/cli/chunk-0gz36akr.js.map +0 -12
- package/dist/cli/chunk-2n4ps1b3.js.map +0 -15
- package/dist/cli/chunk-43zcf4gz.js.map +0 -36
- package/dist/cli/chunk-4ejxbzee.js +0 -39
- package/dist/cli/chunk-4ejxbzee.js.map +0 -10
- package/dist/cli/chunk-4h8z9vv5.js.map +0 -16
- package/dist/cli/chunk-713mngdq.js.map +0 -14
- package/dist/cli/chunk-9xr4dgee.js.map +0 -10
- package/dist/cli/chunk-amrb6hgh.js +0 -145
- package/dist/cli/chunk-amrb6hgh.js.map +0 -11
- package/dist/cli/chunk-nd1821sk.js.map +0 -10
- package/dist/cli/chunk-rekqz4qg.js.map +0 -10
- package/dist/cli/chunk-ta27feev.js.map +0 -10
- package/dist/cli/chunk-xkz5xbtv.js.map +0 -213
- package/dist/cli/chunk-y5h4r2y0.js.map +0 -10
- package/dist/cli/chunk-zf748avv.js.map +0 -37
- /package/dist/cli/{chunk-9geymqns.js.map → chunk-0w6hs479.js.map} +0 -0
- /package/dist/cli/{chunk-y4ykbark.js.map → chunk-1f882900.js.map} +0 -0
- /package/dist/cli/{chunk-py62fewh.js.map → chunk-53jqw8z0.js.map} +0 -0
- /package/dist/cli/{chunk-5wj2qwn2.js.map → chunk-58bt3hag.js.map} +0 -0
- /package/dist/cli/{chunk-e7vvk5ya.js.map → chunk-5cmts6dv.js.map} +0 -0
- /package/dist/cli/{chunk-g2z9x01v.js.map → chunk-9qzgg6mj.js.map} +0 -0
- /package/dist/cli/{chunk-q3wxxq39.js.map → chunk-a57yh0h9.js.map} +0 -0
- /package/dist/cli/{chunk-2f3ndkpw.js.map → chunk-desvm72z.js.map} +0 -0
- /package/dist/cli/{chunk-gp84za0h.js.map → chunk-dhwtqnnd.js.map} +0 -0
- /package/dist/cli/{chunk-2f7n4qzt.js.map → chunk-dqhg54mr.js.map} +0 -0
- /package/dist/cli/{chunk-zhvd6adm.js.map → chunk-gfc5fqvf.js.map} +0 -0
- /package/dist/cli/{chunk-p804f3pe.js.map → chunk-hvcxng5f.js.map} +0 -0
- /package/dist/cli/{chunk-1n228xqb.js.map → chunk-kdpzw38a.js.map} +0 -0
- /package/dist/cli/{chunk-6bm0xpgd.js.map → chunk-s0bdnc7v.js.map} +0 -0
- /package/dist/cli/{chunk-cmtcnh9f.js.map → chunk-tfycddbt.js.map} +0 -0
- /package/dist/cli/{chunk-ntv4qrt7.js.map → chunk-y4msrwm9.js.map} +0 -0
- /package/dist/cli/{chunk-yj17vs39.js.map → chunk-ydp3065p.js.map} +0 -0
package/docs/02-deployment.mdx
CHANGED
|
@@ -16,7 +16,16 @@ sidebar:
|
|
|
16
16
|
| Output directory | `dist` |
|
|
17
17
|
| Node version | 22.12 or newer |
|
|
18
18
|
|
|
19
|
-
These settings work on Vercel, Netlify, Cloudflare Pages, GitHub Pages,
|
|
19
|
+
These settings work on Vercel, Netlify, Cloudflare Pages, GitHub Pages, or any bucket or CDN. Make sure `blume` is a dependency so the host can run the build.
|
|
20
|
+
|
|
21
|
+
Amazon S3 behind CloudFront, with a private bucket read through origin access control, needs two more pieces, because the S3 REST endpoint looks up each key exactly and serves each file with the type it was uploaded with:
|
|
22
|
+
|
|
23
|
+
- A CloudFront Function on viewer requests that maps each page URL to the `index.html` Blume writes for it: `/quickstart` to `/quickstart/index.html`, and `/` (or any path ending in `/`) to its `index.html`. Leave a path whose last segment has a dot (`/quickstart.md`, `/_astro/app.js`) unchanged, and keep the function off `/.well-known/*`, whose `api-catalog` has no extension. Without it, S3 answers `/quickstart` with a `403` or `404`.
|
|
24
|
+
- Uploads that set the types a guess from the file extension gets wrong or leaves without a charset: `text/markdown; charset=utf-8` for `.md` and `.mdx`, `text/plain; charset=utf-8` for `.txt`, and `application/linkset+json; profile="https://www.rfc-editor.org/info/rfc9727"` for `.well-known/api-catalog`. `dist/_headers` lists every rule your build needs.
|
|
25
|
+
|
|
26
|
+
The [S3 and CloudFront guide](/guides/s3-cloudfront-documentation-site) has a CloudFormation template with the function and a deploy script that uploads with these types.
|
|
27
|
+
|
|
28
|
+
On Cloudflare Workers, which serves a static build as static assets, set `"html_handling": "drop-trailing-slash"` under `assets` in your Wrangler config. Blume writes each page as `<route>/index.html` and links to it without a trailing slash, and Cloudflare's default (`auto-trailing-slash`) answers `/quickstart` with a `307` to `/quickstart/`. A [`cloudflare()` server build](#server-rendering) routes every page through its Worker, which serves `/quickstart` under either setting, so there it only matters when the build warns `Could not wire Accept: text/markdown negotiation` and the static layer serves the pages itself.
|
|
20
29
|
|
|
21
30
|
A static build includes:
|
|
22
31
|
|
|
@@ -40,10 +49,14 @@ deployment: {
|
|
|
40
49
|
}
|
|
41
50
|
```
|
|
42
51
|
|
|
43
|
-
On Vercel and Netlify, automatic detection prefers your stable production domain over per-deploy preview URLs, so the canonical origin stays put across deploys. Cloudflare Pages exposes only the current deployment's URL (`CF_PAGES_URL`), which changes with every deploy, so set `site` there.
|
|
52
|
+
On Vercel and Netlify, automatic detection prefers your stable production domain over per-deploy preview URLs, so the canonical origin stays put across deploys. Cloudflare Pages exposes only the current deployment's URL (`CF_PAGES_URL`), which changes with every deploy, so set `site` there. Cloudflare Workers exposes none, so set `site` on Workers too.
|
|
44
53
|
|
|
45
54
|
During `blume dev`, the site URL falls back to your local dev server (e.g. `http://localhost:4321`) when none is set, so site-gated features — Open Graph images, canonicals, the sitemap — work out of the box. Builds never use this fallback, so production output is never pointed at localhost.
|
|
46
55
|
|
|
56
|
+
### Monorepos
|
|
57
|
+
|
|
58
|
+
Deploy the docs workspace as its own project, with the host's root directory set to it (Vercel's **Root Directory**, Netlify's **Base directory**) and the settings above. On Vercel, leave **Include source files outside of the Root Directory in the Build Step** on, which is the default, whenever the docs read files outside their workspace: [component examples](/docs/content/components#component) or a workspace package they import, an `@source` path in `theme.css`, or a spec elsewhere in the repository. With it off, the build can't reach those files. The [monorepo guide](/guides/monorepo-documentation-site) walks through a pnpm and Turborepo setup.
|
|
59
|
+
|
|
47
60
|
## Preview locally
|
|
48
61
|
|
|
49
62
|
Before you ship, preview the production build exactly as a static host would serve it:
|
|
@@ -65,10 +78,26 @@ deployment: {
|
|
|
65
78
|
}
|
|
66
79
|
```
|
|
67
80
|
|
|
68
|
-
`base` (and `site`) are options of every host adapter too: `vercel({ base: "/docs" })`.
|
|
81
|
+
`base` (and `site`) are options of every host adapter too: `vercel({ base: "/docs" })`. `@astrojs/vercel` ignores the base, so a `vercel()` server build moves the static files to `.vercel/output/static/docs/` and the routes and redirects in `.vercel/output/config.json` under `/docs` itself.
|
|
69
82
|
|
|
70
83
|
Every page keeps its own path under the base, even in a content folder that shares the base's name: with `base: "/docs"`, `docs/setup.md` is served at `/docs/docs/setup`, and its canonical URL, sidebar link, and `llms.txt` entry point there. A root-relative link you write that already starts with the base is taken to include it and left as written, so link to that page with a relative link (`./docs/setup`) or its full path (`/docs/docs/setup`).
|
|
71
84
|
|
|
85
|
+
### A different base per deploy
|
|
86
|
+
|
|
87
|
+
`blume.config.ts` is a module, so `base` can come from an environment variable. That lets CI build each pull request's preview under its own path without editing the config:
|
|
88
|
+
|
|
89
|
+
```ts blume.config.ts lineNumbers
|
|
90
|
+
deployment: {
|
|
91
|
+
base: process.env.DOCS_BASE,
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
DOCS_BASE=/pr-1234 blume build
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
With `DOCS_BASE` unset, the site builds at the root, so production needs nothing extra.
|
|
100
|
+
|
|
72
101
|
## Mount the docs under a path
|
|
73
102
|
|
|
74
103
|
`basePath` mounts every generated route under a segment (`/docs/getting-started`) while leaving the sidebar untouched — the top level is your sections, not a wrapper group. Use it when the docs live at `/docs/*` but the site root stays yours (like Docusaurus `routeBasePath` or Fumadocs `baseUrl`).
|
|
@@ -112,9 +141,9 @@ deployment: vercel({
|
|
|
112
141
|
| `vercel()` | `@astrojs/vercel` | Vercel — the most polished path |
|
|
113
142
|
| `netlify()` | `@astrojs/netlify` | Netlify Functions |
|
|
114
143
|
| `node()` | `@astrojs/node` | Self-hosted Node servers, containers |
|
|
115
|
-
| `cloudflare()` | `@astrojs/cloudflare` | Cloudflare Workers
|
|
144
|
+
| `cloudflare()` | `@astrojs/cloudflare` | Cloudflare Workers |
|
|
116
145
|
|
|
117
|
-
`vercel()` and `node()` ship with Blume — choosing one just works. `netlify()` and `cloudflare()` need their package installed in your project (e.g. `bun add -d @astrojs/netlify`). If it's missing, `blume build` stops with the install command for your package manager, `blume dev` warns, and [`blume doctor`](/docs/cli/doctor) reports it. With pnpm
|
|
146
|
+
`vercel()` and `node()` ship with Blume — choosing one just works. `netlify()` and `cloudflare()` need their package installed in your project (e.g. `bun add -d @astrojs/netlify`). If it's missing, `blume build` stops with the install command for your package manager, `blume dev` warns, and [`blume doctor`](/docs/cli/doctor) reports it. With pnpm, also approve the build scripts those packages bring under `allowBuilds` in `pnpm-workspace.yaml`, beside the `esbuild` entry `blume init` writes: `sharp` for Netlify, whose adapter pulls in its own copy, and `workerd` for Cloudflare. pnpm 11 and later stop the install with `ERR_PNPM_IGNORED_BUILDS` until you approve them; pnpm 10 skips the scripts with a warning. `allowBuilds` needs pnpm 10.26 or later.
|
|
118
147
|
|
|
119
148
|
Naming an adapter switches the build to server output. To keep a static build on that host — with its site detection and the platform files it reads — pass `output: "static"`:
|
|
120
149
|
|
|
@@ -122,9 +151,9 @@ Naming an adapter switches the build to server output. To keep a static build on
|
|
|
122
151
|
deployment: netlify({ output: "static" }),
|
|
123
152
|
```
|
|
124
153
|
|
|
125
|
-
A server build includes everything a static build does, plus any Astro endpoints or middleware you add. The `node()` adapter produces a standalone server you can run directly with `node dist/server/entry.mjs`. It listens on `localhost:4321` unless you set the `HOST` and `PORT` environment variables when you start it (`HOST=0.0.0.0 PORT=8080 node dist/server/entry.mjs`); `host` and `port` passed to `node()` have no effect, because `@astrojs/node` replaces them with Astro's own server settings. The server resolves its packages through links into your project's `node_modules`, so deploy the project with its installed dependencies, not `dist/` alone. When the site publishes discovery files, serves images a content source downloaded, or configures redirects, Blume puts a small wrapper in front of Astro's entry (moved to `astro-entry.mjs` beside it). It sends the `.well-known` discovery files with their media types and CORS headers and downloaded SVGs sandboxed, which the standalone server's static handler can't do on its own, and answers each redirect with its configured status.
|
|
154
|
+
A server build includes everything a static build does, plus any Astro endpoints or middleware you add. The `node()` adapter produces a standalone server you can run directly with `node dist/server/entry.mjs`. It listens on `localhost:4321` unless you set the `HOST` and `PORT` environment variables when you start it (`HOST=0.0.0.0 PORT=8080 node dist/server/entry.mjs`); `host` and `port` passed to `node()` have no effect, because `@astrojs/node` replaces them with Astro's own server settings. Behind a reverse proxy, set `allowedDomains` so the [rate limit](/docs/configuration/rate-limiting#behind-a-reverse-proxy) counts each reader apart. The server resolves its packages through links into your project's `node_modules`, so deploy the project with its installed dependencies, not `dist/` alone. When the site publishes discovery files, serves images a content source downloaded, or configures redirects, Blume puts a small wrapper in front of Astro's entry (moved to `astro-entry.mjs` beside it). It sends the `.well-known` discovery files with their media types and CORS headers and downloaded SVGs sandboxed, which the standalone server's static handler can't do on its own, and answers each redirect with its configured status.
|
|
126
155
|
|
|
127
|
-
A `cloudflare()` server build deploys with `npx wrangler deploy` from the project root after `blume build`: Blume writes the redirected Wrangler config to `.wrangler/deploy/` (and adds `.wrangler/` to `.gitignore`), and names the Worker after your project — the `package.json` `name`, else the site's hostname, else the folder — unless a `wrangler.jsonc` of your own at the project root sets `name`.
|
|
156
|
+
A `cloudflare()` server build runs on Cloudflare Workers only, since `@astrojs/cloudflare` dropped Cloudflare Pages in version 13; a static build doesn't load the package, so its `dist/` still deploys to Pages. The server build deploys with `npx wrangler deploy` from the project root after `blume build`: Blume writes the redirected Wrangler config to `.wrangler/deploy/` (and adds `.wrangler/` to `.gitignore`), and names the Worker after your project — the `package.json` `name`, else the site's hostname, else the folder — unless a `wrangler.jsonc` of your own at the project root sets `name`.
|
|
128
157
|
|
|
129
158
|
On Vercel and Cloudflare, a server build also turns on [`Accept: text/markdown` content negotiation](/docs/discoverability/markdown#content-negotiation), so an agent requesting any content page with that header receives its raw-Markdown mirror at the same URL. On Vercel, Blume splices header-conditional rewrites into the deploy's routing config; on Cloudflare, it generates a small Worker in front of the Astro one and points `assets.run_worker_first` at every path except the fingerprinted build assets and the raw `.md`, `.txt`, `.json`, and `.well-known` files, since the platform would otherwise serve the prerendered pages — and its `404.html` for a URL no page backs — before any server code runs; those exempted files keep their zero-Worker fast path. That Worker also answers the prerendered per-page JSON documents (`/api/docs/pages/{route}.json`) from the asset binding when a request for one reaches it, because Astro would otherwise route it to the `/api/` catch-all.
|
|
130
159
|
|
|
@@ -161,7 +190,9 @@ Map old URLs to new ones in `blume.config.ts`:
|
|
|
161
190
|
redirects: [{ from: "/old", to: "/new", status: 301 }],
|
|
162
191
|
```
|
|
163
192
|
|
|
164
|
-
`status` accepts `301`, `302`, `307`, or `308` (default `301`). Server builds answer redirects at request time with the configured status
|
|
193
|
+
`status` accepts `301`, `302`, `307`, or `308` (default `301`). Server builds answer redirects at request time with the configured status, and so does `blume dev`. Static builds emit redirect pages **and** the platform files your host reads, so it issues a real HTTP redirect: `_redirects` for `netlify()` and `cloudflare()`, `vercel.json` for `vercel()`, and — when no host is named — both of those plus `blume-redirects.json`, a structured manifest for anything else (nginx/Apache rules, an edge worker). A `_redirects` or `vercel.json` you ship in `public/` is left untouched.
|
|
194
|
+
|
|
195
|
+
A redirect that moves one page to another moves the page's [raw Markdown](/docs/discoverability/markdown#raw-markdown) with it: `/old.md` and `/old.mdx` redirect to `/new.md` and `/new.mdx` with the same status, in `blume dev` and every build.
|
|
165
196
|
|
|
166
197
|
Two hosts need more than the file:
|
|
167
198
|
|
|
@@ -193,24 +224,39 @@ redirects: [
|
|
|
193
224
|
|
|
194
225
|
Each host gets the patterns in its own syntax: splats in `_redirects`, `path-to-regexp` sources in `vercel.json`, and the routing config of a `vercel()` or `netlify()` server build. The `node()` and `cloudflare()` servers match them themselves, and so does `blume dev`. A static build writes no redirect page for a pattern, since it would need one for every path the pattern covers, so a host that reads none of these files (GitHub Pages, say) applies only the exact redirects; `blume-redirects.json` lists patterns as you wrote them.
|
|
195
226
|
|
|
196
|
-
A pattern can't also match a page: hosts disagree on which of the two answers, so the build stops with `BLUME_REDIRECT_MATCHES_PAGE`, naming the page. Narrow the pattern to the paths that moved.
|
|
227
|
+
A pattern can't also match a page: hosts disagree on which of the two answers, so the build stops with `BLUME_REDIRECT_MATCHES_PAGE`, naming the page. Narrow the pattern to the paths that moved. An exact redirect from a page's own URL answers the same way on every host, taking the URL over so the page never publishes, so the same code is a warning there: delete the page if it moved, or drop the redirect.
|
|
197
228
|
|
|
198
229
|
## Content types
|
|
199
230
|
|
|
200
231
|
Where the host reads one, a build also emits a `_headers` file that pins `charset=utf-8` onto the raw AI-ready endpoints — `/<route>.md`, `/<route>.mdx`, and the `.txt` files (`llms.txt`, `llms-full.txt`). Those responses are valid UTF-8, but many static hosts serve them as `text/markdown` / `text/plain` with **no** charset, and browsers then fall back to Windows-1252 — so non-ASCII docs (Japanese, accented Latin, …) render as mojibake when the raw URL is opened directly. HTML pages are unaffected because they carry `<meta charset>`. Netlify reads `_headers` on a static deploy and Cloudflare (Pages, and Workers static assets) on both static and server builds, so those adapters and an unnamed static host get the file; Vercel (whose headers ride the routing config) and Node (whose server ignores the file) don't. A Netlify server build writes the same rules into the `headers` of its Frameworks API config (`.netlify/v1/config.json`) instead. A static Vercel build writes the same rules into `dist/vercel.json` instead, which a Git-connected project doesn't read (see [Redirects](#redirects)). A `_headers` you ship in `public/` is left untouched.
|
|
201
232
|
|
|
233
|
+
## Powered-by header
|
|
234
|
+
|
|
235
|
+
Blume names itself in an `X-Powered-By: Blume` response header, so HTTP inspectors and technology detectors can tell what built the site. Set `poweredBy` to `false` to leave it out:
|
|
236
|
+
|
|
237
|
+
```ts blume.config.ts
|
|
238
|
+
poweredBy: false,
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
`blume dev` sends it on every response. A server build sends it wherever the host takes its headers from: the `node()` server and the `cloudflare()` Worker set it themselves, a `vercel()` build carries it in its routing config, and a `netlify()` build in the header rules of its Frameworks API config, with Blume's middleware adding it to the pages rendered on demand. A static build lists it in `_headers` and `dist/vercel.json` beside the [content types](#content-types), so it reaches the hosts those files reach: not a Git-connected Vercel project, and not a host that sends no custom headers, such as GitHub Pages.
|
|
242
|
+
|
|
243
|
+
In an [ejected](/docs/configuration/customization#eject) app, the switch is the `poweredBy` option of `blumeIntegration()` in `astro.config.mjs`. Its build sends the header on server-rendered pages and from `_headers`; the server-entry wrapper and routing configs that carry it elsewhere are `blume build` steps.
|
|
244
|
+
|
|
202
245
|
## Environment variables
|
|
203
246
|
|
|
204
|
-
When a feature needs a
|
|
247
|
+
When a feature needs a secret, Blume warns at `blume dev`/`build` if it's missing — so the problem surfaces early instead of at the first request:
|
|
205
248
|
|
|
206
249
|
| Feature | Variable |
|
|
207
250
|
| --- | --- |
|
|
208
251
|
| Assistant (AI Gateway) | `AI_GATEWAY_API_KEY` (or Vercel OIDC) |
|
|
209
252
|
| Assistant (other adapters) | the adapter's default key env var (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, `XAI_API_KEY`, `OPENROUTER_API_KEY`, `LLMGATEWAY_API_KEY`, `INKEEP_API_KEY`), or the `apiKeyEnv` you passed it |
|
|
253
|
+
| [Assistant bot protection](/docs/configuration/assistant#bot-protection) | `TURNSTILE_SECRET_KEY` (`turnstile()`), `HCAPTCHA_SECRET_KEY` (`hcaptcha()`) |
|
|
254
|
+
| [Rate limiting](/docs/configuration/rate-limiting) (`upstash()`) | `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` |
|
|
210
255
|
| Mixedbread search | `MIXEDBREAD_API_KEY` |
|
|
211
|
-
| [
|
|
256
|
+
| [Narration](/docs/configuration/narration) (generated voices) | `AI_GATEWAY_API_KEY` (or Vercel OIDC) for `gateway()`, `OPENAI_API_KEY` for `openai()` (none with a `baseUrl`, unless you name one), or the `apiKeyEnv` you passed to either |
|
|
257
|
+
| [Content sources](/docs/content/sources) | `NOTION_TOKEN` (`notion()`), `SANITY_TOKEN` (`sanity()`), `CONTENTFUL_ACCESS_TOKEN` (`contentful()`, plus `CONTENTFUL_PREVIEW_TOKEN` for `--preview`, which fails without it), `PAYLOAD_API_KEY` (`payload()`), `STRAPI_API_TOKEN` (`strapi()`), `GITHUB_TOKEN` (`githubReleases()`, and `mdxRemote()` reading from GitHub) |
|
|
212
258
|
|
|
213
|
-
Set them in `.env.local` for local dev and in your host's environment for production. A content source reads its token when it fetches, during `blume dev` and `blume build`, so set
|
|
259
|
+
Set them in `.env.local` for local dev and in your host's environment for production. A content source reads its token when it fetches, during `blume dev` and `blume build`, and narration reads its key during `blume build`, so set those where your site builds. Build-time secrets for search-index sync (`ALGOLIA_ADMIN_API_KEY`, `ORAMA_PRIVATE_API_KEY`, `TYPESENSE_ADMIN_API_KEY`) are checked by the sync step itself: when one is unset, the build warns and skips the sync, and when it's set, a failed sync [fails the build](/docs/configuration/search#adapters). The [GitHub info](/docs/content/components#github-info) card also sends `GITHUB_TOKEN`, when it's set, to lift GitHub's API rate limit.
|
|
214
260
|
|
|
215
261
|
## Build cache
|
|
216
262
|
|
|
@@ -222,7 +268,7 @@ Blume keeps two caches a build can reuse. Astro's and Vite's caches live under `
|
|
|
222
268
|
- **GitHub Actions** and other runners you manage keep nothing unless you cache the directory yourself:
|
|
223
269
|
|
|
224
270
|
```yaml
|
|
225
|
-
- uses: actions/cache@
|
|
271
|
+
- uses: actions/cache@v6
|
|
226
272
|
with:
|
|
227
273
|
path: node_modules/.cache/blume/og
|
|
228
274
|
key: blume-og-${{ runner.os }}-${{ hashFiles('**/bun.lock', '**/package-lock.json', '**/pnpm-lock.yaml') }}
|
package/docs/03-upgrading.mdx
CHANGED
|
@@ -88,7 +88,7 @@ export default defineConfig({
|
|
|
88
88
|
- `netlify()`, `cloudflare()`, and `node()` work the same way. Naming a host adapter switches to server output; pass `output: "static"` to keep a static build with that host's platform files.
|
|
89
89
|
- A config that only sets `site` or `base` stays as it is: `deployment: { site, base }` is still the static form.
|
|
90
90
|
- `redirects` read `:name` segments and a trailing `*` as patterns, matched the same way on every host (see [Pattern redirects](/docs/deployment#pattern-redirects)). Blume 1 never supported patterns and handed them to each host as written, so check any `from` or `to` that holds one.
|
|
91
|
-
- The `--adapter`, `--output`, and `--base` flags on `blume build` are gone, and passing one stops the build with an error naming the `deployment` setting that replaces it. Set the adapter in `blume.config.ts`, and name it explicitly: server output is no longer inferred from the platform's environment.
|
|
91
|
+
- The `--adapter`, `--output`, and `--base` flags on `blume build` are gone, and passing one stops the build with an error naming the `deployment` setting that replaces it. Set the adapter in `blume.config.ts`, and name it explicitly: server output is no longer inferred from the platform's environment. A CI step that passed a different `--base` per deploy can [read it from an environment variable](/docs/deployment#a-different-base-per-deploy) in the config instead.
|
|
92
92
|
|
|
93
93
|
See [Deployment](/docs/deployment) for each adapter's options.
|
|
94
94
|
|
|
@@ -133,6 +133,7 @@ export default defineConfig({
|
|
|
133
133
|
- `mdx-remote`, `sanity`, `notion`, and `obsidian` become `mdxRemote()`, `sanity()`, `notion()`, and `obsidian()`, with every other field moving into the call unchanged. `{ type: "custom", source }` becomes `custom(source)`.
|
|
134
134
|
- `content.root`, `content.include`, and `content.exclude` are still the shorthand for a single folder, but they can't sit beside `sources` any more. Move them into the `filesystem()` entry.
|
|
135
135
|
- Release pages from `githubReleases()` publish in one language now, so a multi-locale site no longer copies them to every other locale's URL (`/de/changelog/…`). If other sites link to those copies, add [redirects](/docs/deployment#redirects) to the default-locale pages.
|
|
136
|
+
- Text typed in Notion renders as written now: a component, `{`, or Markdown character in a `notion()` page shows as typed instead of being read as MDX. If your Notion pages hold components or Markdown typed as text, set [`mdx: true`](/docs/content/sources/notion#writing-mdx-in-notion) on the source.
|
|
136
137
|
|
|
137
138
|
## API references
|
|
138
139
|
|
package/docs/04-migrating.mdx
CHANGED
|
@@ -22,15 +22,15 @@ Swap `fumadocs` for your framework, and `--codex` for `--claude` to use Claude C
|
|
|
22
22
|
|
|
23
23
|
Name the framework you're migrating from, or leave it out and Blume detects it from the project's own files. When you name one and the project looks like another, Blume warns and continues with the one you named:
|
|
24
24
|
|
|
25
|
-
| Source | Detected from |
|
|
26
|
-
| --- | --- |
|
|
27
|
-
| `mintlify` | `docs.json` or `mint.json` |
|
|
28
|
-
| `fumadocs` | `source.config.ts`, or `fumadocs-core`, `fumadocs-ui`, or `fumadocs-mdx` in `package.json` |
|
|
29
|
-
| `docusaurus` | `docusaurus.config.*` |
|
|
30
|
-
| `starlight` | `@astrojs/starlight` in `package.json` |
|
|
31
|
-
| `nextra` | `nextra` in `package.json` |
|
|
32
|
-
|
|
33
|
-
Each source has its own mapping reference in the playbook. A site built with anything else still migrates: run the command without a source, and the agent inventories the repo first, then works from the playbook's general rules.
|
|
25
|
+
| Source | Detected from | Guide |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| `mintlify` | `docs.json` or `mint.json` | [Migrate from Mintlify](/guides/migrate-from-mintlify) |
|
|
28
|
+
| `fumadocs` | `source.config.ts`, or `fumadocs-core`, `fumadocs-ui`, or `fumadocs-mdx` in `package.json` | [Migrate from Fumadocs](/guides/migrate-from-fumadocs) |
|
|
29
|
+
| `docusaurus` | `docusaurus.config.*` | [Migrate from Docusaurus](/guides/migrate-from-docusaurus) |
|
|
30
|
+
| `starlight` | `@astrojs/starlight` in `package.json` | [Migrate from Starlight](/guides/migrate-from-starlight) |
|
|
31
|
+
| `nextra` | `nextra` in `package.json` | [Migrate from Nextra](/guides/migrate-from-nextra) |
|
|
32
|
+
|
|
33
|
+
Each source has its own mapping reference in the playbook. A site built with anything else still migrates: run the command without a source, and the agent inventories the repo first, then works from the playbook's general rules. The [MkDocs Material guide](/guides/migrate-from-mkdocs-material) walks through a migration that way.
|
|
34
34
|
|
|
35
35
|
## What the agent does
|
|
36
36
|
|
package/docs/08-faq.mdx
CHANGED
|
@@ -87,18 +87,18 @@ We reported it upstream in [oxc-project/oxc#24096](https://github.com/oxc-projec
|
|
|
87
87
|
|
|
88
88
|
Patch oxfmt so it preserves the line break that sits directly against a `:::` fence. Blume ships the same fix in its own repo, and you can apply it in any project.
|
|
89
89
|
|
|
90
|
-
1. Save the patch as `patches/oxfmt@0.
|
|
91
|
-
|
|
92
|
-
```diff patches/oxfmt@0.
|
|
93
|
-
diff --git a/dist/markdown-
|
|
94
|
-
index
|
|
95
|
-
--- a/dist/markdown-
|
|
96
|
-
+++ b/dist/markdown-
|
|
97
|
-
@@ -
|
|
90
|
+
1. Save the patch as `patches/oxfmt@0.71.0.patch`:
|
|
91
|
+
|
|
92
|
+
```diff patches/oxfmt@0.71.0.patch
|
|
93
|
+
diff --git a/dist/markdown-gizI1LFO.js b/dist/markdown-gizI1LFO.js
|
|
94
|
+
index 95a638402fa6f73b29ebb8d7a7ef229bee68a690..e2e2ea5b443fe10698c49c2ef3dc3d5909335915 100644
|
|
95
|
+
--- a/dist/markdown-gizI1LFO.js
|
|
96
|
+
+++ b/dist/markdown-gizI1LFO.js
|
|
97
|
+
@@ -4898,7 +4898,43 @@ function lu(e, t, r) {
|
|
98
98
|
case "sentence": return Oh(e, r);
|
|
99
99
|
case "word": return t.parser !== "mdx" ? zh(e, t) : Uh(e);
|
|
100
100
|
case "whitespace": {
|
|
101
|
-
- let { next: a } = e, u = a && /^>|^(?:[*+-]|#{1,6}|\d+[).])$/.test(a.value) && !
|
|
101
|
+
- let { next: a } = e, u = a && /^>|^(?:[*+-]|#{1,6}|\d+[).])$/.test(a.value) && !RE(e) && !(t.proseWrap === "preserve" && ME(e)) ? "never" : t.proseWrap;
|
|
102
102
|
+ let { next: a, previous: oxfmtFencePrev } = e;
|
|
103
103
|
+ // Preserve line breaks that sit directly against a `:::` container
|
|
104
104
|
+ // directive fence, so `proseWrap: "never"` keeps the opening/closing
|
|
@@ -135,7 +135,7 @@ Patch oxfmt so it preserves the line break that sits directly against a `:::` fe
|
|
|
135
135
|
+ }
|
|
136
136
|
+ oxfmtPrevIsTitledFence = oxfmtIsFence(oxfmtLineFirst);
|
|
137
137
|
+ }
|
|
138
|
-
+ let u = oxfmtIsFence(oxfmtFencePrev) || oxfmtPrevIsTitledFence || oxfmtIsFence(a) ? "preserve" : a && /^>|^(?:[*+-]|#{1,6}|\d+[).])$/.test(a.value) && !
|
|
138
|
+
+ let u = oxfmtIsFence(oxfmtFencePrev) || oxfmtPrevIsTitledFence || oxfmtIsFence(a) ? "preserve" : a && /^>|^(?:[*+-]|#{1,6}|\d+[).])$/.test(a.value) && !RE(e) && !(t.proseWrap === "preserve" && ME(e)) ? "never" : t.proseWrap;
|
|
139
139
|
return ou(e, n.value, u, !1, t);
|
|
140
140
|
}
|
|
141
141
|
case "emphasis": {
|
|
@@ -146,7 +146,7 @@ Patch oxfmt so it preserves the line break that sits directly against a `:::` fe
|
|
|
146
146
|
```json package.json
|
|
147
147
|
{
|
|
148
148
|
"patchedDependencies": {
|
|
149
|
-
"oxfmt@0.
|
|
149
|
+
"oxfmt@0.71.0": "patches/oxfmt@0.71.0.patch"
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
```
|
|
@@ -155,7 +155,7 @@ Patch oxfmt so it preserves the line break that sits directly against a `:::` fe
|
|
|
155
155
|
|
|
156
156
|
```yaml pnpm-workspace.yaml
|
|
157
157
|
patchedDependencies:
|
|
158
|
-
oxfmt@0.
|
|
158
|
+
oxfmt@0.71.0: patches/oxfmt@0.71.0.patch
|
|
159
159
|
```
|
|
160
160
|
|
|
161
161
|
3. Reinstall so the patch is applied:
|
|
@@ -62,9 +62,18 @@ Once you have at least one `type: changelog` entry, Blume generates a **`/change
|
|
|
62
62
|
- The date follows the configured [`dateFormat`](/docs/configuration#date-format), minus the year the row's group already shows.
|
|
63
63
|
- Drafts and `sidebar.hidden` entries are skipped.
|
|
64
64
|
|
|
65
|
-
The page
|
|
65
|
+
The page is headed **Changelog** (in English), with a one-line description below. Set your own with `changelog` in your config; they also become the page's `<title>`, meta description, and OG card, and the top of its Markdown mirror at `/changelog.md`:
|
|
66
|
+
|
|
67
|
+
```ts blume.config.ts
|
|
68
|
+
changelog: {
|
|
69
|
+
title: "Release notes",
|
|
70
|
+
description: "Every Acme SDK release, newest first.",
|
|
71
|
+
},
|
|
72
|
+
```
|
|
66
73
|
|
|
67
|
-
|
|
74
|
+
Each takes a map of locale code to text too, like a [header tab label](/docs/content/i18n#per-locale-navigation). The index renders in the default locale, so it shows that locale's entry. Leave either unset and it keeps the built-in text, which a [UI string override](/docs/content/i18n#translated-ui) (`changelog.title` and `changelog.description` under `i18n.ui`) replaces.
|
|
75
|
+
|
|
76
|
+
The page appears only when nothing already occupies the `/changelog` route. To replace it with your own design, add a [custom page](/docs/advanced/custom-pages) at `pages/changelog.astro` — it takes over and Blume stops generating the default index. The `<Update>` component the previous timeline was built from still ships for a custom page that wants inline release notes. It isn't one of the MDX components, so import it in the `.astro` page itself: `import Update from "blume/components/content/Update.astro";`.
|
|
68
77
|
|
|
69
78
|
## From GitHub Releases
|
|
70
79
|
|
|
@@ -87,6 +96,25 @@ content: {
|
|
|
87
96
|
|
|
88
97
|
The release name becomes the title, its tag becomes `changelog.version`, and its published date sorts the timeline. Each release page also gets a unique meta description summarized from its notes — markdown stripped, section headings and changeset commit-hash prefixes dropped, trimmed to the search-snippet length [`blume audit`](/docs/cli/audit) checks for — instead of falling back to the site description. A private repo authenticates with the `GITHUB_TOKEN` environment variable. See [GitHub Releases](/docs/content/sources/github-releases) for every option.
|
|
89
98
|
|
|
99
|
+
## Keep entries out of the sidebar
|
|
100
|
+
|
|
101
|
+
Changelog entries are ordinary pages, so the generated sidebar lists them like any other: a `changelog/` folder, or a `githubReleases()` source with `prefix: "changelog"`, becomes a Changelog group, newest entry first, that grows with every release. Previous/next links run through it too, so the last docs page can lead into the newest release.
|
|
102
|
+
|
|
103
|
+
To keep the entries out of the docs sidebar, link the changelog with a header [tab](/docs/content/navigation#tabs) rather than a [header action](/docs/content/navigation#header-actions):
|
|
104
|
+
|
|
105
|
+
```ts blume.config.ts
|
|
106
|
+
navigation: {
|
|
107
|
+
tabs: [
|
|
108
|
+
{ label: "Docs", path: "/" },
|
|
109
|
+
{ label: "Changelog", path: "/changelog" },
|
|
110
|
+
],
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The `/changelog` tab opens the index, with no `href` needed, and owns the `changelog/` section: pages outside it stop listing the releases, and their previous/next links stay among the docs. An entry's own page shows the release list as its sidebar. The index, the [RSS feed](#the-rss-feed), `llms.txt`, the sitemap, and search still list every entry. The tab's `path` has to match the folder or `prefix` the entries live under. The `Docs` tab at `/` is optional; it gives readers a tab to return to.
|
|
115
|
+
|
|
116
|
+
Setting `sidebar.hidden` on the entries doesn't do this: it unlists them everywhere, the index and the feed included.
|
|
117
|
+
|
|
90
118
|
## The RSS feed
|
|
91
119
|
|
|
92
120
|
Blume also builds a changelog feed at **`/changelog/rss.xml`**, sorted newest-first by `date`. Feeds need an absolute site URL, so set [`deployment.site`](/docs/deployment); Blume then injects a `<link rel="alternate">` tag on every page so readers discover it automatically.
|
|
@@ -255,7 +255,7 @@ Passing `siteUrl` (and `ogEnabled`) derives the page's `canonical` and a generat
|
|
|
255
255
|
|
|
256
256
|
Only this page changes — every other route keeps its generated card — so it's how you give the home page alone a bespoke share image. The generated card declares its size and alt text to crawlers on its own; for your own `ogImage`, pass `ogImageAlt` and `ogImageSize` alongside so the share card gets the same treatment.
|
|
257
257
|
|
|
258
|
-
The page also emits schema.org JSON-LD — the same
|
|
258
|
+
The page also emits schema.org JSON-LD — the same graph the docs pages carry, with a `WebPage` node on the home page — so the home page (usually a custom page) isn't the one URL without structured data. A custom page has no content file to date, so pass `lastModified` (a date string or `Date`) to emit its `dateModified`; without a machine-readable date, search engines can take any other date the page shows as the page's own. Pass `structuredDataEnabled={config.structuredData}` to keep it in sync with the [`structuredData`](/docs/discoverability/structured-data) config, or `structuredDataEnabled={false}` to turn it off for one page.
|
|
259
259
|
|
|
260
260
|
`page.title` is used verbatim as the document title (no `- siteTitle` suffix), since marketing pages usually set their own. To give a custom page the full docs chrome instead — sidebar, TOC, and all — wrap it in `RootLayout`, the layout the generated pages use. Pull the required props straight from `blume:data`:
|
|
261
261
|
|
package/docs/advanced/skills.mdx
CHANGED
|
@@ -23,7 +23,7 @@ npx skills add haydenbleasel/blume --skill blume-migrate
|
|
|
23
23
|
|
|
24
24
|
## Self-updating docs
|
|
25
25
|
|
|
26
|
-
`blume-update-docs` keeps your docs in sync with the product they document. On each run — typically from a schedule you configure in your agent runner — it audits recently merged PRs, changelogs, config schemas, and CLI help against the docs content, updates only pages that are factually stale (feature-flagged work is ignored), verifies with `blume build`, and opens or updates a `blume/*` pull request. If nothing drifted, it reports a clean no-op instead of opening a noisy PR.
|
|
26
|
+
`blume-update-docs` keeps your docs in sync with the product they document. On each run — typically from a schedule you configure in your agent runner — it audits recently merged PRs, changelogs, config schemas, and CLI help against the docs content, updates only pages that are factually stale (feature-flagged work is ignored), verifies with `blume build` and `blume validate`, and opens or updates a `blume/*` pull request. If nothing drifted, it reports a clean no-op instead of opening a noisy PR.
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
npx skills add haydenbleasel/blume --skill blume-update-docs
|
package/docs/cli/audit.mdx
CHANGED
|
@@ -25,8 +25,9 @@ Findings are grouped by check rather than listed per page, so the report reads a
|
|
|
25
25
|
## Flags
|
|
26
26
|
|
|
27
27
|
- `--fail-on error|warning|info` — the CI gate: exit non-zero at this severity or above. Defaults to `error`; `--strict` is an alias for `--fail-on warning`.
|
|
28
|
-
- `--url <origin>` — also probe a live deployment for status codes, response headers, and
|
|
28
|
+
- `--url <origin>` — also probe a live deployment for status codes, response headers, and configured redirects.
|
|
29
29
|
- `--external` — probe outbound links over the network.
|
|
30
|
+
- `--ignore <glob>` — with `--external`, don't probe an outbound link whose URL matches the glob, like `--ignore "https://api.acme.example/**"`. Repeat the flag for more patterns. It matches the way [`blume validate --ignore`](/docs/cli/validate#flags) does, and internal links are always checked.
|
|
30
31
|
- `--only <check|category>` / `--skip <check|category>` — narrow the report to, or away from, these checks or categories (comma-separated). A term that names no check or category is an error that suggests the closest one, so a typo can't quietly empty the report.
|
|
31
32
|
- `--list-checks` — print every check the audit can report, then exit.
|
|
32
33
|
- `--verbose` — list every affected page with each finding's full detail, instead of the first few.
|
|
@@ -44,14 +45,18 @@ blume audit --fail-on warning # also fails on warnings
|
|
|
44
45
|
|
|
45
46
|
## Checking a live deployment
|
|
46
47
|
|
|
47
|
-
Some things only the real server can tell you: whether a page that exists in `dist/` actually 404s behind a bad rewrite, whether responses are compressed,
|
|
48
|
+
Some things only the real server can tell you: whether a page that exists in `dist/` actually 404s behind a bad rewrite, whether responses are compressed, whether an `X-Robots-Tag` header is quietly deindexing a page whose HTML looks perfectly fine, and whether each old URL in [`redirects`](/docs/deployment#redirects) really redirects where you configured it. Point the audit at a deployment to add those checks:
|
|
48
49
|
|
|
49
50
|
```bash
|
|
50
51
|
blume audit --url https://docs.example.com
|
|
51
52
|
blume audit --url https://docs.example.com --external # also probe outbound links
|
|
52
53
|
```
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
These requests go out as a plain HTTP client, not as a crawler: the audit doesn't send Googlebot's or an AI crawler's user agent, since a host's bot protection can block a client pretending to be one. A firewall or CDN rule that treats crawlers differently isn't exercised, so check it with the crawler's own tools, such as Google Search Console's URL Inspection.
|
|
56
|
+
|
|
57
|
+
The audit requests every exact redirect's old URL (a pattern names no single URL to request). One that 404s is an error. One that answers 200 is a warning: a host that doesn't read the redirect file the build wrote serves the build's meta-refresh page there instead of an HTTP redirect, which readers follow but crawlers may not. See [Redirects](/docs/deployment#redirects) for what each host reads.
|
|
58
|
+
|
|
59
|
+
Outbound links are graded rather than flatly failed: a 404 or 410, or a host name that doesn't resolve, is a broken link you can fix, while any other error status (a 401 or 403 from a site that turns bots away, a 429, a 5xx), a refused connection, or a timeout is usually rate limiting or someone else's outage and is reported as a warning. Leave out URLs the audit can't check from where it runs, like a placeholder domain or a local server, with `--ignore`.
|
|
55
60
|
|
|
56
61
|
## Fixing the findings with an agent
|
|
57
62
|
|
|
@@ -78,7 +83,7 @@ Limits worth stating plainly:
|
|
|
78
83
|
Anything the audit did not run is reported as skipped rather than silently passing:
|
|
79
84
|
|
|
80
85
|
```
|
|
81
|
-
⊘ network skipped — pass --url <origin> (
|
|
86
|
+
⊘ network skipped — pass --url <origin> (12 checks)
|
|
82
87
|
⊘ external skipped — pass --external (2 checks)
|
|
83
88
|
```
|
|
84
89
|
|
|
@@ -195,7 +200,7 @@ Fix: Give each page a distinct `description`.
|
|
|
195
200
|
|
|
196
201
|
`BLUME_AUDIT_DUPLICATE_CONTENT` · warning · from the built HTML
|
|
197
202
|
|
|
198
|
-
Fix: Merge the pages, or
|
|
203
|
+
Fix: Merge the pages, or point `seo.canonical` on all but one at the page to index.
|
|
199
204
|
|
|
200
205
|
### Indexability
|
|
201
206
|
|
|
@@ -273,6 +278,8 @@ Fix: Remove the X-Robots-Tag header, or align it with the page's robots meta.
|
|
|
273
278
|
|
|
274
279
|
Fix: Fix the link target, or create the page it points at.
|
|
275
280
|
|
|
281
|
+
Under [`deployment.base`](/docs/deployment#subpath-deploys), a root-relative link without the base is reported here, since the host serves nothing of this build there. A full URL on the same host outside the base isn't: that's how a page links to another app the host serves beside the docs.
|
|
282
|
+
|
|
276
283
|
#### Page has links to a redirect [#link-to-redirect]
|
|
277
284
|
|
|
278
285
|
`BLUME_AUDIT_LINK_TO_REDIRECT` · warning · from the built HTML
|
|
@@ -345,7 +352,7 @@ Fix: Use a real redirect in `blume.config.ts` instead of a meta refresh.
|
|
|
345
352
|
|
|
346
353
|
`BLUME_AUDIT_REDIRECT_SOURCE_IS_PAGE` · error · from the built HTML
|
|
347
354
|
|
|
348
|
-
Fix: Remove the redirect, or delete the page it shadows —
|
|
355
|
+
Fix: Remove the redirect, or delete the page it shadows — a path can't be both, and which one readers get depends on the host.
|
|
349
356
|
|
|
350
357
|
#### HTTPS to HTTP redirect [#redirect-to-http]
|
|
351
358
|
|
|
@@ -353,6 +360,14 @@ Fix: Remove the redirect, or delete the page it shadows — the page wins and th
|
|
|
353
360
|
|
|
354
361
|
Fix: Redirect to the HTTPS URL.
|
|
355
362
|
|
|
363
|
+
#### Live site doesn't redirect as configured [#redirect-not-served]
|
|
364
|
+
|
|
365
|
+
`BLUME_AUDIT_REDIRECT_NOT_SERVED` · error · needs `--url`
|
|
366
|
+
|
|
367
|
+
Fix: Deploy the redirect file your host reads (see Redirects in the deployment docs), or name the host in `deployment`.
|
|
368
|
+
|
|
369
|
+
A warning instead when the old URL answers 200 (the meta-refresh page) or redirects somewhere other than the configured destination.
|
|
370
|
+
|
|
356
371
|
### Social cards
|
|
357
372
|
|
|
358
373
|
#### Open Graph tags missing or incomplete [#og-incomplete]
|
|
@@ -509,7 +524,7 @@ Fix: Load the subresource over HTTPS — browsers block mixed content.
|
|
|
509
524
|
|
|
510
525
|
`BLUME_AUDIT_INDEXABLE_PAGE_NOT_IN_SITEMAP` · warning · from the built HTML
|
|
511
526
|
|
|
512
|
-
Fix: Remove `draft`/`hidden`/`noindex` from the page's frontmatter if it should be indexed.
|
|
527
|
+
Fix: Remove `draft`/`hidden`/`noindex` from the page's frontmatter if it should be indexed. A `public/sitemap.xml` replaces the generated sitemap, so add the page there or delete that file.
|
|
513
528
|
|
|
514
529
|
#### Noindex page in sitemap [#noindex-in-sitemap]
|
|
515
530
|
|
|
@@ -579,6 +594,14 @@ Fix: Every robots.txt line must be a `Field: value` directive or a comment.
|
|
|
579
594
|
|
|
580
595
|
Fix: A page can't be both disallowed in robots.txt and advertised in the sitemap.
|
|
581
596
|
|
|
597
|
+
#### robots.txt blocks one crawler from pages in the sitemap [#robots-blocks-crawler]
|
|
598
|
+
|
|
599
|
+
`BLUME_AUDIT_ROBOTS_BLOCKS_CRAWLER` · warning · from the built HTML
|
|
600
|
+
|
|
601
|
+
Fix: Narrow or remove the rule in that crawler's `User-agent` group if it should read these pages. Blocking an AI crawler on purpose is fine; skip this check.
|
|
602
|
+
|
|
603
|
+
A crawler named in its own `User-agent` group follows only that group, so a rule there (`User-agent: GPTBot` then `Disallow: /`) shuts it out while every other crawler reads the page. The audit reports each crawler once, at the rule that blocks its first page.
|
|
604
|
+
|
|
582
605
|
#### robots.txt does not reference the sitemap [#robots-sitemap-missing]
|
|
583
606
|
|
|
584
607
|
`BLUME_AUDIT_ROBOTS_SITEMAP_MISSING` · info · from the built HTML
|
package/docs/cli/doctor.mdx
CHANGED
|
@@ -9,16 +9,20 @@ description: blume doctor diagnoses configuration and content problems before yo
|
|
|
9
9
|
blume doctor
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
`blume init` also adds it to `package.json` as a `doctor` script. With pnpm, run that as `pnpm run doctor` (`pnpm --filter <workspace> run doctor` from a monorepo root): a bare `pnpm doctor` runs pnpm's own built-in `doctor` command instead of the script.
|
|
13
|
+
|
|
12
14
|
## What it checks
|
|
13
15
|
|
|
14
16
|
- **The Node version** against the range the installed `blume` package supports, read from its own `engines` field. A version outside it is a warning: things may work, but it isn't a combination Blume tests.
|
|
15
17
|
- **`blume.config.ts`**, with the same validation a build runs. A removed or renamed key fails with a hint naming its replacement rather than a bare "unrecognized key".
|
|
16
18
|
- **Every content page and folder meta**: the diagnostics `blume dev` and `blume build` print as they load the project — invalid frontmatter, navigation problems, missing include targets, and the rest — collected in one report.
|
|
19
|
+
- **Navigation that leads nowhere**: a tab, selector item, featured link, header action, or call to action whose path matches no page, custom `.astro` page, generated route, or reference: a warning (`BLUME_NAV_MISSING_PAGE`), the same one `blume dev` and `blume build` print.
|
|
20
|
+
- **[`<Component>`](/docs/content/components#component) examples that don't exist**: a `path` that names no file under `examples`, which the page would show as a "No example found" box: a warning (`BLUME_EXAMPLE_NOT_FOUND`) at its line, as `blume dev` and `blume build` print it. A `components.ts` override or island named `Component` replaces the built-in, and isn't checked.
|
|
17
21
|
- **Features that need a server** on a site configured for static output — the assistant, the MCP server, the Try it playground's built-in proxy, or server-mode search (Mixedbread): an error naming the feature, with the deployment adapter to switch to (or, when a host adapter is set to `output: "static"`, telling you to drop that option).
|
|
18
|
-
- **Packages your config needs** that aren't installed — the SDK a search, content source, or
|
|
22
|
+
- **Packages your config needs** that aren't installed — the SDK a search, content source, assistant, or narration adapter imports, a deployment adapter's `@astrojs/*` package, or the renderer for Vue or Svelte islands: an error naming each package, with the install command for your package manager. `blume build` stops on the same check.
|
|
19
23
|
- **`components.ts` overrides** Blume can't plan — an inline or computed entry, or an import whose file doesn't exist: an error for each, at its line.
|
|
20
24
|
- **A version-shaped folder** (`v1.0/`) on a site with no `versions` configured, which would otherwise build as ordinary content: a warning pointing at [`blume version`](/docs/cli/version).
|
|
21
|
-
- **Secrets an enabled feature reads** that aren't set, such as `MIXEDBREAD_API_KEY` or `OPENROUTER_API_KEY`: a warning naming the variable. Doctor loads `.env` and `.env.local` first, like `blume dev` and `blume build
|
|
25
|
+
- **Secrets an enabled feature reads** that aren't set, such as `MIXEDBREAD_API_KEY` or `OPENROUTER_API_KEY`: a warning naming the variable. Doctor loads `.env` and `.env.local` first, like `blume dev` and `blume build`, and checks before any remote content source fetches, so the warning still prints when a source then fails without its token.
|
|
22
26
|
|
|
23
27
|
## The summary
|
|
24
28
|
|
package/docs/cli/evals.mdx
CHANGED
|
@@ -25,7 +25,7 @@ blume eval 4 question(s) · Codex
|
|
|
25
25
|
|
|
26
26
|
## How it works
|
|
27
27
|
|
|
28
|
-
Each question runs through two agent sessions, using an agent CLI you already have installed — [Codex](https://developers.openai.com/codex/cli) by default, or [Claude Code](https://claude.com/claude-code) with `--agent claude`. Blume holds no API keys and calls no model itself. With Codex, both sessions also run without Codex's shell, command, and image tools, and inherit none of your environment variables.
|
|
28
|
+
Each question runs through two agent sessions, using an agent CLI you already have installed — [Codex](https://developers.openai.com/codex/cli) by default, or [Claude Code](https://claude.com/claude-code) with `--agent claude`. Blume holds no API keys and calls no model itself. With Codex, both sessions also run without Codex's shell, command, and image tools, and inherit none of your environment variables. With Claude Code, both sessions run with every built-in tool turned off and skip your Claude Code settings files and `CLAUDE.md`, so your hooks, plugins, and memory can't tell the reader what the docs don't. Your Claude Code login still works; set anything else it needs, such as `ANTHROPIC_API_KEY`, in your shell rather than in `settings.json`.
|
|
29
29
|
|
|
30
30
|
1. **The reader** answers the question using _only_ your documentation. It runs in an empty directory with its file, shell, and web tools disabled, connected to a private [MCP server](/docs/discoverability/mcp) that serves your docs — the same `search_docs`/`get_page` tools a real agent uses against your deployed site. It cannot read your repo, so it experiences the docs exactly like a fresh user: what isn't written doesn't exist.
|
|
31
31
|
2. **The judge** grades the answer against the facts you listed, with no tools at all. Paraphrase passes; a missing or contradicted fact fails — and so does "the documentation doesn't say."
|
|
@@ -82,9 +82,9 @@ blume eval --threshold 0.8 # at least 80% must pass
|
|
|
82
82
|
blume eval --json # machine-readable report on stdout
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
The JSON report carries the same `diagnostics` + `summary` shape as `blume validate --json` and `blume audit --json`, with the per-question results (answer, score, missing facts, cost) alongside.
|
|
85
|
+
The JSON report carries the same `diagnostics` + `summary` shape as `blume validate --json` and `blume audit --json`, with the per-question results (answer, score, missing facts, and with Claude Code, cost) alongside.
|
|
86
86
|
|
|
87
|
-
Because each question is two model sessions, an eval run costs real money and minutes
|
|
87
|
+
Because each question is two model sessions, an eval run costs real money and minutes. With Claude Code, the per-question spend is printed as it runs and totaled in the summary; Codex doesn't report its spend, so a Codex run shows none. A sensible CI setup runs `blume eval` on docs changes rather than every push.
|
|
88
88
|
|
|
89
89
|
## Fixing the findings
|
|
90
90
|
|
|
@@ -94,7 +94,7 @@ Each failure names the missing facts and the page that should state them. To han
|
|
|
94
94
|
blume eval --fix
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
This writes the full JSON report to a file and opens the agent interactively with a prompt that walks it through each failed question: read the named page, add the missing facts in the page's voice, and rerun `blume eval` until everything passes. The session is interactive by design — you review the edits through the agent's own permission flow — and the agent is told never to delete questions or weaken expected facts to get to green.
|
|
97
|
+
This writes the full JSON report to a file and opens the agent interactively with a prompt that walks it through each failed question: read the named page, add the missing facts in the page's voice, and rerun `blume eval` with the run's own `--agent`, `--file`, `--threshold`, and `--timeout` until everything passes. The session is interactive by design — you review the edits through the agent's own permission flow — and the agent is told never to delete questions or weaken expected facts to get to green.
|
|
98
98
|
|
|
99
99
|
## Flags
|
|
100
100
|
|
package/docs/cli/translate.mdx
CHANGED
|
@@ -43,6 +43,7 @@ Translations you wrote by hand are **adopted, never overwritten**: a translation
|
|
|
43
43
|
The agent is never trusted with structure. Before writing, Blume checks each reply and rebuilds the file from the source:
|
|
44
44
|
|
|
45
45
|
- The frontmatter is reconstructed from the source file's data, with only the six translatable values overlaid — keys the agent invented are dropped, keys it deleted are restored, and `slug`, `icon`, `order`, and dates are source-verbatim by construction.
|
|
46
|
+
- `seo.canonical` is the one source key left out. It names a page in the source language, and a translation that canonicalizes to another language drops out of search in its own, so the translation gets the default canonical, its own URL.
|
|
46
47
|
- The number of code fences must match the source, the body must be non-empty, and the frontmatter must parse.
|
|
47
48
|
- Every heading is pinned to its source heading's anchor id with a trailing [`[#id]` marker](/docs/content/syntax#custom-anchors), unless the translation already pins one, so `#fragment` links resolve identically in every language. Headings pair up positionally, so a translation whose heading structure doesn't match the source gets no pins.
|
|
48
49
|
|
package/docs/cli/validate.mdx
CHANGED
|
@@ -9,10 +9,10 @@ description: blume validate checks every link in your content — pages, anchors
|
|
|
9
9
|
blume validate
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
- **Internal page links** (`/guides/intro`, `./sibling`) must resolve to a real page — broken ones are reported as errors.
|
|
12
|
+
- **Internal page links** (`/guides/intro`, `./sibling`) must resolve to a real page — broken ones are reported as errors. Every link form Markdown and MDX render is read: inline links, including one whose label wraps onto the next line; reference-style links, checked at their `[label]: /target` definition; autolinks (`<https://…>`, in `.md`); and a component's string `href` (`<Card href="./install">`). A lowercase HTML `<a href>` ships exactly as written, so it's checked the way a browser reads it: a relative path resolves against the page's URL, and no [`basePath`](/docs/deployment#mount-the-docs-under-a-path) is added. An `href={…}` expression isn't checked.
|
|
13
13
|
- **Anchor links** (`#section`, `/guides/intro#setup`) must match an anchor on the target page — a heading's id (generated or [pinned](/docs/content/syntax#custom-anchors)) or a raw HTML element's `id` attribute — with misses reported as warnings. Ids inside code blocks, inline code, HTML comments, and `<Prompt>` blocks don't count.
|
|
14
14
|
- **Asset links** are checked where the file lives: an absolute path (`/logo.png`) against the `public/` directory, a relative image embed (``) against the page's own folder. A plain link to a relative path still resolves as a site route — only image embeds go through the image pipeline.
|
|
15
|
-
- **External links** are only checked with [`--external`](#flags) (off by default since it requires the network)
|
|
15
|
+
- **External links** are only checked with [`--external`](#flags) (off by default since it requires the network). A dead link is an error: a 404 or 410, or a host name that doesn't resolve. Anything else that fails is a warning, since it's more often the other site or the network than the link: any other error status (a 401 or 403 from a site that turns bots away, a 429 rate limit, a 5xx outage), a refused or dropped connection, or no answer within 10 seconds. To leave out URLs that can't be checked from where the command runs, like a placeholder domain, a local server, or a site that turns bots away, pass [`--ignore`](#flags). A bare URL that GitHub-flavored Markdown links on its own, with no link syntax around it, isn't read; [`blume audit --external`](/docs/cli/audit) checks it in the built site.
|
|
16
16
|
|
|
17
17
|
## What counts as a page
|
|
18
18
|
|
|
@@ -21,6 +21,7 @@ Links resolve against everything the built site serves, not just Markdown pages:
|
|
|
21
21
|
## Flags
|
|
22
22
|
|
|
23
23
|
- `--external` — also check external `http(s)` links over the network.
|
|
24
|
+
- `--ignore <glob>` — with `--external`, don't request an external link whose URL matches the glob, and report nothing for it. The glob is matched against the link's full URL, scheme included: `*` matches within one path segment and `**` across segments, so `--ignore "https://api.acme.example/**"` skips every link to that host and `--ignore "http://localhost:*/**"` every local server. Repeat the flag for more patterns, and quote each one so your shell doesn't expand it. Internal links are always checked: they resolve against your own pages, so fix a broken one or add a [redirect](/docs/deployment#redirects).
|
|
24
25
|
- `--strict` — exit non-zero on warnings too. Info-level notes stay advisory.
|
|
25
26
|
- `--json` — emit the diagnostics as JSON on stdout instead of the terminal report.
|
|
26
27
|
|
|
@@ -32,7 +33,7 @@ Links resolve against everything the built site serves, not just Markdown pages:
|
|
|
32
33
|
| `BLUME_BROKEN_ANCHOR` | warning | The page exists but has no anchor matching the fragment. |
|
|
33
34
|
| `BLUME_BROKEN_ASSET` | warning | An absolute path isn't in `public/`, or a relative image embed isn't beside the page. |
|
|
34
35
|
| `BLUME_ASSETS_UNCHECKED` | info | There is no `public/` directory, so absolute asset paths weren't checked. |
|
|
35
|
-
| `BLUME_DEAD_LINK` | error or warning | An external link (with `--external`) returned 404/410 or
|
|
36
|
+
| `BLUME_DEAD_LINK` | error or warning | An external link (with `--external`) returned 404/410 or its host doesn't resolve (error), or it got any other error status, no connection, or no answer in time (warning). |
|
|
36
37
|
|
|
37
38
|
The exit code is the contract: errors exit non-zero, and `--strict` makes warnings do the same.
|
|
38
39
|
|