blume 2.0.1 → 2.0.3
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 +147 -0
- package/dist/cli/{chunk-qwsrynx5.js → chunk-1d7ve1dm.js} +38 -19
- package/dist/cli/{chunk-qwsrynx5.js.map → chunk-1d7ve1dm.js.map} +4 -4
- package/dist/cli/{chunk-s6jhgk0q.js → chunk-2eytanqx.js} +2 -2
- package/dist/cli/{chunk-kdp5q7ke.js → chunk-2hsdwb9n.js} +18 -19
- package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-2hsdwb9n.js.map} +2 -2
- package/dist/cli/{chunk-hdpx1tax.js → chunk-2z928egk.js} +5 -5
- package/dist/cli/{chunk-jwyddg7y.js → chunk-35d4wj9f.js} +30 -24
- package/dist/cli/chunk-35d4wj9f.js.map +15 -0
- package/dist/cli/{chunk-ah61y8py.js → chunk-364znk6q.js} +2 -2
- package/dist/cli/{chunk-jts8mvcz.js → chunk-3em5wd2y.js} +25 -6
- package/dist/cli/{chunk-jts8mvcz.js.map → chunk-3em5wd2y.js.map} +3 -3
- package/dist/cli/{chunk-s1p84fyh.js → chunk-5f86nr5m.js} +63 -22
- package/dist/cli/chunk-5f86nr5m.js.map +11 -0
- package/dist/cli/{chunk-2hn4b8z7.js → chunk-5m5nmvyq.js} +170 -76
- package/dist/cli/chunk-5m5nmvyq.js.map +13 -0
- package/dist/cli/{chunk-epjnccmv.js → chunk-5xvm6tfj.js} +18 -15
- package/dist/cli/chunk-5xvm6tfj.js.map +10 -0
- package/dist/cli/{chunk-fz5wtpmh.js → chunk-6dsbexzp.js} +18 -15
- package/dist/cli/chunk-6dsbexzp.js.map +10 -0
- package/dist/cli/{chunk-vtk4a6dg.js → chunk-8ktnccpt.js} +1 -1
- package/dist/cli/{chunk-6hsn950k.js → chunk-9t7a85s3.js} +178 -48
- package/dist/cli/chunk-9t7a85s3.js.map +10 -0
- package/dist/cli/{chunk-fxypxtvm.js → chunk-a58773jm.js} +2 -2
- package/dist/cli/{chunk-mb2919y2.js → chunk-acanzt5p.js} +17 -6
- package/dist/cli/chunk-acanzt5p.js.map +10 -0
- package/dist/cli/{chunk-27g6wdth.js → chunk-akbpwfxc.js} +90 -26
- package/dist/cli/chunk-akbpwfxc.js.map +10 -0
- package/dist/cli/{chunk-wm7js3j9.js → chunk-b07cmahc.js} +2 -2
- package/dist/cli/{chunk-wgm7m9qk.js → chunk-c8chx29p.js} +179 -51
- package/dist/cli/chunk-c8chx29p.js.map +36 -0
- package/dist/cli/{chunk-qs4q5p4e.js → chunk-crgn1q09.js} +32 -14
- package/dist/cli/chunk-crgn1q09.js.map +10 -0
- package/dist/cli/chunk-e04dxsz1.js +39 -0
- package/dist/cli/chunk-e04dxsz1.js.map +10 -0
- package/dist/cli/{chunk-yt5n7ppj.js → chunk-ey84smr6.js} +17 -7
- package/dist/cli/chunk-ey84smr6.js.map +10 -0
- package/dist/cli/{chunk-f2z5v128.js → chunk-g4hq16wv.js} +14 -15
- package/dist/cli/{chunk-f2z5v128.js.map → chunk-g4hq16wv.js.map} +2 -2
- package/dist/cli/{chunk-fa25z98p.js → chunk-ga0pf4aj.js} +9 -8
- package/dist/cli/chunk-ga0pf4aj.js.map +11 -0
- package/dist/cli/{chunk-kpf8rrjc.js → chunk-hm3vjy5s.js} +109 -58
- package/dist/cli/chunk-hm3vjy5s.js.map +19 -0
- package/dist/cli/{chunk-fs23ddbb.js → chunk-j85vccga.js} +625 -750
- package/dist/cli/chunk-j85vccga.js.map +36 -0
- package/dist/cli/{chunk-ch6g3ar0.js → chunk-p3v96n38.js} +6 -6
- package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-p3v96n38.js.map} +3 -3
- package/dist/cli/{chunk-q5163e60.js → chunk-p73c0m7w.js} +21 -19
- package/dist/cli/chunk-p73c0m7w.js.map +11 -0
- package/dist/cli/{chunk-dh8cwk36.js → chunk-pehfxfta.js} +24 -9
- package/dist/cli/chunk-pehfxfta.js.map +10 -0
- package/dist/cli/{chunk-qkqwkpte.js → chunk-pv29h0wf.js} +3688 -1313
- package/dist/cli/chunk-pv29h0wf.js.map +190 -0
- package/dist/cli/{chunk-6vm74dry.js → chunk-q58y5e6a.js} +10 -10
- package/dist/cli/{chunk-6vm74dry.js.map → chunk-q58y5e6a.js.map} +3 -3
- package/dist/cli/{chunk-zxcczpyx.js → chunk-r20tn01b.js} +1 -1
- package/dist/cli/{chunk-m3vmjgmq.js → chunk-r9rcc4w7.js} +16 -8
- package/dist/cli/chunk-r9rcc4w7.js.map +10 -0
- package/dist/cli/{chunk-5shv93fd.js → chunk-tkacnehg.js} +2 -2
- package/dist/cli/{chunk-zxh4d9vy.js → chunk-tzmab476.js} +4 -4
- package/dist/cli/{chunk-yw7dm696.js → chunk-vg9r4eb9.js} +24 -11
- package/dist/cli/chunk-vg9r4eb9.js.map +14 -0
- package/dist/cli/{chunk-79jhk4py.js → chunk-wrr3j9w9.js} +260 -132
- package/dist/cli/chunk-wrr3j9w9.js.map +35 -0
- package/dist/cli/{chunk-6crbhc3x.js → chunk-yfyb25rh.js} +54 -27
- package/dist/cli/chunk-yfyb25rh.js.map +14 -0
- package/dist/cli/index.js +162 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +7 -0
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/link-headers.d.ts +8 -1
- package/dist/types/ai/openapi-components.d.ts +5 -2
- package/dist/types/ai/relative-links.d.ts +11 -4
- package/dist/types/ai/skills.d.ts +4 -1
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/ai/tar.d.ts +1 -3
- package/dist/types/analytics/databuddy.d.ts +43 -0
- package/dist/types/analytics/index.d.ts +4 -0
- package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
- package/dist/types/analytics/schema.d.ts +28 -0
- package/dist/types/astro/integration.d.ts +3 -2
- package/dist/types/cli/env.d.ts +5 -0
- package/dist/types/cli/init/scaffold.d.ts +19 -3
- package/dist/types/cli/init/starter-spec.d.ts +11 -0
- package/dist/types/core/base-path.d.ts +24 -1
- package/dist/types/core/config-input.d.ts +13 -11
- package/dist/types/core/config.d.ts +2 -2
- package/dist/types/core/directive-diagnostics.d.ts +12 -0
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/heading-markers.d.ts +5 -7
- package/dist/types/core/i18n-ui.d.ts +31 -0
- package/dist/types/core/i18n.d.ts +9 -1
- package/dist/types/core/last-modified.d.ts +10 -0
- package/dist/types/core/links.d.ts +3 -1
- package/dist/types/core/load-module.d.ts +10 -0
- package/dist/types/core/locale-links.d.ts +12 -2
- package/dist/types/core/meta.d.ts +13 -1
- package/dist/types/core/nav-diagnostics.d.ts +10 -0
- package/dist/types/core/navigation.d.ts +38 -0
- package/dist/types/core/ordering-prefix.d.ts +4 -0
- package/dist/types/core/safe-links.d.ts +3 -1
- package/dist/types/core/schema.d.ts +59 -13
- package/dist/types/core/sources/github-releases.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +38 -13
- package/dist/types/core/sources/normalize.d.ts +23 -2
- package/dist/types/core/sources/remote.d.ts +11 -1
- package/dist/types/core/sources/resolve.d.ts +12 -0
- package/dist/types/core/sources/types.d.ts +31 -0
- package/dist/types/core/sources/watch.d.ts +12 -5
- package/dist/types/core/standard-schema.d.ts +5 -0
- package/dist/types/core/types.d.ts +9 -0
- package/dist/types/deploy/adapters/node.d.ts +5 -2
- package/dist/types/deploy/adapters/types.d.ts +7 -0
- package/dist/types/deploy/artifacts.d.ts +6 -4
- package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
- package/dist/types/deploy/headers.d.ts +36 -7
- package/dist/types/deploy/node-headers.d.ts +43 -8
- package/dist/types/deploy/platforms/netlify.d.ts +27 -2
- package/dist/types/deploy/platforms/node.d.ts +6 -5
- package/dist/types/deploy/platforms/types.d.ts +15 -0
- package/dist/types/deploy/platforms/vercel.d.ts +3 -2
- package/dist/types/deploy/redirects.d.ts +31 -15
- package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
- package/dist/types/markdown/directives.d.ts +62 -0
- package/dist/types/markdown/features.d.ts +21 -0
- package/dist/types/markdown/mdast.d.ts +63 -0
- package/dist/types/openapi/asyncapi.d.ts +4 -2
- package/dist/types/openapi/model.d.ts +20 -6
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +20 -9
- package/docs/08-faq.mdx +10 -3
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +7 -5
- package/docs/cli/audit.mdx +19 -3
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +4 -1
- package/docs/cli/translate.mdx +4 -4
- package/docs/cli/version.mdx +1 -1
- package/docs/configuration/analytics.mdx +42 -2
- package/docs/configuration/assistant.mdx +1 -1
- package/docs/configuration/customization.mdx +6 -3
- package/docs/configuration/index.mdx +5 -3
- package/docs/configuration/search.mdx +2 -2
- package/docs/content/components.mdx +2 -2
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +3 -1
- package/docs/content/index.mdx +8 -4
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +7 -3
- package/docs/content/navigation.mdx +29 -4
- package/docs/content/sources.mdx +18 -16
- package/docs/content/syntax.mdx +14 -0
- package/docs/content/versioning.mdx +2 -1
- package/docs/discoverability/agent-discovery.mdx +22 -8
- package/docs/discoverability/index.mdx +4 -3
- package/docs/discoverability/llms-txt.mdx +2 -5
- package/docs/discoverability/markdown.mdx +6 -4
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +3 -2
- package/docs/discoverability/open-graph.mdx +8 -4
- package/docs/discoverability/rss.mdx +4 -2
- package/docs/references/asyncapi.mdx +2 -2
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/openapi.mdx +6 -4
- package/package.json +1 -1
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +6 -6
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +3 -3
- package/skills/blume-migrate/references/monorepo.md +1 -1
- package/skills/blume-migrate/references/nextra.md +2 -2
- package/skills/blume-migrate/references/starlight.md +5 -5
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +9 -4
- package/skills/blume-update-docs/references/audit-checklist.md +1 -1
- package/src/ai/agent-readability.ts +2 -2
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/ai-catalog.ts +6 -2
- package/src/ai/api/handlers.ts +2 -2
- package/src/ai/api/spec.ts +17 -4
- package/src/ai/api-catalog.ts +13 -3
- package/src/ai/ask-context.ts +14 -2
- package/src/ai/ask-data.ts +26 -12
- package/src/ai/changelog-markdown.ts +2 -2
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/link-headers.ts +22 -8
- package/src/ai/llms.ts +22 -10
- package/src/ai/markdown.ts +23 -11
- package/src/ai/mcp/discovery.ts +2 -2
- package/src/ai/mcp/query.ts +2 -2
- package/src/ai/mcp/server.ts +80 -9
- package/src/ai/openapi-components.ts +22 -6
- package/src/ai/relative-links.ts +99 -15
- package/src/ai/serializers.ts +2 -1
- package/src/ai/skills.ts +14 -1
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/tar.ts +139 -12
- package/src/ai/visibility.ts +45 -14
- package/src/analytics/databuddy.ts +67 -0
- package/src/analytics/head.ts +8 -0
- package/src/analytics/index.ts +7 -0
- package/src/analytics/one-dollar-stats.ts +86 -0
- package/src/analytics/posthog.ts +21 -3
- package/src/analytics/schema.ts +4 -0
- package/src/astro/generate.ts +72 -28
- package/src/astro/include-hmr.ts +31 -12
- package/src/astro/include-refresh.ts +19 -8
- package/src/astro/integration.ts +108 -14
- package/src/astro/runtime-modules.ts +28 -13
- package/src/astro/templates.ts +139 -57
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +25 -5
- package/src/audit/checks/content.ts +20 -2
- package/src/audit/checks/i18n.ts +46 -8
- package/src/audit/checks/indexability.ts +39 -19
- package/src/audit/checks/links.ts +22 -1
- package/src/audit/checks/llms.ts +6 -3
- package/src/audit/checks/network.ts +3 -1
- package/src/audit/checks/og-image.ts +10 -0
- package/src/audit/checks/robots.ts +6 -1
- package/src/audit/checks/sitemap.ts +56 -31
- package/src/audit/checks/social.ts +21 -2
- package/src/audit/crawl.ts +88 -15
- package/src/audit/graph.ts +3 -1
- package/src/audit/report.ts +54 -17
- package/src/audit/run.ts +13 -9
- package/src/audit/snapshot.ts +5 -0
- package/src/audit/types.ts +18 -0
- package/src/audit/url.ts +37 -6
- package/src/cli/args.ts +32 -0
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +11 -1
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/doctor.ts +3 -1
- package/src/cli/commands/eval.ts +20 -18
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +18 -18
- package/src/cli/commands/upgrade.ts +11 -0
- package/src/cli/commands/validate.ts +3 -1
- package/src/cli/dev-lock.ts +157 -37
- package/src/cli/eject-scripts.ts +32 -7
- package/src/cli/env.ts +12 -1
- package/src/cli/init/scaffold.ts +117 -11
- package/src/cli/init/starter-spec.ts +235 -0
- package/src/cli/report-format.ts +11 -6
- package/src/components/colors.ts +19 -0
- package/src/components/content/AccordionItem.astro +26 -22
- package/src/components/content/Badge.astro +7 -12
- package/src/components/content/Card.astro +2 -2
- package/src/components/content/Component.astro +11 -5
- package/src/components/content/Expandable.astro +5 -1
- package/src/components/content/Frame.astro +2 -7
- package/src/components/content/GithubInfo.astro +12 -2
- package/src/components/content/Prompt.astro +2 -7
- package/src/components/content/Tab.astro +0 -1
- package/src/components/content/Tabs.astro +58 -5
- package/src/components/content/Tile.astro +1 -1
- package/src/components/content/Tooltip.astro +69 -7
- package/src/components/content/Tree.astro +7 -2
- package/src/components/content/TypeTable.astro +10 -5
- package/src/components/content/Update.astro +8 -2
- package/src/components/content/auto-type-table.ts +4 -1
- package/src/components/content/badge-color.ts +20 -0
- package/src/components/content/base-href.ts +14 -22
- package/src/components/content/inline-markdown.ts +27 -7
- package/src/components/copy-feedback.ts +35 -8
- package/src/components/islands/assistant.tsx +37 -6
- package/src/components/islands/base-path.ts +47 -10
- package/src/components/islands/hooks.ts +42 -21
- package/src/components/islands/webmcp.ts +16 -10
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Breadcrumbs.astro +5 -2
- package/src/components/layout/DiscoveryLinks.astro +9 -5
- package/src/components/layout/Header.astro +23 -10
- package/src/components/layout/LanguageSwitcher.astro +2 -2
- package/src/components/layout/Logo.astro +5 -0
- package/src/components/layout/NavSelector.astro +8 -3
- package/src/components/layout/NavTabMenu.astro +133 -0
- package/src/components/layout/NavTree.astro +31 -12
- package/src/components/layout/NavTreeCache.astro +5 -2
- package/src/components/layout/NavTreeScript.astro +45 -5
- package/src/components/layout/PageActions.astro +4 -3
- package/src/components/layout/PageLayout.astro +28 -13
- package/src/components/layout/Pagination.astro +3 -3
- package/src/components/layout/ReferenceLayout.astro +4 -1
- package/src/components/layout/RootLayout.astro +25 -12
- package/src/components/layout/Search.astro +38 -14
- package/src/components/layout/VersionBanner.astro +2 -2
- package/src/components/layout/analytics-client.ts +14 -0
- package/src/components/layout/toc-active.ts +41 -0
- package/src/components/layout/toc-element.ts +8 -14
- package/src/components/openapi/ApiTagOperations.astro +2 -2
- package/src/components/openapi/AsyncApiOperation.astro +7 -4
- package/src/components/openapi/GraphqlChip.astro +2 -2
- package/src/components/openapi/GraphqlType.astro +11 -3
- package/src/components/openapi/MessageComposer.astro +1 -1
- package/src/components/openapi/Operation.astro +23 -5
- package/src/components/openapi/PanelTabs.astro +4 -1
- package/src/components/openapi/Playground.astro +8 -2
- package/src/components/openapi/RequestPanel.astro +13 -6
- package/src/components/openapi/SchemaProperty.astro +11 -33
- package/src/components/openapi/SchemaTable.astro +34 -52
- package/src/components/openapi/async.ts +38 -6
- package/src/components/openapi/helpers.ts +100 -12
- package/src/components/openapi/message-composer.ts +14 -1
- package/src/components/openapi/message-model.ts +12 -2
- package/src/components/openapi/message.ts +21 -3
- package/src/components/openapi/operation-model.ts +119 -17
- package/src/components/openapi/panel.ts +31 -5
- package/src/components/openapi/param-style.ts +181 -0
- package/src/components/openapi/playground-client.ts +110 -23
- package/src/components/openapi/playground-schema.ts +25 -6
- package/src/components/openapi/request.ts +192 -26
- package/src/components/openapi/schema-tree.ts +209 -0
- package/src/components/openapi/snippets.ts +113 -19
- package/src/components/openapi/validate-json.ts +1 -1
- package/src/components/openapi/ws-client.ts +18 -2
- package/src/core/base-path.ts +69 -8
- package/src/core/config-input.ts +13 -11
- package/src/core/config.ts +18 -4
- package/src/core/diagnostics.ts +219 -30
- package/src/core/directive-diagnostics.ts +99 -0
- package/src/core/frontmatter.ts +21 -18
- package/src/core/graph.ts +120 -11
- package/src/core/heading-markers.ts +5 -18
- package/src/core/i18n-ui.ts +39 -2
- package/src/core/i18n.ts +44 -5
- package/src/core/last-modified.ts +25 -3
- package/src/core/links.ts +7 -4
- package/src/core/load-module.ts +20 -0
- package/src/core/locale-links.ts +22 -18
- package/src/core/manifest.ts +3 -2
- package/src/core/meta.ts +89 -12
- package/src/core/nav-diagnostics.ts +56 -1
- package/src/core/navigation.ts +272 -83
- package/src/core/ordering-prefix.ts +27 -0
- package/src/core/project-graph.ts +50 -6
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +94 -18
- package/src/core/sources/assets.ts +83 -41
- package/src/core/sources/contentful-rich-text.ts +28 -20
- package/src/core/sources/contentful.ts +25 -12
- package/src/core/sources/filesystem.ts +25 -3
- package/src/core/sources/github-releases.ts +131 -11
- package/src/core/sources/lexical.ts +30 -20
- package/src/core/sources/lower.ts +276 -56
- package/src/core/sources/mdx-remote.ts +52 -16
- package/src/core/sources/normalize.ts +456 -119
- package/src/core/sources/notion.ts +77 -34
- package/src/core/sources/obsidian.ts +40 -9
- package/src/core/sources/payload.ts +1 -0
- package/src/core/sources/portable-text.ts +85 -49
- package/src/core/sources/remote.ts +18 -2
- package/src/core/sources/resolve.ts +52 -33
- package/src/core/sources/sanity.ts +1 -0
- package/src/core/sources/strapi-blocks.ts +28 -19
- package/src/core/sources/strapi.ts +1 -0
- package/src/core/sources/types.ts +31 -0
- package/src/core/sources/watch.ts +20 -7
- package/src/core/standard-schema.ts +10 -6
- package/src/core/types.ts +9 -0
- package/src/core/ui-packs/ar.ts +13 -0
- package/src/core/ui-packs/bg.ts +13 -0
- package/src/core/ui-packs/bn.ts +13 -0
- package/src/core/ui-packs/ca.ts +13 -0
- package/src/core/ui-packs/cs.ts +13 -0
- package/src/core/ui-packs/da.ts +13 -0
- package/src/core/ui-packs/de.ts +13 -0
- package/src/core/ui-packs/el.ts +13 -0
- package/src/core/ui-packs/es.ts +13 -0
- package/src/core/ui-packs/fa.ts +13 -0
- package/src/core/ui-packs/fi.ts +13 -0
- package/src/core/ui-packs/fr.ts +13 -0
- package/src/core/ui-packs/he.ts +13 -0
- package/src/core/ui-packs/hi.ts +13 -0
- package/src/core/ui-packs/hr.ts +13 -0
- package/src/core/ui-packs/hu.ts +13 -0
- package/src/core/ui-packs/id.ts +13 -0
- package/src/core/ui-packs/it.ts +13 -0
- package/src/core/ui-packs/ja.ts +13 -0
- package/src/core/ui-packs/ko.ts +13 -0
- package/src/core/ui-packs/nl.ts +13 -0
- package/src/core/ui-packs/no.ts +13 -0
- package/src/core/ui-packs/pl.ts +13 -0
- package/src/core/ui-packs/pt-br.ts +13 -0
- package/src/core/ui-packs/pt.ts +13 -0
- package/src/core/ui-packs/ro.ts +13 -0
- package/src/core/ui-packs/ru.ts +13 -0
- package/src/core/ui-packs/sk.ts +13 -0
- package/src/core/ui-packs/sr.ts +13 -0
- package/src/core/ui-packs/sv.ts +13 -0
- package/src/core/ui-packs/th.ts +13 -0
- package/src/core/ui-packs/tr.ts +13 -0
- package/src/core/ui-packs/uk.ts +13 -0
- package/src/core/ui-packs/vi.ts +13 -0
- package/src/core/ui-packs/zh-tw.ts +13 -0
- package/src/core/ui-packs/zh.ts +13 -0
- package/src/core/version-cut.ts +69 -17
- package/src/core/versions.ts +4 -1
- package/src/deploy/adapters/node.ts +5 -2
- package/src/deploy/adapters/registry.ts +2 -1
- package/src/deploy/adapters/types.ts +13 -1
- package/src/deploy/artifacts.ts +52 -11
- package/src/deploy/cloudflare-negotiation.ts +27 -16
- package/src/deploy/headers.ts +75 -55
- package/src/deploy/node-headers.ts +148 -27
- package/src/deploy/platforms/cloudflare.ts +13 -3
- package/src/deploy/platforms/netlify.ts +83 -5
- package/src/deploy/platforms/node.ts +8 -5
- package/src/deploy/platforms/static.ts +2 -0
- package/src/deploy/platforms/types.ts +15 -0
- package/src/deploy/platforms/vercel.ts +10 -3
- package/src/deploy/redirects.ts +68 -21
- package/src/deploy/robots.ts +2 -2
- package/src/deploy/rss.ts +4 -3
- package/src/deploy/sitemap.ts +7 -5
- package/src/deploy/vercel-negotiation.ts +35 -3
- package/src/eval/agents.ts +10 -2
- package/src/eval/run.ts +25 -0
- package/src/markdown/base-links.ts +74 -29
- package/src/markdown/directives.ts +242 -36
- package/src/markdown/features.ts +17 -0
- package/src/markdown/index.ts +13 -9
- package/src/markdown/mdast.ts +5 -2
- package/src/markdown/relative-links.ts +15 -27
- package/src/markdown/route-snapshot.ts +37 -0
- package/src/og/card.ts +149 -9
- package/src/og/derive.ts +156 -5
- package/src/og/index.ts +1 -0
- package/src/openapi/asyncapi.ts +4 -2
- package/src/openapi/graphql-build.ts +28 -2
- package/src/openapi/model.ts +99 -27
- package/src/openapi/proxy.ts +63 -10
- package/src/openapi/render-mdx.ts +51 -3
- package/src/registry/eject.ts +297 -43
- package/src/search/adapters/version-scope.ts +30 -0
- package/src/search/documents.ts +89 -27
- package/src/search/popular.ts +2 -1
- package/src/search/sync/algolia.ts +36 -2
- package/src/seo/jsonld.ts +7 -3
- package/src/sources/registry.ts +5 -0
- package/src/theme/entry.ts +11 -4
- package/src/translate/agents.ts +6 -1
- package/src/translate/ledger.ts +26 -3
- package/src/translate/meta.ts +76 -24
- package/src/translate/run.ts +14 -8
- package/src/translate/validate.ts +14 -2
- package/src/translate/work-list.ts +91 -19
- package/src/upgrade/upgrade.ts +36 -4
- package/dist/cli/chunk-27g6wdth.js.map +0 -10
- package/dist/cli/chunk-2hn4b8z7.js.map +0 -12
- package/dist/cli/chunk-6crbhc3x.js.map +0 -14
- package/dist/cli/chunk-6hsn950k.js.map +0 -10
- package/dist/cli/chunk-79jhk4py.js.map +0 -35
- package/dist/cli/chunk-82bbrxdn.js +0 -51
- package/dist/cli/chunk-82bbrxdn.js.map +0 -10
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-ce574jw2.js +0 -23
- package/dist/cli/chunk-ce574jw2.js.map +0 -10
- package/dist/cli/chunk-dh8cwk36.js.map +0 -10
- package/dist/cli/chunk-epjnccmv.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-fs23ddbb.js.map +0 -35
- package/dist/cli/chunk-fz5wtpmh.js.map +0 -10
- package/dist/cli/chunk-jwyddg7y.js.map +0 -15
- package/dist/cli/chunk-kpf8rrjc.js.map +0 -19
- package/dist/cli/chunk-m3vmjgmq.js.map +0 -10
- package/dist/cli/chunk-mb2919y2.js.map +0 -10
- package/dist/cli/chunk-q5163e60.js.map +0 -11
- package/dist/cli/chunk-qkqwkpte.js.map +0 -182
- package/dist/cli/chunk-qs4q5p4e.js.map +0 -10
- package/dist/cli/chunk-s1p84fyh.js.map +0 -10
- package/dist/cli/chunk-wgm7m9qk.js.map +0 -36
- package/dist/cli/chunk-yt5n7ppj.js.map +0 -10
- package/dist/cli/chunk-yw7dm696.js.map +0 -14
- /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-2eytanqx.js.map} +0 -0
- /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-2z928egk.js.map} +0 -0
- /package/dist/cli/{chunk-ah61y8py.js.map → chunk-364znk6q.js.map} +0 -0
- /package/dist/cli/{chunk-vtk4a6dg.js.map → chunk-8ktnccpt.js.map} +0 -0
- /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-a58773jm.js.map} +0 -0
- /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-b07cmahc.js.map} +0 -0
- /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-r20tn01b.js.map} +0 -0
- /package/dist/cli/{chunk-5shv93fd.js.map → chunk-tkacnehg.js.map} +0 -0
- /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-tzmab476.js.map} +0 -0
package/src/astro/templates.ts
CHANGED
|
@@ -14,14 +14,17 @@ import { BLUME_IGNORE_DIRS } from "../core/sources/watch.ts";
|
|
|
14
14
|
import { trimChar } from "../core/trim.ts";
|
|
15
15
|
import type { ProjectContext } from "../core/types.ts";
|
|
16
16
|
import { deployPassthrough } from "../deploy/adapters/types.ts";
|
|
17
|
-
import {
|
|
17
|
+
import { SVG_ASSET_HEADERS } from "../deploy/headers.ts";
|
|
18
18
|
import { deployPlatform } from "../deploy/platforms/index.ts";
|
|
19
19
|
import { adapterRoot, distDir } from "../deploy/platforms/paths.ts";
|
|
20
20
|
import { applyBaseToAstroRedirects } from "../deploy/redirects.ts";
|
|
21
21
|
import type { OgCache } from "../og/cache.ts";
|
|
22
|
-
import type { OgFont, OgFontFamilies } from "../og/card.ts";
|
|
22
|
+
import type { OgFont, OgFontFamilies, OgGoogleFont } from "../og/card.ts";
|
|
23
23
|
import type { MixedbreadOptions } from "../search/adapters/mixedbread.ts";
|
|
24
|
-
import type {
|
|
24
|
+
import type {
|
|
25
|
+
ResolvedSearchAdapter,
|
|
26
|
+
SearchAdapterKind,
|
|
27
|
+
} from "../search/adapters/registry.ts";
|
|
25
28
|
import { buildFontEntries, fontLocaleCodes } from "../theme/fonts.ts";
|
|
26
29
|
import { importSpecifier, wrapperPropsType } from "./component-slots.ts";
|
|
27
30
|
import type { ExampleSpec } from "./examples.ts";
|
|
@@ -398,14 +401,32 @@ export interface ClientFeatures {
|
|
|
398
401
|
/** Every feature on: what a checkout that predates the detection shipped. */
|
|
399
402
|
const ALL_CLIENT_FEATURES: ClientFeatures = { epub: true, mermaid: true };
|
|
400
403
|
|
|
404
|
+
/**
|
|
405
|
+
* The npm module each browser-queried search adapter's client imports (see
|
|
406
|
+
* `components/layout/search/`). The `<Search>` dialog lazy-imports that client
|
|
407
|
+
* on first open, after the dev dep optimizer's startup run, so the first
|
|
408
|
+
* search of a fresh `blume dev` session discovered the library, re-ran the
|
|
409
|
+
* optimizer, and reloaded the page. Pagefind loads its script from the build
|
|
410
|
+
* output and Mixedbread queries through the server, so neither has one.
|
|
411
|
+
*/
|
|
412
|
+
const SEARCH_CLIENT_DEPS: Partial<Record<SearchAdapterKind, string>> = {
|
|
413
|
+
algolia: "algoliasearch/lite",
|
|
414
|
+
flexsearch: "flexsearch",
|
|
415
|
+
orama: "@orama/orama",
|
|
416
|
+
"orama-cloud": "@oramacloud/client",
|
|
417
|
+
typesense: "typesense",
|
|
418
|
+
};
|
|
419
|
+
|
|
401
420
|
const resolveOptimizeDeps = (options: {
|
|
402
421
|
aliases: Record<string, string> | undefined;
|
|
403
422
|
context: ProjectContext;
|
|
404
423
|
features: ClientFeatures;
|
|
405
424
|
needsReact: boolean;
|
|
406
425
|
reactCompilerPath: string | null | undefined;
|
|
426
|
+
searchKind: SearchAdapterKind;
|
|
407
427
|
}): OptimizeDepsConfig => {
|
|
408
428
|
const { context, features } = options;
|
|
429
|
+
const searchDep = SEARCH_CLIENT_DEPS[options.searchKind];
|
|
409
430
|
const optimizeDepsEntries = [
|
|
410
431
|
...(context.pagesRoot ? [`${context.pagesRoot}/**/*.astro`] : []),
|
|
411
432
|
`${context.root}/islands/**/*.{jsx,svelte,tsx,vue}`,
|
|
@@ -418,6 +439,8 @@ const resolveOptimizeDeps = (options: {
|
|
|
418
439
|
// Mermaid costs the dev server seconds at startup for nothing otherwise.
|
|
419
440
|
...(features.mermaid ? ["blume > mermaid"] : []),
|
|
420
441
|
...(features.epub ? ["blume > epub-gen-memory/bundle"] : []),
|
|
442
|
+
// Only the configured search adapter's client library.
|
|
443
|
+
...(searchDep ? [`blume > ${searchDep}`] : []),
|
|
421
444
|
// Astro's own client-router/prefetch virtual modules are deliberately NOT
|
|
422
445
|
// forced in here: they read Vite `define`-injected constants
|
|
423
446
|
// (__PREFETCH_PREFETCH_ALL__ and friends) that a pre-bundled copy loses,
|
|
@@ -538,7 +561,7 @@ const blumeIntegrationOptions = (options: {
|
|
|
538
561
|
buildArtifactsRoot: ".",
|
|
539
562
|
contentRoutes: options.contentRoutes,
|
|
540
563
|
homeLinkHeader:
|
|
541
|
-
buildHomeLinkHeader(options.config, options.contentRoutes) ??
|
|
564
|
+
buildHomeLinkHeader(options.config, options.contentRoutes, "dev") ??
|
|
542
565
|
undefined,
|
|
543
566
|
pages: options.pages,
|
|
544
567
|
}
|
|
@@ -623,6 +646,7 @@ export const astroConfigTemplate = (options: {
|
|
|
623
646
|
features,
|
|
624
647
|
needsReact,
|
|
625
648
|
reactCompilerPath: options.reactCompilerPath,
|
|
649
|
+
searchKind: config.search.provider.kind,
|
|
626
650
|
});
|
|
627
651
|
|
|
628
652
|
const {
|
|
@@ -660,7 +684,8 @@ export const astroConfigTemplate = (options: {
|
|
|
660
684
|
const basedRedirects = applyBaseToAstroRedirects(
|
|
661
685
|
config.redirects,
|
|
662
686
|
config.basePath,
|
|
663
|
-
deployment.options.base ?? ""
|
|
687
|
+
deployment.options.base ?? "",
|
|
688
|
+
new Set(contentRoutes)
|
|
664
689
|
);
|
|
665
690
|
const redirectsOption =
|
|
666
691
|
basedRedirects.length > 0
|
|
@@ -892,6 +917,10 @@ ${userConfigSetup}export default defineConfig({
|
|
|
892
917
|
// \`/bundle\` subpath that is actually imported: optimizing the package
|
|
893
918
|
// root leaves that entry out. Production (Rollup) already handles the
|
|
894
919
|
// interop, so all of this only affects dev.
|
|
920
|
+
//
|
|
921
|
+
// The search adapter's client library rides the list for the same reason
|
|
922
|
+
// as the compiler runtime: the search dialog lazy-imports it on first
|
|
923
|
+
// open, and discovering it then re-optimizes and reloads the page.
|
|
895
924
|
optimizeDeps: {
|
|
896
925
|
entries: ${JSON.stringify(optimizeDepsEntries)},
|
|
897
926
|
include: ${JSON.stringify(optimizeDepsInclude)},
|
|
@@ -1246,9 +1275,15 @@ export const askEndpointTemplate = (
|
|
|
1246
1275
|
"messages",
|
|
1247
1276
|
...backend.template.fields,
|
|
1248
1277
|
];
|
|
1278
|
+
// The request's signal aborts when the reader closes the panel mid-answer
|
|
1279
|
+
// (the client drops the connection): passing it on stops the model call,
|
|
1280
|
+
// which otherwise kept generating, and billing, to completion into a closed
|
|
1281
|
+
// connection. `streamText` ends an aborted call through its abort path, not
|
|
1282
|
+
// `onError`, so the reader leaving is never logged as a provider error.
|
|
1249
1283
|
const call = ` const result = streamText({
|
|
1250
1284
|
${streamFields.join(",\n ")},
|
|
1251
1285
|
${onError}
|
|
1286
|
+
abortSignal: request.signal,
|
|
1252
1287
|
});`;
|
|
1253
1288
|
const stream = grounded
|
|
1254
1289
|
? ` const instructions =
|
|
@@ -1377,7 +1412,10 @@ export const createSearch = () => create(${JSON.stringify(provider.options)});
|
|
|
1377
1412
|
* site uses the feature and `null` otherwise, so an unused library is absent
|
|
1378
1413
|
* from the module graph (never bundled, never pre-bundled in dev) rather than
|
|
1379
1414
|
* merely lazy. Regenerated on every pass: a page that gains a mermaid fence
|
|
1380
|
-
* turns the loader on.
|
|
1415
|
+
* turns the loader on. The EPUB module is named — even in a type — only when
|
|
1416
|
+
* `export.epub` is on: an ejected app depends on `epub-gen-memory` only then,
|
|
1417
|
+
* and a type import of a package it can't resolve fails its type check under
|
|
1418
|
+
* a strict linker such as pnpm.
|
|
1381
1419
|
*/
|
|
1382
1420
|
export const featuresTemplate = (features: ClientFeatures): string =>
|
|
1383
1421
|
`// Generated by Blume. Do not edit.
|
|
@@ -1394,9 +1432,13 @@ export const loadMermaid: (() => Promise<unknown>) | null = ${
|
|
|
1394
1432
|
};
|
|
1395
1433
|
|
|
1396
1434
|
/** The EPUB generator's browser bundle; null when export.epub is off. */
|
|
1397
|
-
|
|
1435
|
+
${
|
|
1436
|
+
features.epub
|
|
1437
|
+
? `export const loadEpub:
|
|
1398
1438
|
| (() => Promise<typeof import("epub-gen-memory/bundle")>)
|
|
1399
|
-
| null =
|
|
1439
|
+
| null = () => import("epub-gen-memory/bundle");`
|
|
1440
|
+
: "export const loadEpub: (() => Promise<unknown>) | null = null;"
|
|
1441
|
+
}
|
|
1400
1442
|
`;
|
|
1401
1443
|
|
|
1402
1444
|
/**
|
|
@@ -1561,12 +1603,13 @@ export function GET({ props }: { props: { route: string } }) {
|
|
|
1561
1603
|
* materializes under `.blume/public/blume-assets` (see
|
|
1562
1604
|
* `core/sources/assets.ts`). That directory is NOT Astro's `publicDir`
|
|
1563
1605
|
* (which points at the user project's `public/`), so without this endpoint
|
|
1564
|
-
* those references 404.
|
|
1606
|
+
* those references 404. `null` for an ejected app, which copies those
|
|
1607
|
+
* files into its own `public/blume-assets` instead.
|
|
1565
1608
|
* Prerendered: every asset becomes a static file in the build output; the dev
|
|
1566
1609
|
* server renders on demand, so new images appear without a restart.
|
|
1567
1610
|
*/
|
|
1568
1611
|
export const contentAssetsEndpointTemplate = (
|
|
1569
|
-
stagedAssetsDir: string
|
|
1612
|
+
stagedAssetsDir: string | null
|
|
1570
1613
|
): string =>
|
|
1571
1614
|
`// Generated by Blume. Do not edit.
|
|
1572
1615
|
import { existsSync } from "node:fs";
|
|
@@ -1588,18 +1631,29 @@ const TYPES: Record<string, string> = {
|
|
|
1588
1631
|
".ico": "image/x-icon",
|
|
1589
1632
|
".jpeg": "image/jpeg",
|
|
1590
1633
|
".jpg": "image/jpeg",
|
|
1634
|
+
".mov": "video/quicktime",
|
|
1635
|
+
".mp4": "video/mp4",
|
|
1636
|
+
".ogv": "video/ogg",
|
|
1591
1637
|
".png": "image/png",
|
|
1592
1638
|
".svg": "image/svg+xml",
|
|
1593
1639
|
".tiff": "image/tiff",
|
|
1640
|
+
".webm": "video/webm",
|
|
1594
1641
|
".webp": "image/webp",
|
|
1595
1642
|
};
|
|
1596
1643
|
|
|
1644
|
+
const extensionOf = (path: string): string =>
|
|
1645
|
+
path.slice(path.lastIndexOf(".")).toLowerCase();
|
|
1646
|
+
|
|
1597
1647
|
const contentType = (path: string): string =>
|
|
1598
|
-
TYPES[
|
|
1599
|
-
|
|
1648
|
+
TYPES[extensionOf(path)] ?? "application/octet-stream";
|
|
1649
|
+
|
|
1650
|
+
// A source downloads only images and videos; anything else in the staged
|
|
1651
|
+
// directory (a page an older build saved under its URL's extension) is never
|
|
1652
|
+
// published from the docs origin.
|
|
1653
|
+
const isMedia = (path: string): boolean => Object.hasOwn(TYPES, extensionOf(path));
|
|
1600
1654
|
|
|
1601
1655
|
const stagedParams = async (): Promise<string[]> => {
|
|
1602
|
-
if (!existsSync(STAGED_DIR)) {
|
|
1656
|
+
if (STAGED_DIR === null || !existsSync(STAGED_DIR)) {
|
|
1603
1657
|
return [];
|
|
1604
1658
|
}
|
|
1605
1659
|
const entries = await readdir(STAGED_DIR, {
|
|
@@ -1607,7 +1661,7 @@ const stagedParams = async (): Promise<string[]> => {
|
|
|
1607
1661
|
withFileTypes: true,
|
|
1608
1662
|
});
|
|
1609
1663
|
return entries
|
|
1610
|
-
.filter((entry) => entry.isFile())
|
|
1664
|
+
.filter((entry) => entry.isFile() && isMedia(entry.name))
|
|
1611
1665
|
.map((entry) =>
|
|
1612
1666
|
relative(STAGED_DIR, join(entry.parentPath, entry.name)).replaceAll(
|
|
1613
1667
|
"\\\\",
|
|
@@ -1628,6 +1682,9 @@ const resolveAsset = (asset: string): string | null => {
|
|
|
1628
1682
|
if (asset.startsWith("content/")) {
|
|
1629
1683
|
return files[asset.slice("content/".length)] ?? null;
|
|
1630
1684
|
}
|
|
1685
|
+
if (STAGED_DIR === null) {
|
|
1686
|
+
return null;
|
|
1687
|
+
}
|
|
1631
1688
|
const abs = resolve(STAGED_DIR, asset);
|
|
1632
1689
|
// Traversal guard: the dev server renders on demand, so the param is
|
|
1633
1690
|
// attacker-controlled there — never step outside the staged directory.
|
|
@@ -1637,7 +1694,7 @@ const resolveAsset = (asset: string): string | null => {
|
|
|
1637
1694
|
// asset — and a bare prefix also admits a sibling directory that merely
|
|
1638
1695
|
// shares the name.
|
|
1639
1696
|
const rel = relative(STAGED_DIR, abs);
|
|
1640
|
-
if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
|
|
1697
|
+
if (rel === "" || rel.startsWith("..") || isAbsolute(rel) || !isMedia(rel)) {
|
|
1641
1698
|
return null;
|
|
1642
1699
|
}
|
|
1643
1700
|
return existsSync(abs) ? abs : null;
|
|
@@ -1651,11 +1708,12 @@ export const GET: APIRoute = async ({ params }) => {
|
|
|
1651
1708
|
const body = await readFile(path);
|
|
1652
1709
|
const type = contentType(path);
|
|
1653
1710
|
// An SVG opened directly is a document that can run script; the sandbox
|
|
1654
|
-
// keeps an uploaded one inert on the docs origin.
|
|
1655
|
-
//
|
|
1711
|
+
// keeps an uploaded one inert on the docs origin. This endpoint
|
|
1712
|
+
// prerenders, so these headers reach dev only: a build serves the files
|
|
1713
|
+
// with the same headers from its host's rules (see deploy/headers.ts).
|
|
1656
1714
|
const headers: Record<string, string> =
|
|
1657
1715
|
type === "image/svg+xml"
|
|
1658
|
-
? {
|
|
1716
|
+
? { ...${JSON.stringify(SVG_ASSET_HEADERS)}, "Content-Type": type }
|
|
1659
1717
|
: { "Content-Type": type };
|
|
1660
1718
|
return new Response(new Uint8Array(body), { headers });
|
|
1661
1719
|
};
|
|
@@ -1769,7 +1827,7 @@ export const navFragmentTemplate = (): string =>
|
|
|
1769
1827
|
`---
|
|
1770
1828
|
// Generated by Blume. Do not edit.
|
|
1771
1829
|
import NavTree from "blume/components/layout/NavTree.astro";
|
|
1772
|
-
import {
|
|
1830
|
+
import { withMountedBase } from "blume/components/islands/base-path.ts";
|
|
1773
1831
|
import {
|
|
1774
1832
|
hiddenDefaultLocale,
|
|
1775
1833
|
navGroupIds,
|
|
@@ -1808,7 +1866,7 @@ if (!(variant && node && node.kind === "group")) {
|
|
|
1808
1866
|
}
|
|
1809
1867
|
const strings =
|
|
1810
1868
|
locale === "default" ? data.ui.nav : (data.uiByLocale[locale] ?? data.ui).nav;
|
|
1811
|
-
const fragmentBase =
|
|
1869
|
+
const fragmentBase = withMountedBase(\`/blume-nav/\${version}/\${locale}\`);
|
|
1812
1870
|
---
|
|
1813
1871
|
|
|
1814
1872
|
<NavTree
|
|
@@ -1832,6 +1890,7 @@ export const ogEndpointTemplate = (
|
|
|
1832
1890
|
* Absent, every card renders on every build.
|
|
1833
1891
|
*/
|
|
1834
1892
|
cache?: OgCache;
|
|
1893
|
+
fallbacks?: OgGoogleFont[];
|
|
1835
1894
|
families?: OgFontFamilies;
|
|
1836
1895
|
fonts?: OgFont[];
|
|
1837
1896
|
/**
|
|
@@ -1845,7 +1904,7 @@ export const ogEndpointTemplate = (
|
|
|
1845
1904
|
): string =>
|
|
1846
1905
|
`// Generated by Blume. Do not edit.
|
|
1847
1906
|
import { cachedOgImage } from "blume/og";
|
|
1848
|
-
import type { OgCache, OgFont, OgFontFamilies } from "blume/og";
|
|
1907
|
+
import type { OgCache, OgFont, OgFontFamilies, OgGoogleFont } from "blume/og";
|
|
1849
1908
|
import data from "blume:data";
|
|
1850
1909
|
|
|
1851
1910
|
export const prerender = true;
|
|
@@ -1863,6 +1922,9 @@ const fonts: OgFont[] = ${JSON.stringify(og.fonts ?? [])};
|
|
|
1863
1922
|
const families: OgFontFamilies | undefined = ${
|
|
1864
1923
|
og.families ? JSON.stringify(og.families) : "undefined"
|
|
1865
1924
|
};
|
|
1925
|
+
// Script fallbacks (Noto families, the configured locales' first). A card
|
|
1926
|
+
// fetches them only when its text has a glyph Takumi's built-in font lacks.
|
|
1927
|
+
const fallbacks: OgGoogleFont[] = ${JSON.stringify(og.fallbacks ?? [])};
|
|
1866
1928
|
|
|
1867
1929
|
// Rendered cards are kept on disk between builds, keyed by everything that
|
|
1868
1930
|
// decides their pixels, so a rebuild renders only the cards whose title,
|
|
@@ -1935,6 +1997,7 @@ export async function GET({ props }: { props: CardProps }) {
|
|
|
1935
1997
|
accent: data.config.og.palette?.accent ?? data.config.theme.accent.light,
|
|
1936
1998
|
brand: data.config.title,
|
|
1937
1999
|
description: props.description ?? data.config.og.description,
|
|
2000
|
+
fallbacks,
|
|
1938
2001
|
families,
|
|
1939
2002
|
fonts,
|
|
1940
2003
|
logo: data.config.og.logo,
|
|
@@ -2130,8 +2193,8 @@ export const catchAllPageTemplate = (options: {
|
|
|
2130
2193
|
import { getEntry, render } from "astro:content";
|
|
2131
2194
|
import type { CollectionKey } from "astro:content";
|
|
2132
2195
|
import RootLayout from "blume/components/layout/RootLayout.astro";
|
|
2133
|
-
import { withBase } from "blume/components/islands/base-path.ts";
|
|
2134
|
-
import {
|
|
2196
|
+
import { withBase, withMountedBase } from "blume/components/islands/base-path.ts";
|
|
2197
|
+
import { mountBasePath, stripBasePath } from "blume/core/base-path.ts";
|
|
2135
2198
|
import { resolveSlot } from "blume/components/layout/overrides.ts";
|
|
2136
2199
|
${componentImports}
|
|
2137
2200
|
import data from "blume:data";
|
|
@@ -2196,12 +2259,16 @@ const base = data.config.site ? data.config.site.replace(/\\/$/, "") : null;
|
|
|
2196
2259
|
const ogPath = data.config.og.enabled
|
|
2197
2260
|
? encodeURI(\`/og/\${route === "/" ? "index" : route.slice(1)}.png\`)
|
|
2198
2261
|
: null;
|
|
2199
|
-
const ogRel = seo.image ?? ogPath;
|
|
2200
2262
|
// Absolute URLs also carry the deployment base (the page is served under it):
|
|
2201
2263
|
// \`site + base + path\`. Only absolutize root-relative paths: \`seo.image\` may be
|
|
2202
|
-
// an external URL, which passes through verbatim (mirrors PageLayout).
|
|
2203
|
-
|
|
2204
|
-
|
|
2264
|
+
// an external URL, which passes through verbatim (mirrors PageLayout). An
|
|
2265
|
+
// authored \`seo.image\` keeps a base written by hand; the generated card is
|
|
2266
|
+
// always mounted under it.
|
|
2267
|
+
const absoluteOg = (path: string, based: (path: string) => string) =>
|
|
2268
|
+
base && path.startsWith("/") ? \`\${base}\${based(path)}\` : path;
|
|
2269
|
+
const ogImage = seo.image
|
|
2270
|
+
? absoluteOg(seo.image, withBase)
|
|
2271
|
+
: ogPath && absoluteOg(ogPath, withMountedBase);
|
|
2205
2272
|
// Blume's generated card has known dimensions the layout can declare; a user's
|
|
2206
2273
|
// \`seo.image\` could be any size or format, so it gets none.
|
|
2207
2274
|
const ogGenerated = !seo.image && Boolean(ogPath);
|
|
@@ -2210,7 +2277,7 @@ const ogGenerated = !seo.image && Boolean(ogPath);
|
|
|
2210
2277
|
// itself (a guest post crediting its own author) over the configured default.
|
|
2211
2278
|
const x = { ...data.config.x, ...(seo.x?.creator ? { creator: seo.x.creator } : {}) };
|
|
2212
2279
|
|
|
2213
|
-
const basedRoute =
|
|
2280
|
+
const basedRoute = withMountedBase(route);
|
|
2214
2281
|
|
|
2215
2282
|
// Locale resolution. With i18n on, pick the active locale's nav + dictionary,
|
|
2216
2283
|
// build hreflang alternates, and derive the language-switcher targets.
|
|
@@ -2258,7 +2325,7 @@ const contentDir = i18n
|
|
|
2258
2325
|
: "ltr";
|
|
2259
2326
|
// The root route keeps its trailing slash (\`https://site/\`) so canonical and
|
|
2260
2327
|
// hreflang URLs byte-match the sitemap's <loc> for the home page.
|
|
2261
|
-
const absolute = (path: string) => base +
|
|
2328
|
+
const absolute = (path: string) => base + withMountedBase(path);
|
|
2262
2329
|
|
|
2263
2330
|
// A fallback page renders the fallback locale's page at this locale's URL, so
|
|
2264
2331
|
// its canonical names the page it copies, and search engines never rank the
|
|
@@ -2303,7 +2370,7 @@ const xDefault = defaultAlt && base ? absolute(defaultAlt.path) : null;
|
|
|
2303
2370
|
// carries sits *after* the base (\`/docs/ja/guide\`), while \`localePrefix\` is
|
|
2304
2371
|
// base-less (\`/ja\`). Stripping and re-adding a locale therefore happen in
|
|
2305
2372
|
// base-less space, with the base re-applied at the end — the same
|
|
2306
|
-
// \`
|
|
2373
|
+
// \`mountBasePath(basePath, localizeRoute(...))\` composition the manifest uses to
|
|
2307
2374
|
// build every real route. Done in based space, \`stripLocale\` matches nothing
|
|
2308
2375
|
// and \`localizeRoute\` prepends a second prefix (\`/ja/docs/ja/guide\`). Only a
|
|
2309
2376
|
// switcher entry for a locale with no real translation reaches this fallback:
|
|
@@ -2311,7 +2378,7 @@ const xDefault = defaultAlt && base ? absolute(defaultAlt.path) : null;
|
|
|
2311
2378
|
// generated reference (which has no \`alternates\` at all) for every locale
|
|
2312
2379
|
// but its own.
|
|
2313
2380
|
const mountLocalized = (logical: string, codeArg: string) =>
|
|
2314
|
-
|
|
2381
|
+
mountBasePath(data.config.basePath, localizeRoute(logical, codeArg));
|
|
2315
2382
|
const logicalRoute = i18n
|
|
2316
2383
|
? stripLocale(stripBasePath(data.config.basePath, route), locale)
|
|
2317
2384
|
: route;
|
|
@@ -2340,7 +2407,7 @@ const versionRootFor = (id: string) => {
|
|
|
2340
2407
|
const logical = id ? \`/\${id}\` : "/";
|
|
2341
2408
|
return i18n
|
|
2342
2409
|
? mountLocalized(logical, locale)
|
|
2343
|
-
:
|
|
2410
|
+
: mountBasePath(data.config.basePath, logical);
|
|
2344
2411
|
};
|
|
2345
2412
|
const samePageSwitch = versionsConfig
|
|
2346
2413
|
? versionsConfig.switcher.redirect === "same-page"
|
|
@@ -2440,7 +2507,7 @@ const LayoutComponent = resolveSlot(layoutOverrides.Layout, RootLayout);
|
|
|
2440
2507
|
exportEpub={${options.exportEpub}}${
|
|
2441
2508
|
options.navFragments
|
|
2442
2509
|
? `
|
|
2443
|
-
navFragmentBase={
|
|
2510
|
+
navFragmentBase={withMountedBase(\`/blume-nav/\${version || "current"}/\${i18n && localePrefix(locale) ? locale : "default"}\`)}`
|
|
2444
2511
|
: ""
|
|
2445
2512
|
}
|
|
2446
2513
|
openInChat={data.config.openInChat}
|
|
@@ -2493,7 +2560,7 @@ export const changelogIndexTemplate = (options: {
|
|
|
2493
2560
|
// Generated by Blume. Do not edit.
|
|
2494
2561
|
import { getCollection } from "astro:content";
|
|
2495
2562
|
import RootLayout from "blume/components/layout/RootLayout.astro";
|
|
2496
|
-
import {
|
|
2563
|
+
import { withMountedBase } from "blume/components/islands/base-path.ts";
|
|
2497
2564
|
import { resolveSlot } from "blume/components/layout/overrides.ts";
|
|
2498
2565
|
import { resolveDateFormatOptions } from "blume/core/date-format.ts";
|
|
2499
2566
|
import { layoutOverrides } from "../generated/components.ts";
|
|
@@ -2592,7 +2659,7 @@ const items = changelogEntries.map((entry) => {
|
|
|
2592
2659
|
return {
|
|
2593
2660
|
date: date ? formatRowDate(date) : null,
|
|
2594
2661
|
dateTime: date ? date.toISOString().slice(0, 10) : null,
|
|
2595
|
-
href: route ?
|
|
2662
|
+
href: route ? withMountedBase(route) : null,
|
|
2596
2663
|
id: slugify(label),
|
|
2597
2664
|
label,
|
|
2598
2665
|
tag: entry.data.changelog?.category ?? null,
|
|
@@ -2628,14 +2695,14 @@ for (const item of items) {
|
|
|
2628
2695
|
|
|
2629
2696
|
const base = data.config.site ? data.config.site.replace(/\\/$/, "") : null;
|
|
2630
2697
|
// The canonical URL carries the deployment base (the page is served under it),
|
|
2631
|
-
// matching how the catch-all canonicalizes via \`
|
|
2632
|
-
const basedRoute =
|
|
2698
|
+
// matching how the catch-all canonicalizes via \`withMountedBase(route)\`.
|
|
2699
|
+
const basedRoute = withMountedBase("/changelog");
|
|
2633
2700
|
const canonical = base ? base + basedRoute : null;
|
|
2634
2701
|
|
|
2635
2702
|
// The generated OG card for this route (the /og endpoint emits it alongside
|
|
2636
2703
|
// the content-route cards), absolutized like the catch-all's so crawlers get
|
|
2637
2704
|
// a full URL when the site is known.
|
|
2638
|
-
const ogPath = data.config.og.enabled ?
|
|
2705
|
+
const ogPath = data.config.og.enabled ? withMountedBase("/og/changelog.png") : null;
|
|
2639
2706
|
const ogImage = ogPath && base ? base + ogPath : ogPath;
|
|
2640
2707
|
|
|
2641
2708
|
// The page chrome (h1, title, description) comes from the translatable
|
|
@@ -2757,7 +2824,8 @@ export const notFoundPageTemplate = (): string => `---
|
|
|
2757
2824
|
// Generated by Blume. Do not edit. Override by adding \`pages/404.astro\`.
|
|
2758
2825
|
import Icon from "blume/components/Icon.astro";
|
|
2759
2826
|
import PageLayout from "blume/components/layout/PageLayout.astro";
|
|
2760
|
-
import {
|
|
2827
|
+
import { withMountedBase } from "blume/components/islands/base-path.ts";
|
|
2828
|
+
import { mountBasePath } from "blume/core/base-path.ts";
|
|
2761
2829
|
import data from "blume:data";
|
|
2762
2830
|
|
|
2763
2831
|
export const prerender = true;
|
|
@@ -2781,22 +2849,27 @@ const htmlLang = i18n ? i18n.defaultLocale : "en";
|
|
|
2781
2849
|
// their resolved target when the section has no index page of its own.
|
|
2782
2850
|
const suggestions = [
|
|
2783
2851
|
...data.navigation.tabs.map((tab) => ({
|
|
2784
|
-
href:
|
|
2852
|
+
href: withMountedBase(tab.href ?? tab.path),
|
|
2785
2853
|
label: tab.label,
|
|
2786
2854
|
})),
|
|
2787
2855
|
...(data.config.discovery.sitemap
|
|
2788
|
-
? [{ href:
|
|
2856
|
+
? [{ href: withMountedBase("/sitemap.xml"), label: nf.sitemap }]
|
|
2789
2857
|
: []),
|
|
2790
2858
|
...(data.config.discovery.llmsTxt
|
|
2791
|
-
? [{ href:
|
|
2859
|
+
? [{ href: withMountedBase("/llms.txt"), label: nf.llms }]
|
|
2792
2860
|
: []),
|
|
2793
2861
|
];
|
|
2794
2862
|
|
|
2795
2863
|
// Every host serves this one page for any missing URL, so a reader who
|
|
2796
2864
|
// mistyped \`/ar/…\` would get the default locale's message. The other locales'
|
|
2797
2865
|
// copy rides along, and the script below swaps it in when the URL's first
|
|
2798
|
-
// segment names one of them — the message, its language
|
|
2799
|
-
// tab title, and the home link (to that locale's root).
|
|
2866
|
+
// segment past the site's base names one of them — the message, its language
|
|
2867
|
+
// and direction, the tab title, and the home link (to that locale's root).
|
|
2868
|
+
// Localized routes sit under both bases (\`{deployment.base}/{basePath}/ar/…\`),
|
|
2869
|
+
// so the script strips the two together, trailing slash included.
|
|
2870
|
+
const { basePath } = data.config;
|
|
2871
|
+
const siteRoot = withMountedBase(mountBasePath(basePath, "/"));
|
|
2872
|
+
const localeBase = siteRoot.endsWith("/") ? siteRoot : siteRoot + "/";
|
|
2800
2873
|
const localized = Object.fromEntries(
|
|
2801
2874
|
(i18n?.locales ?? [])
|
|
2802
2875
|
.filter((l) => l.code !== i18n?.defaultLocale && data.uiByLocale[l.code])
|
|
@@ -2808,7 +2881,7 @@ const localized = Object.fromEntries(
|
|
|
2808
2881
|
description: strings.description,
|
|
2809
2882
|
dir: l.dir ?? "ltr",
|
|
2810
2883
|
home: strings.home,
|
|
2811
|
-
homeHref:
|
|
2884
|
+
homeHref: withMountedBase(mountBasePath(basePath, "/" + l.code)),
|
|
2812
2885
|
suggestions: strings.suggestions,
|
|
2813
2886
|
title: strings.title,
|
|
2814
2887
|
},
|
|
@@ -2837,7 +2910,7 @@ const localizedJson = JSON.stringify(localized).replaceAll("<", "\\\\u003c");
|
|
|
2837
2910
|
>
|
|
2838
2911
|
<div
|
|
2839
2912
|
class="mx-auto grid w-full max-w-5xl gap-12 px-6 py-20 sm:py-28 md:grid-cols-[3fr_2fr] md:gap-16 lg:gap-24 lg:py-36"
|
|
2840
|
-
data-base={
|
|
2913
|
+
data-base={localeBase}
|
|
2841
2914
|
data-blume-not-found
|
|
2842
2915
|
>
|
|
2843
2916
|
<div class="flex flex-col items-start">
|
|
@@ -2858,7 +2931,7 @@ const localizedJson = JSON.stringify(localized).replaceAll("<", "\\\\u003c");
|
|
|
2858
2931
|
<a
|
|
2859
2932
|
class="mt-8 inline-flex items-center gap-1.5 rounded-full bg-accent py-2 pe-4 ps-3.5 text-sm font-medium text-accent-foreground transition-opacity hover:opacity-90"
|
|
2860
2933
|
data-nf-home
|
|
2861
|
-
href={
|
|
2934
|
+
href={withMountedBase("/")}
|
|
2862
2935
|
>
|
|
2863
2936
|
<Icon class="rtl:-scale-x-100" name="arrow-left" size={14} />
|
|
2864
2937
|
<span data-nf="home">{nf.home}</span>
|
|
@@ -2940,7 +3013,7 @@ const localizedJson = JSON.stringify(localized).replaceAll("<", "\\\\u003c");
|
|
|
2940
3013
|
*/
|
|
2941
3014
|
export const notFoundMarkdownTemplate =
|
|
2942
3015
|
(): string => `// Generated by Blume. Do not edit. Override by adding \`pages/404.astro\`.
|
|
2943
|
-
import {
|
|
3016
|
+
import { withMountedBase } from "blume/components/islands/base-path.ts";
|
|
2944
3017
|
import { absoluteUrl } from "blume/core/site-url.ts";
|
|
2945
3018
|
import data from "blume:data";
|
|
2946
3019
|
|
|
@@ -2951,7 +3024,7 @@ const nf = data.ui.notFound;
|
|
|
2951
3024
|
// Absolute for internal routes when the site is known; an external tab href
|
|
2952
3025
|
// passes through untouched.
|
|
2953
3026
|
const href = (path: string): string => {
|
|
2954
|
-
const based =
|
|
3027
|
+
const based = withMountedBase(path);
|
|
2955
3028
|
return data.config.site && based.startsWith("/") && !based.startsWith("//")
|
|
2956
3029
|
? absoluteUrl(data.config.site, based)
|
|
2957
3030
|
: based;
|
|
@@ -3010,7 +3083,7 @@ export function GET() {
|
|
|
3010
3083
|
export const notFoundJsonTemplate =
|
|
3011
3084
|
(): string => `// Generated by Blume. Do not edit. Override by adding \`pages/404.astro\`.
|
|
3012
3085
|
import { problem } from "blume/ai/api/problem.ts";
|
|
3013
|
-
import {
|
|
3086
|
+
import { withMountedBase } from "blume/components/islands/base-path.ts";
|
|
3014
3087
|
import { absoluteUrl } from "blume/core/site-url.ts";
|
|
3015
3088
|
import data from "blume:data";
|
|
3016
3089
|
|
|
@@ -3021,7 +3094,7 @@ const nf = data.ui.notFound;
|
|
|
3021
3094
|
// Absolute for internal routes when the site is known; an external tab href
|
|
3022
3095
|
// passes through untouched.
|
|
3023
3096
|
const href = (path: string): string => {
|
|
3024
|
-
const based =
|
|
3097
|
+
const based = withMountedBase(path);
|
|
3025
3098
|
return data.config.site && based.startsWith("/") && !based.startsWith("//")
|
|
3026
3099
|
? absoluteUrl(data.config.site, based)
|
|
3027
3100
|
: based;
|
|
@@ -3196,7 +3269,7 @@ ${wrapperPropsType("Example")}
|
|
|
3196
3269
|
/**
|
|
3197
3270
|
* The route prefix `<Component />` preview frames are served under:
|
|
3198
3271
|
* `{basePath}/blume-examples/<example path>`. `deployment.base` is layered on
|
|
3199
|
-
* top by Astro (components apply it with `
|
|
3272
|
+
* top by Astro (components apply it with `withMountedBase`).
|
|
3200
3273
|
*/
|
|
3201
3274
|
export const examplesRouteBase = (basePath: string): string =>
|
|
3202
3275
|
`${basePath}/blume-examples`;
|
|
@@ -3300,11 +3373,20 @@ const Example = entry.Component;
|
|
|
3300
3373
|
root.dataset.theme = theme;
|
|
3301
3374
|
root.classList.toggle("dark", theme === "dark");
|
|
3302
3375
|
};
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3376
|
+
// Blocked storage (a sandboxed or privacy-locked frame) throws on
|
|
3377
|
+
// access; it falls through to the OS setting like an unset preference.
|
|
3378
|
+
const stored = () => {
|
|
3379
|
+
let theme = null;
|
|
3380
|
+
try {
|
|
3381
|
+
theme = localStorage.getItem("blume-theme");
|
|
3382
|
+
} catch {}
|
|
3383
|
+
return (
|
|
3384
|
+
theme ??
|
|
3385
|
+
(matchMedia("(prefers-color-scheme: dark)").matches
|
|
3386
|
+
? "dark"
|
|
3387
|
+
: "light")
|
|
3388
|
+
);
|
|
3389
|
+
};
|
|
3308
3390
|
try {
|
|
3309
3391
|
const host = window.parent.document.documentElement;
|
|
3310
3392
|
apply(host.dataset.theme ?? stored());
|
package/src/audit/catalog.ts
CHANGED
|
@@ -583,7 +583,7 @@ export const CHECKS = [
|
|
|
583
583
|
},
|
|
584
584
|
{
|
|
585
585
|
category: "sitemap",
|
|
586
|
-
fix: "Sitemaps must be valid XML in the sitemaps.org urlset format.",
|
|
586
|
+
fix: "Sitemaps must be valid XML in the sitemaps.org urlset or sitemap index format.",
|
|
587
587
|
id: "BLUME_AUDIT_SITEMAP_INVALID",
|
|
588
588
|
severity: "error",
|
|
589
589
|
tier: "static",
|
|
@@ -684,7 +684,7 @@ export const CHECKS = [
|
|
|
684
684
|
},
|
|
685
685
|
{
|
|
686
686
|
category: "ai",
|
|
687
|
-
fix: "Rebuild so llms.txt matches the site; if the page is deliberately excluded,
|
|
687
|
+
fix: "Rebuild so llms.txt matches the site; if the page is deliberately excluded, set `ai.exclude: true` in its front matter.",
|
|
688
688
|
id: "BLUME_AUDIT_LLMS_TXT_PAGE_MISSING",
|
|
689
689
|
severity: "warning",
|
|
690
690
|
tier: "static",
|
|
@@ -11,6 +11,13 @@ import type {
|
|
|
11
11
|
} from "../types.ts";
|
|
12
12
|
import { resolveHref, siteOrigin } from "../url.ts";
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Vercel's image optimization route (`/_vercel/image?url=…&w=…`), which
|
|
16
|
+
* `imageService` on the Vercel adapter points `<img>` at. The platform
|
|
17
|
+
* serves it; the build never writes a file there.
|
|
18
|
+
*/
|
|
19
|
+
const VERCEL_IMAGE_ENDPOINT = "/_vercel/image";
|
|
20
|
+
|
|
14
21
|
const formatBytes = (bytes: number): string =>
|
|
15
22
|
bytes < 1024 * 1024
|
|
16
23
|
? `${Math.round(bytes / 1024)} kB`
|
|
@@ -44,17 +51,30 @@ const resolveAsset = (
|
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
const origin = siteOrigin(context.project.config.deployment.options.site);
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
asset.src,
|
|
50
|
-
origin,
|
|
51
|
-
normalizeBasePath(context.project.config.deployment.options.base)
|
|
54
|
+
const deployBase = normalizeBasePath(
|
|
55
|
+
context.project.config.deployment.options.base
|
|
52
56
|
);
|
|
57
|
+
const resolved = resolveHref(page.url, asset.src, origin, deployBase);
|
|
53
58
|
// A subresource on another origin (a CDN, an analytics script) is outside the
|
|
54
59
|
// build; we can't check whether it exists without the network.
|
|
55
60
|
if (resolved.kind === "external" || resolved.kind === "ignored") {
|
|
56
61
|
return null;
|
|
57
62
|
}
|
|
63
|
+
// Vercel's image optimization endpoint answers these at request time, at the
|
|
64
|
+
// host root whatever the base.
|
|
65
|
+
if (resolved.path === VERCEL_IMAGE_ENDPOINT) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (resolved.kind === "outside-base") {
|
|
69
|
+
found.push(
|
|
70
|
+
finding(
|
|
71
|
+
missingId,
|
|
72
|
+
pageSite(context, page),
|
|
73
|
+
`Page references ${asset.src}, which is missing deployment.base (${deployBase}), so the deployed site does not serve it.`
|
|
74
|
+
)
|
|
75
|
+
);
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
58
78
|
|
|
59
79
|
const bytes = context.files.get(resolved.path);
|
|
60
80
|
if (bytes === undefined) {
|
|
@@ -38,6 +38,22 @@ const frontmatterDate = (source: string): Date | null => {
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* API reference pages (OpenAPI, AsyncAPI, GraphQL) are generated from a spec
|
|
43
|
+
* and have no front matter to edit: their title comes from the operation's
|
|
44
|
+
* summary (the spec's own title on the overview page) and their description
|
|
45
|
+
* from its description or summary. A fix naming front matter would send the
|
|
46
|
+
* reader to a file that doesn't exist.
|
|
47
|
+
*/
|
|
48
|
+
const isGeneratedReference = (page: PageSnapshot): boolean =>
|
|
49
|
+
page.route?.source.name === "openapi";
|
|
50
|
+
|
|
51
|
+
const GENERATED_TITLE_FIX =
|
|
52
|
+
"This page is generated from an API spec, which titles it with the operation's `summary` (the spec's own title on the overview page) — rewrite it there.";
|
|
53
|
+
|
|
54
|
+
const GENERATED_DESCRIPTION_FIX =
|
|
55
|
+
"This page is generated from an API spec, which describes it with the operation's `description` or `summary` (the spec's own description on the overview page) — rewrite it there.";
|
|
56
|
+
|
|
41
57
|
const titleChecks = (
|
|
42
58
|
context: AuditContext,
|
|
43
59
|
page: PageSnapshot
|
|
@@ -74,7 +90,8 @@ const titleChecks = (
|
|
|
74
90
|
finding(
|
|
75
91
|
"BLUME_AUDIT_TITLE_LENGTH",
|
|
76
92
|
pageSite(context, page, ["title"]),
|
|
77
|
-
`Title renders ${width} columns wide — too ${direction} (aim for ${titleMin}–${titleMax})
|
|
93
|
+
`Title renders ${width} columns wide — too ${direction} (aim for ${titleMin}–${titleMax}).`,
|
|
94
|
+
isGeneratedReference(page) ? GENERATED_TITLE_FIX : undefined
|
|
78
95
|
)
|
|
79
96
|
);
|
|
80
97
|
}
|
|
@@ -123,7 +140,8 @@ const descriptionChecks = (
|
|
|
123
140
|
finding(
|
|
124
141
|
"BLUME_AUDIT_DESCRIPTION_LENGTH",
|
|
125
142
|
pageSite(context, page, ["description"]),
|
|
126
|
-
`Meta description renders ${width} columns wide — too ${direction} (aim for ${descriptionMin}–${descriptionMax})
|
|
143
|
+
`Meta description renders ${width} columns wide — too ${direction} (aim for ${descriptionMin}–${descriptionMax}).`,
|
|
144
|
+
isGeneratedReference(page) ? GENERATED_DESCRIPTION_FIX : undefined
|
|
127
145
|
)
|
|
128
146
|
);
|
|
129
147
|
}
|