blume 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +48 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-1d7ve1dm.js → chunk-0gz36akr.js} +18 -2
- package/dist/cli/{chunk-1d7ve1dm.js.map → chunk-0gz36akr.js.map} +3 -3
- package/dist/cli/{chunk-2eytanqx.js → chunk-1n228xqb.js} +2 -2
- package/dist/cli/{chunk-yfyb25rh.js → chunk-2f3ndkpw.js} +24 -8
- package/dist/cli/chunk-2f3ndkpw.js.map +14 -0
- package/dist/cli/{chunk-r20tn01b.js → chunk-2f7n4qzt.js} +8 -2
- package/dist/cli/{chunk-r20tn01b.js.map → chunk-2f7n4qzt.js.map} +3 -3
- package/dist/cli/{chunk-35d4wj9f.js → chunk-2n4ps1b3.js} +7 -7
- package/dist/cli/{chunk-j85vccga.js → chunk-43zcf4gz.js} +97 -57
- package/dist/cli/{chunk-j85vccga.js.map → chunk-43zcf4gz.js.map} +6 -6
- package/dist/cli/{chunk-e04dxsz1.js → chunk-4ejxbzee.js} +1 -1
- package/dist/cli/{chunk-5m5nmvyq.js → chunk-4h8z9vv5.js} +233 -39
- package/dist/cli/chunk-4h8z9vv5.js.map +16 -0
- package/dist/cli/{chunk-5f86nr5m.js → chunk-5cg2rzgf.js} +18 -16
- package/dist/cli/{chunk-5f86nr5m.js.map → chunk-5cg2rzgf.js.map} +2 -2
- package/dist/cli/{chunk-tzmab476.js → chunk-5ffywsmb.js} +4 -4
- package/dist/cli/{chunk-2z928egk.js → chunk-5wj2qwn2.js} +5 -5
- package/dist/cli/chunk-6bm0xpgd.js +18 -0
- package/dist/cli/chunk-6bm0xpgd.js.map +10 -0
- package/dist/cli/{chunk-vg9r4eb9.js → chunk-713mngdq.js} +12 -5
- package/dist/cli/{chunk-vg9r4eb9.js.map → chunk-713mngdq.js.map} +3 -3
- package/dist/cli/{chunk-5xvm6tfj.js → chunk-9geymqns.js} +17 -15
- package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-9geymqns.js.map} +2 -2
- package/dist/cli/{chunk-q58y5e6a.js → chunk-9xr4dgee.js} +26 -17
- package/dist/cli/chunk-9xr4dgee.js.map +10 -0
- package/dist/cli/{chunk-b07cmahc.js → chunk-amrb6hgh.js} +2 -2
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-akbpwfxc.js → chunk-cmtcnh9f.js} +2 -2
- package/dist/cli/chunk-cy5bm0j0.js +104 -0
- package/dist/cli/chunk-cy5bm0j0.js.map +11 -0
- package/dist/cli/{chunk-crgn1q09.js → chunk-e7vvk5ya.js} +4 -4
- package/dist/cli/{chunk-pehfxfta.js → chunk-g2z9x01v.js} +6 -98
- package/dist/cli/chunk-g2z9x01v.js.map +10 -0
- package/dist/cli/{chunk-tkacnehg.js → chunk-gp84za0h.js} +2 -2
- package/dist/cli/{chunk-wrr3j9w9.js → chunk-h2a48yhd.js} +186 -63
- package/dist/cli/chunk-h2a48yhd.js.map +36 -0
- package/dist/cli/{chunk-hm3vjy5s.js → chunk-jnwj5kjj.js} +14 -9
- package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-jnwj5kjj.js.map} +4 -4
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-2hsdwb9n.js → chunk-nd1821sk.js} +18 -16
- package/dist/cli/{chunk-2hsdwb9n.js.map → chunk-nd1821sk.js.map} +2 -2
- package/dist/cli/{chunk-6dsbexzp.js → chunk-ntv4qrt7.js} +17 -15
- package/dist/cli/{chunk-6dsbexzp.js.map → chunk-ntv4qrt7.js.map} +2 -2
- package/dist/cli/{chunk-r9rcc4w7.js → chunk-p804f3pe.js} +7 -7
- package/dist/cli/{chunk-ey84smr6.js → chunk-py62fewh.js} +6 -6
- package/dist/cli/{chunk-ey84smr6.js.map → chunk-py62fewh.js.map} +1 -1
- package/dist/cli/chunk-q3wxxq39.js +126 -0
- package/dist/cli/chunk-q3wxxq39.js.map +11 -0
- package/dist/cli/{chunk-9t7a85s3.js → chunk-rekqz4qg.js} +23 -13
- package/dist/cli/chunk-rekqz4qg.js.map +10 -0
- package/dist/cli/{chunk-8ktnccpt.js → chunk-ta27feev.js} +1 -1
- package/dist/cli/{chunk-pv29h0wf.js → chunk-xkz5xbtv.js} +3476 -822
- package/dist/cli/chunk-xkz5xbtv.js.map +213 -0
- package/dist/cli/{chunk-a58773jm.js → chunk-y4ykbark.js} +2 -2
- package/dist/cli/{chunk-p3v96n38.js → chunk-y5h4r2y0.js} +4 -4
- package/dist/cli/{chunk-acanzt5p.js → chunk-yj17vs39.js} +6 -6
- package/dist/cli/{chunk-p73c0m7w.js → chunk-yxmk4pec.js} +16 -14
- package/dist/cli/{chunk-p73c0m7w.js.map → chunk-yxmk4pec.js.map} +2 -2
- package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
- package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
- package/dist/cli/{chunk-c8chx29p.js → chunk-zf748avv.js} +384 -207
- package/dist/cli/chunk-zf748avv.js.map +37 -0
- package/dist/cli/{chunk-g4hq16wv.js → chunk-zhvd6adm.js} +16 -14
- package/dist/cli/{chunk-g4hq16wv.js.map → chunk-zhvd6adm.js.map} +2 -2
- package/dist/cli/index.js +26 -20
- package/dist/cli/index.js.map +5 -5
- package/dist/types/ai/agent-surface.d.ts +8 -7
- package/dist/types/ai/ai-catalog.d.ts +7 -0
- package/dist/types/ai/ask-context.d.ts +22 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +16 -0
- package/dist/types/astro/integration.d.ts +8 -0
- package/dist/types/captcha/hcaptcha.d.ts +27 -0
- package/dist/types/captcha/index.d.ts +28 -0
- package/dist/types/captcha/schema.d.ts +29 -0
- package/dist/types/captcha/turnstile.d.ts +28 -0
- package/dist/types/components/content/api-field.d.ts +59 -0
- package/dist/types/components/content/api-page.d.ts +95 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/helpers.d.ts +137 -0
- package/dist/types/components/openapi/security.d.ts +85 -0
- package/dist/types/consent/ethyca.d.ts +48 -0
- package/dist/types/consent/index.d.ts +37 -0
- package/dist/types/consent/native.d.ts +28 -0
- package/dist/types/consent/osano.d.ts +42 -0
- package/dist/types/consent/schema.d.ts +110 -0
- package/dist/types/core/config-input.d.ts +187 -20
- package/dist/types/core/data.d.ts +49 -4
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/i18n-ui.d.ts +86 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/redirect-patterns.d.ts +144 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +551 -56
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/types.d.ts +1 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +5 -0
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/vercel.d.ts +6 -0
- package/dist/types/deploy/redirects.d.ts +39 -11
- package/dist/types/deploy/vercel-negotiation.d.ts +9 -0
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/features.d.ts +3 -2
- package/dist/types/narration/build.d.ts +70 -0
- package/dist/types/narration/provider.d.ts +26 -0
- package/dist/types/narration/script.d.ts +154 -0
- package/dist/types/openapi/model.d.ts +12 -6
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +13 -0
- package/dist/types/openapi/references.d.ts +14 -4
- package/dist/types/ratelimit/cloudflare.d.ts +39 -0
- package/dist/types/ratelimit/index.d.ts +27 -0
- package/dist/types/ratelimit/memory.d.ts +36 -0
- package/dist/types/ratelimit/schema.d.ts +111 -0
- package/dist/types/ratelimit/upstash.d.ts +21 -0
- package/dist/types/ratelimit/wrangler.d.ts +23 -0
- package/dist/types/reference/asyncapi.d.ts +10 -10
- package/dist/types/reference/graphql.d.ts +13 -10
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +45 -5
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +60 -36
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +4 -0
- package/dist/types/seo/metatags.d.ts +20 -0
- package/docs/02-deployment.mdx +41 -5
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/advanced/changelog.mdx +2 -2
- package/docs/advanced/skills.mdx +14 -0
- package/docs/cli/audit.mdx +21 -1
- package/docs/cli/index.mdx +1 -0
- package/docs/configuration/analytics.mdx +3 -1
- package/docs/configuration/assistant.mdx +188 -36
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +4 -4
- package/docs/configuration/index.mdx +63 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +69 -0
- package/docs/configuration/search.mdx +29 -1
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +106 -0
- package/docs/content/frontmatter.mdx +76 -0
- package/docs/content/i18n.mdx +38 -3
- package/docs/content/includes.mdx +16 -0
- package/docs/content/meta.mdx +1 -0
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +28 -6
- package/docs/content/sources/contentful.mdx +32 -0
- package/docs/content/sources/custom.mdx +39 -0
- package/docs/content/sources/github-releases.mdx +31 -0
- package/docs/content/sources/index.mdx +91 -0
- package/docs/content/sources/meta.ts +16 -0
- package/docs/content/sources/notion.mdx +32 -0
- package/docs/content/sources/obsidian.mdx +37 -0
- package/docs/content/sources/payload.mdx +30 -0
- package/docs/content/sources/remote-mdx.mdx +40 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +31 -0
- package/docs/content/syntax.mdx +67 -2
- package/docs/content/variables.mdx +41 -0
- package/docs/discoverability/agent-discovery.mdx +29 -2
- package/docs/discoverability/index.mdx +1 -1
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +1 -1
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +102 -3
- package/docs/references/scalar.mdx +3 -1
- package/package.json +36 -1
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +5 -5
- package/skills/blume-migrate/references/docusaurus.md +3 -3
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +2 -2
- package/skills/blume-migrate/references/starlight.md +2 -1
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +2 -1
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +6 -3
- package/src/ai/ask-context.ts +73 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/component-markdown.ts +75 -0
- package/src/ai/cors.ts +2 -0
- package/src/ai/index.ts +12 -0
- package/src/ai/llms.ts +6 -2
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/openapi-components.ts +9 -3
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +35 -2
- package/src/ai/write-skill.ts +97 -0
- package/src/astro/generate.ts +132 -18
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +35 -0
- package/src/astro/module-types.ts +6 -0
- package/src/astro/templates.ts +283 -30
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +19 -0
- package/src/audit/checks/contrast.ts +183 -0
- package/src/audit/checks/i18n.ts +2 -3
- package/src/audit/checks/indexability.ts +2 -3
- package/src/audit/checks/links.ts +5 -12
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +2 -0
- package/src/audit/types.ts +2 -1
- package/src/blume-modules.d.ts +7 -0
- package/src/captcha/client.ts +152 -0
- package/src/captcha/hcaptcha.ts +36 -0
- package/src/captcha/index.ts +28 -0
- package/src/captcha/schema.ts +32 -0
- package/src/captcha/turnstile.ts +38 -0
- package/src/captcha/verify.ts +71 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/doctor.ts +22 -16
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/index.ts +5 -0
- package/src/cli/required-secrets.ts +71 -29
- package/src/components/BlumePage.astro +2 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +62 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Color.astro +1 -0
- package/src/components/content/FileTree.astro +1 -0
- package/src/components/content/GithubInfo.astro +1 -0
- package/src/components/content/Panel.astro +1 -0
- package/src/components/content/ParamField.astro +25 -0
- package/src/components/content/RequestExample.astro +17 -0
- package/src/components/content/ResponseExample.astro +17 -0
- package/src/components/content/ResponseField.astro +32 -0
- package/src/components/content/Step.astro +1 -0
- package/src/components/content/Tile.astro +1 -0
- package/src/components/content/Tooltip.astro +1 -0
- package/src/components/content/Tree.astro +1 -0
- package/src/components/content/TypeTable.astro +4 -1
- package/src/components/content/View.astro +21 -0
- package/src/components/content/ViewSwitcher.astro +168 -0
- package/src/components/content/api-field.ts +100 -0
- package/src/components/content/api-page.ts +224 -0
- package/src/components/content/view-switcher.ts +71 -0
- package/src/components/index.ts +2 -0
- package/src/components/islands/Assistant.astro +10 -1
- package/src/components/islands/assistant.tsx +104 -14
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +110 -21
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +6 -2
- package/src/components/layout/ConsentBanner.astro +62 -0
- package/src/components/layout/ConsentHead.astro +38 -0
- package/src/components/layout/Directory.astro +94 -0
- package/src/components/layout/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +122 -80
- package/src/components/layout/LanguageSwitcher.astro +48 -15
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +33 -7
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +71 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +308 -45
- package/src/components/layout/Search.astro +31 -17
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/consent/native.ts +79 -0
- package/src/components/layout/consent/types.ts +37 -0
- package/src/components/layout/footer-links.ts +53 -0
- package/src/components/layout/footer-socials.ts +87 -0
- package/src/components/layout/locale-redirect.ts +107 -0
- package/src/components/layout/nav-utils.ts +83 -0
- package/src/components/layout/page-feedback.ts +96 -0
- package/src/components/layout/search/analytics.ts +98 -0
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/types.ts +20 -0
- package/src/components/layout/search/typesense.ts +5 -1
- package/src/components/openapi/Operation.astro +161 -13
- package/src/components/openapi/RequestBody.astro +6 -4
- package/src/components/openapi/RequestPanel.astro +59 -7
- package/src/components/openapi/Responses.astro +6 -4
- package/src/components/openapi/async-snippets.ts +4 -4
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/security.ts +6 -3
- package/src/components/openapi/snippets.ts +869 -8
- package/src/components/props.ts +6 -0
- package/src/consent/client.ts +95 -0
- package/src/consent/clients.ts +19 -0
- package/src/consent/ethyca.ts +71 -0
- package/src/consent/head.ts +24 -0
- package/src/consent/index.ts +37 -0
- package/src/consent/init.ts +29 -0
- package/src/consent/native.ts +36 -0
- package/src/consent/osano.ts +59 -0
- package/src/consent/schema.ts +30 -0
- package/src/core/builtin-tags.ts +5 -0
- package/src/core/client-address.ts +19 -0
- package/src/core/config-input.ts +194 -20
- package/src/core/data.ts +44 -4
- package/src/core/diagnostics.ts +3 -2
- package/src/core/footer.ts +26 -0
- package/src/core/graph.ts +39 -36
- package/src/core/i18n-ui.ts +82 -2
- package/src/core/includes.ts +20 -3
- package/src/core/links.ts +16 -2
- package/src/core/localizable.ts +26 -0
- package/src/core/navigation.ts +43 -12
- package/src/core/page-modes.ts +56 -0
- package/src/core/project-graph.ts +111 -5
- package/src/core/redirect-patterns.ts +491 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +318 -64
- package/src/core/sources/normalize.ts +2 -1
- package/src/core/sources/read.ts +8 -3
- package/src/core/types.ts +1 -1
- package/src/core/ui-packs/ar.ts +43 -0
- package/src/core/ui-packs/bg.ts +45 -0
- package/src/core/ui-packs/bn.ts +43 -0
- package/src/core/ui-packs/ca.ts +46 -0
- package/src/core/ui-packs/cs.ts +44 -0
- package/src/core/ui-packs/da.ts +45 -0
- package/src/core/ui-packs/de.ts +46 -0
- package/src/core/ui-packs/el.ts +45 -0
- package/src/core/ui-packs/es.ts +46 -0
- package/src/core/ui-packs/fa.ts +45 -0
- package/src/core/ui-packs/fi.ts +45 -0
- package/src/core/ui-packs/fr.ts +46 -0
- package/src/core/ui-packs/he.ts +43 -0
- package/src/core/ui-packs/hi.ts +44 -0
- package/src/core/ui-packs/hr.ts +45 -0
- package/src/core/ui-packs/hu.ts +44 -0
- package/src/core/ui-packs/id.ts +45 -0
- package/src/core/ui-packs/it.ts +45 -0
- package/src/core/ui-packs/ja.ts +45 -0
- package/src/core/ui-packs/ko.ts +44 -0
- package/src/core/ui-packs/nl.ts +46 -0
- package/src/core/ui-packs/no.ts +44 -0
- package/src/core/ui-packs/pl.ts +45 -0
- package/src/core/ui-packs/pt-br.ts +46 -0
- package/src/core/ui-packs/pt.ts +45 -0
- package/src/core/ui-packs/ro.ts +45 -0
- package/src/core/ui-packs/ru.ts +45 -0
- package/src/core/ui-packs/sk.ts +44 -0
- package/src/core/ui-packs/sr.ts +45 -0
- package/src/core/ui-packs/sv.ts +44 -0
- package/src/core/ui-packs/th.ts +43 -0
- package/src/core/ui-packs/tr.ts +45 -0
- package/src/core/ui-packs/uk.ts +45 -0
- package/src/core/ui-packs/vi.ts +45 -0
- package/src/core/ui-packs/zh-tw.ts +43 -0
- package/src/core/ui-packs/zh.ts +43 -0
- package/src/core/variables.ts +103 -0
- package/src/deploy/artifacts.ts +77 -8
- package/src/deploy/cloudflare-negotiation.ts +35 -5
- package/src/deploy/headers.ts +2 -1
- package/src/deploy/node-headers.ts +63 -9
- package/src/deploy/platforms/cloudflare.ts +32 -0
- package/src/deploy/platforms/netlify.ts +33 -1
- package/src/deploy/platforms/vercel.ts +37 -2
- package/src/deploy/redirects.ts +91 -24
- package/src/deploy/vercel-negotiation.ts +36 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/features.ts +3 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +28 -5
- package/src/markdown/math.ts +4 -4
- package/src/markdown/variables.ts +56 -0
- package/src/markdown/views.ts +82 -0
- package/src/narration/build.ts +412 -0
- package/src/narration/player.ts +249 -0
- package/src/narration/provider.ts +29 -0
- package/src/narration/script.ts +592 -0
- package/src/og/card.ts +7 -6
- package/src/openapi/model.ts +57 -24
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +55 -2
- package/src/openapi/references.ts +21 -5
- package/src/openapi/render-mdx.ts +5 -1
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +1 -1
- package/src/ratelimit/cloudflare.ts +54 -0
- package/src/ratelimit/index.ts +30 -0
- package/src/ratelimit/memory.ts +45 -0
- package/src/ratelimit/runtime.ts +229 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +30 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +5 -2
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +51 -7
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +20 -4
- package/src/registry/registry.ts +7 -0
- package/src/search/documents.ts +26 -2
- package/src/search/orama-index.ts +28 -3
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/sync/algolia.ts +15 -4
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +5 -0
- package/src/seo/metatags.ts +67 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +56 -3
- package/src/theme/palette.ts +121 -45
- package/src/translate/prompts.ts +1 -0
- package/src/translate/validate.ts +8 -2
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-364znk6q.js +0 -75
- package/dist/cli/chunk-364znk6q.js.map +0 -11
- package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
- package/dist/cli/chunk-9t7a85s3.js.map +0 -10
- package/dist/cli/chunk-c8chx29p.js.map +0 -36
- package/dist/cli/chunk-pehfxfta.js.map +0 -10
- package/dist/cli/chunk-pv29h0wf.js.map +0 -190
- package/dist/cli/chunk-q58y5e6a.js.map +0 -10
- package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
- package/dist/cli/chunk-yfyb25rh.js.map +0 -14
- package/docs/content/sources.mdx +0 -334
- /package/dist/cli/{chunk-2eytanqx.js.map → chunk-1n228xqb.js.map} +0 -0
- /package/dist/cli/{chunk-35d4wj9f.js.map → chunk-2n4ps1b3.js.map} +0 -0
- /package/dist/cli/{chunk-e04dxsz1.js.map → chunk-4ejxbzee.js.map} +0 -0
- /package/dist/cli/{chunk-tzmab476.js.map → chunk-5ffywsmb.js.map} +0 -0
- /package/dist/cli/{chunk-2z928egk.js.map → chunk-5wj2qwn2.js.map} +0 -0
- /package/dist/cli/{chunk-b07cmahc.js.map → chunk-amrb6hgh.js.map} +0 -0
- /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-cmtcnh9f.js.map} +0 -0
- /package/dist/cli/{chunk-crgn1q09.js.map → chunk-e7vvk5ya.js.map} +0 -0
- /package/dist/cli/{chunk-tkacnehg.js.map → chunk-gp84za0h.js.map} +0 -0
- /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-p804f3pe.js.map} +0 -0
- /package/dist/cli/{chunk-8ktnccpt.js.map → chunk-ta27feev.js.map} +0 -0
- /package/dist/cli/{chunk-a58773jm.js.map → chunk-y4ykbark.js.map} +0 -0
- /package/dist/cli/{chunk-p3v96n38.js.map → chunk-y5h4r2y0.js.map} +0 -0
- /package/dist/cli/{chunk-acanzt5p.js.map → chunk-yj17vs39.js.map} +0 -0
package/src/core/i18n-ui.ts
CHANGED
|
@@ -15,6 +15,8 @@ const uiStringsObject = z.object({
|
|
|
15
15
|
.object({
|
|
16
16
|
addToCursor: z.string().default("Add to Cursor"),
|
|
17
17
|
addToVscode: z.string().default("Add to VS Code"),
|
|
18
|
+
// A code block's button that opens the assistant with the code attached.
|
|
19
|
+
askAboutCode: z.string().default("Ask about this code"),
|
|
18
20
|
connectMcp: z.string().default("Connect to MCP"),
|
|
19
21
|
copied: z.string().default("Copied!"),
|
|
20
22
|
copyClaudeCode: z.string().default("Copy Claude Code command"),
|
|
@@ -47,11 +49,32 @@ const uiStringsObject = z.object({
|
|
|
47
49
|
copy: z.string().default("Copy conversation"),
|
|
48
50
|
empty: z.string().default("Ask a question about the docs."),
|
|
49
51
|
error: z.string().default("Sorry, something went wrong."),
|
|
52
|
+
// The question sent about an attached code block when the reader
|
|
53
|
+
// writes none.
|
|
54
|
+
explainCode: z.string().default("Explain this code."),
|
|
50
55
|
label: z.string().default("Ask a question"),
|
|
56
|
+
// The header trigger's tooltip.
|
|
57
|
+
open: z.string().default("Open assistant"),
|
|
51
58
|
placeholder: z.string().default("Ask a question…"),
|
|
59
|
+
// The answer when the rate limit (`rateLimit`) turns a question away.
|
|
60
|
+
rateLimited: z
|
|
61
|
+
.string()
|
|
62
|
+
.default(
|
|
63
|
+
"You've asked a lot of questions. Try again in a few minutes."
|
|
64
|
+
),
|
|
65
|
+
// The attached code block's dismiss button.
|
|
66
|
+
removeCode: z.string().default("Remove code"),
|
|
52
67
|
send: z.string().default("Send"),
|
|
68
|
+
// The link to your support channel (`ai.assistant.support`), and the
|
|
69
|
+
// subject of an email it starts.
|
|
70
|
+
support: z.string().default("Contact support"),
|
|
71
|
+
supportSubject: z.string().default("Question from the docs"),
|
|
53
72
|
tip: z.string().default("Tip: You can open and close chat with"),
|
|
54
73
|
title: z.string().default("Assistant"),
|
|
74
|
+
// The answer when the bot check (`ai.assistant.captcha`) fails.
|
|
75
|
+
verifyFailed: z
|
|
76
|
+
.string()
|
|
77
|
+
.default("We couldn't check that you're human. Try again."),
|
|
55
78
|
you: z.string().default("You"),
|
|
56
79
|
})
|
|
57
80
|
.prefault({}),
|
|
@@ -70,6 +93,23 @@ const uiStringsObject = z.object({
|
|
|
70
93
|
title: z.string().default("Changelog"),
|
|
71
94
|
})
|
|
72
95
|
.prefault({}),
|
|
96
|
+
// The built-in cookie consent banner (`consent: native()`) and the footer
|
|
97
|
+
// link that reopens a consent manager's preferences.
|
|
98
|
+
consent: z
|
|
99
|
+
.object({
|
|
100
|
+
accept: z.string().default("Accept"),
|
|
101
|
+
decline: z.string().default("Decline"),
|
|
102
|
+
// The banner's accessible name.
|
|
103
|
+
label: z.string().default("Cookie consent"),
|
|
104
|
+
message: z
|
|
105
|
+
.string()
|
|
106
|
+
.default(
|
|
107
|
+
"We'd like to use cookies to understand how these docs are used."
|
|
108
|
+
),
|
|
109
|
+
policy: z.string().default("Privacy policy"),
|
|
110
|
+
settings: z.string().default("Cookie settings"),
|
|
111
|
+
})
|
|
112
|
+
.prefault({}),
|
|
73
113
|
content: z
|
|
74
114
|
.object({
|
|
75
115
|
// `<Component>`'s source tab.
|
|
@@ -89,7 +129,12 @@ const uiStringsObject = z.object({
|
|
|
89
129
|
prop: z.string().default("Prop"),
|
|
90
130
|
// `<Tabs dropdown>`: the accessible name of the tab picker.
|
|
91
131
|
selectTab: z.string().default("Select tab"),
|
|
92
|
-
// `<
|
|
132
|
+
// `<View>`: the accessible name of the page's view picker.
|
|
133
|
+
selectView: z.string().default("Select view"),
|
|
134
|
+
// An expanded `expandable` code block's toggle.
|
|
135
|
+
showLess: z.string().default("Show less"),
|
|
136
|
+
// `<Expandable>`'s toggle when it sets no `title`, and a collapsed
|
|
137
|
+
// `expandable` code block's.
|
|
93
138
|
showMore: z.string().default("Show more"),
|
|
94
139
|
stars: z.string().default("Stars"),
|
|
95
140
|
// An untitled tab's label; `{n}` is replaced with its position.
|
|
@@ -102,8 +147,11 @@ const uiStringsObject = z.object({
|
|
|
102
147
|
.prefault({}),
|
|
103
148
|
feedback: z
|
|
104
149
|
.object({
|
|
150
|
+
// The written comment box after the rating (`feedback.comments`).
|
|
151
|
+
comment: z.string().default("Tell us more (optional)"),
|
|
105
152
|
no: z.string().default("No"),
|
|
106
153
|
question: z.string().default("Was this page helpful?"),
|
|
154
|
+
send: z.string().default("Send"),
|
|
107
155
|
thanks: z.string().default("Thanks for your feedback!"),
|
|
108
156
|
yes: z.string().default("Yes"),
|
|
109
157
|
})
|
|
@@ -114,6 +162,36 @@ const uiStringsObject = z.object({
|
|
|
114
162
|
untranslated: z.string().default("Not translated"),
|
|
115
163
|
})
|
|
116
164
|
.prefault({}),
|
|
165
|
+
narration: z
|
|
166
|
+
.object({
|
|
167
|
+
// Spoken, not shown: the cues that introduce a callout of each type, a
|
|
168
|
+
// step (`{n}` is its number), a tab (`{title}` is its label), and a
|
|
169
|
+
// collapsible section. End each with a full stop so it reads as its own
|
|
170
|
+
// sentence.
|
|
171
|
+
cueDanger: z.string().default("Danger."),
|
|
172
|
+
cueInfo: z.string().default("Info."),
|
|
173
|
+
cueNote: z.string().default("Note."),
|
|
174
|
+
cueSection: z.string().default("Expandable section."),
|
|
175
|
+
cueStep: z.string().default("Step {n}."),
|
|
176
|
+
cueSuccess: z.string().default("Success."),
|
|
177
|
+
cueTab: z.string().default("{title} tab."),
|
|
178
|
+
cueTip: z.string().default("Tip."),
|
|
179
|
+
cueWarning: z.string().default("Warning."),
|
|
180
|
+
error: z.string().default("The narration couldn't load."),
|
|
181
|
+
// Resumes following the sentence being read after the reader scrolls away.
|
|
182
|
+
follow: z.string().default("Follow along"),
|
|
183
|
+
label: z.string().default("Listen to this page"),
|
|
184
|
+
// The estimated listening time; `{n}` is whole minutes.
|
|
185
|
+
minutes: z.string().default("{n} min"),
|
|
186
|
+
next: z.string().default("Next sentence"),
|
|
187
|
+
pause: z.string().default("Pause"),
|
|
188
|
+
play: z.string().default("Play"),
|
|
189
|
+
previous: z.string().default("Previous sentence"),
|
|
190
|
+
progress: z.string().default("Narration progress"),
|
|
191
|
+
speed: z.string().default("Playback speed"),
|
|
192
|
+
stop: z.string().default("Stop listening"),
|
|
193
|
+
})
|
|
194
|
+
.prefault({}),
|
|
117
195
|
nav: z
|
|
118
196
|
.object({
|
|
119
197
|
back: z.string().default("Back"),
|
|
@@ -128,7 +206,7 @@ const uiStringsObject = z.object({
|
|
|
128
206
|
primary: z.string().default("Primary"),
|
|
129
207
|
sections: z.string().default("Sections"),
|
|
130
208
|
toggleNavigation: z.string().default("Toggle navigation"),
|
|
131
|
-
toggleTheme: z.string().default("Toggle
|
|
209
|
+
toggleTheme: z.string().default("Toggle theme"),
|
|
132
210
|
})
|
|
133
211
|
.prefault({}),
|
|
134
212
|
notFound: z
|
|
@@ -154,6 +232,8 @@ const uiStringsObject = z.object({
|
|
|
154
232
|
next: z.string().default("Next"),
|
|
155
233
|
pagination: z.string().default("Pagination"),
|
|
156
234
|
previous: z.string().default("Previous"),
|
|
235
|
+
// The heading over a page's `related` links.
|
|
236
|
+
related: z.string().default("Related pages"),
|
|
157
237
|
skipToContent: z.string().default("Skip to content"),
|
|
158
238
|
})
|
|
159
239
|
.prefault({}),
|
package/src/core/includes.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { FenceState } from "./code-fences.ts";
|
|
|
7
7
|
import matter from "./frontmatter.ts";
|
|
8
8
|
import { INLINE_CODE, MD_IMAGE, targetOffsetIn } from "./sources/normalize.ts";
|
|
9
9
|
import type { Diagnostic } from "./types.ts";
|
|
10
|
+
import { substituteVariables } from "./variables.ts";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Content includes: `<include>./relative.mdx</include>` on a line of its own
|
|
@@ -98,6 +99,12 @@ export interface IncludeAttributes {
|
|
|
98
99
|
lang?: string;
|
|
99
100
|
/** Fence meta string in code-block mode (e.g. `title="lib.ts"`). */
|
|
100
101
|
meta?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Every other attribute with a value: the snippet's own variables.
|
|
104
|
+
* `<include plan="Pro">` makes `{{plan}}` in the included file read `Pro`,
|
|
105
|
+
* ahead of any site-wide variable of the same name.
|
|
106
|
+
*/
|
|
107
|
+
props?: Record<string, string>;
|
|
101
108
|
}
|
|
102
109
|
|
|
103
110
|
/** A parsed include statement. */
|
|
@@ -108,8 +115,8 @@ export interface IncludeStatement {
|
|
|
108
115
|
|
|
109
116
|
/**
|
|
110
117
|
* Parse one trimmed line as an include statement, or `null` when it isn't
|
|
111
|
-
* one.
|
|
112
|
-
*
|
|
118
|
+
* one. `lang` and `meta` shape a code include; every other attribute with a
|
|
119
|
+
* value becomes a prop, a variable scoped to the included file.
|
|
113
120
|
*/
|
|
114
121
|
export const parseIncludeStatement = (
|
|
115
122
|
line: string
|
|
@@ -128,6 +135,9 @@ export const parseIncludeStatement = (
|
|
|
128
135
|
if (name === "meta" && value) {
|
|
129
136
|
attributes.meta = value;
|
|
130
137
|
}
|
|
138
|
+
if (name && name !== "lang" && name !== "meta" && value !== undefined) {
|
|
139
|
+
attributes.props = { ...attributes.props, [name]: value };
|
|
140
|
+
}
|
|
131
141
|
}
|
|
132
142
|
return { attributes, target: match.groups.target ?? "" };
|
|
133
143
|
};
|
|
@@ -519,8 +529,15 @@ const expandStatement = async (
|
|
|
519
529
|
lines.shift();
|
|
520
530
|
origins.shift();
|
|
521
531
|
}
|
|
532
|
+
// Props replace their `{{name}}` references line by line, so every line
|
|
533
|
+
// keeps its origin; they reach the file's own nested includes too.
|
|
534
|
+
const { props } = statement.attributes;
|
|
522
535
|
return {
|
|
523
|
-
lines: rebaseImages(
|
|
536
|
+
lines: rebaseImages(
|
|
537
|
+
props ? lines.map((text) => substituteVariables(text, props)) : lines,
|
|
538
|
+
dirname(path),
|
|
539
|
+
dirname(filePath)
|
|
540
|
+
),
|
|
524
541
|
origins,
|
|
525
542
|
};
|
|
526
543
|
};
|
package/src/core/links.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import type { LocaleRouting } from "./i18n.ts";
|
|
11
11
|
import { localizeLinkPath } from "./locale-links.ts";
|
|
12
12
|
import { gradeExternal, probeAll } from "./probe.ts";
|
|
13
|
+
import { isPatternPath, pathsUnderPattern } from "./redirect-patterns.ts";
|
|
13
14
|
import type {
|
|
14
15
|
ContentGraph,
|
|
15
16
|
Diagnostic,
|
|
@@ -87,6 +88,8 @@ interface LinkContext {
|
|
|
87
88
|
publicDir: string | null;
|
|
88
89
|
/** Normalized `redirect.from` paths — valid targets that resolve at runtime. */
|
|
89
90
|
redirects: Set<string>;
|
|
91
|
+
/** Pattern `redirect.from`s (`/beta/:slug*`), based like `redirects`. */
|
|
92
|
+
redirectPatterns: string[];
|
|
90
93
|
routes: Set<string>;
|
|
91
94
|
}
|
|
92
95
|
|
|
@@ -322,10 +325,16 @@ const checkPathLink = (
|
|
|
322
325
|
if (ctx.extraRoutes.has(route)) {
|
|
323
326
|
return null;
|
|
324
327
|
}
|
|
325
|
-
// A configured `redirect.from
|
|
328
|
+
// A configured `redirect.from`, or a path a pattern `from` covers, resolves
|
|
329
|
+
// at runtime, so it's a valid target.
|
|
326
330
|
// Its destination (and any anchor there) is validated on its own page, so we
|
|
327
331
|
// don't follow the redirect to check the fragment here.
|
|
328
|
-
if (
|
|
332
|
+
if (
|
|
333
|
+
ctx.redirects.has(route) ||
|
|
334
|
+
ctx.redirectPatterns.some(
|
|
335
|
+
(from) => pathsUnderPattern(from, [route]).length > 0
|
|
336
|
+
)
|
|
337
|
+
) {
|
|
329
338
|
return null;
|
|
330
339
|
}
|
|
331
340
|
|
|
@@ -585,6 +594,11 @@ export const validateLinks = async (
|
|
|
585
594
|
fileRoutes: buildFileRouteIndex(graph.pages, options.i18n ?? null),
|
|
586
595
|
i18n: options.i18n ?? null,
|
|
587
596
|
publicDir: options.publicDir,
|
|
597
|
+
redirectPatterns: (options.redirects ?? []).flatMap((redirect) =>
|
|
598
|
+
isPatternPath(redirect.from)
|
|
599
|
+
? [withBasePath(basePath, redirect.from)]
|
|
600
|
+
: []
|
|
601
|
+
),
|
|
588
602
|
redirects: new Set(
|
|
589
603
|
(options.redirects ?? []).map((redirect) =>
|
|
590
604
|
toRoute(withBasePath(basePath, redirect.from))
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { LocalizableLabel } from "./schema.ts";
|
|
2
|
+
|
|
3
|
+
/** A label is either one string for every locale or a per-locale map. */
|
|
4
|
+
const isSingleLabel = (label: LocalizableLabel): label is string =>
|
|
5
|
+
typeof label === "string";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a possibly-per-locale label to the string a locale renders: the
|
|
9
|
+
* active locale's entry, else the default locale's, else the map's first
|
|
10
|
+
* entry (which is also what a single-locale site gets).
|
|
11
|
+
*/
|
|
12
|
+
export const resolveLocalizable = (
|
|
13
|
+
label: LocalizableLabel,
|
|
14
|
+
locale?: string,
|
|
15
|
+
defaultLocale?: string
|
|
16
|
+
): string => {
|
|
17
|
+
if (isSingleLabel(label)) {
|
|
18
|
+
return label;
|
|
19
|
+
}
|
|
20
|
+
return (
|
|
21
|
+
(locale === undefined ? undefined : label[locale]) ??
|
|
22
|
+
(defaultLocale === undefined ? undefined : label[defaultLocale]) ??
|
|
23
|
+
Object.values(label)[0] ??
|
|
24
|
+
""
|
|
25
|
+
);
|
|
26
|
+
};
|
package/src/core/navigation.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { extname } from "pathe";
|
|
|
3
3
|
import { stripBasePath, withBasePath } from "./base-path.ts";
|
|
4
4
|
import { orderingPrefix, stripOrderingPrefix } from "./ordering-prefix.ts";
|
|
5
5
|
import type {
|
|
6
|
+
DirectoryMode,
|
|
6
7
|
FolderMeta,
|
|
7
8
|
SidebarDisplay,
|
|
8
9
|
SidebarItemConfig,
|
|
@@ -202,6 +203,7 @@ interface MutableGroup {
|
|
|
202
203
|
label: string;
|
|
203
204
|
icon?: string;
|
|
204
205
|
collapsed?: boolean;
|
|
206
|
+
directory?: DirectoryMode;
|
|
205
207
|
display?: SidebarDisplay;
|
|
206
208
|
order: number;
|
|
207
209
|
/** Whether `order` is the node's position in its folder meta `pages` list. */
|
|
@@ -305,9 +307,19 @@ interface FallbackFolderMeta {
|
|
|
305
307
|
meta: (path: string) => FolderMeta | undefined;
|
|
306
308
|
}
|
|
307
309
|
|
|
310
|
+
/** A folder meta's own fields onto its group, over what the folder implied. */
|
|
311
|
+
const applyMetaFields = (group: MutableGroup, meta: FolderMeta): void => {
|
|
312
|
+
group.label = meta.title ?? group.label;
|
|
313
|
+
group.icon = meta.icon ?? group.icon;
|
|
314
|
+
group.order = meta.order ?? group.order;
|
|
315
|
+
group.collapsed = meta.collapsed ?? group.collapsed;
|
|
316
|
+
group.directory = meta.directory ?? group.directory;
|
|
317
|
+
};
|
|
318
|
+
|
|
308
319
|
/**
|
|
309
|
-
* Apply folder meta (title/order/icon/collapsed/display and
|
|
310
|
-
* order), plus the index-frontmatter display sugar collected
|
|
320
|
+
* Apply folder meta (title/order/icon/collapsed/display/directory and
|
|
321
|
+
* explicit page order), plus the index-frontmatter display sugar collected
|
|
322
|
+
* per folder path.
|
|
311
323
|
*/
|
|
312
324
|
const applyFolderMeta = (
|
|
313
325
|
group: MutableGroup,
|
|
@@ -346,10 +358,7 @@ const applyFolderMeta = (
|
|
|
346
358
|
(mirrored ? fallback.indexDisplay.get(group.path) : undefined) ??
|
|
347
359
|
meta?.display;
|
|
348
360
|
if (meta) {
|
|
349
|
-
group
|
|
350
|
-
group.icon = meta.icon ?? group.icon;
|
|
351
|
-
group.order = meta.order ?? group.order;
|
|
352
|
-
group.collapsed = meta.collapsed ?? group.collapsed;
|
|
361
|
+
applyMetaFields(group, meta);
|
|
353
362
|
}
|
|
354
363
|
|
|
355
364
|
for (const child of group.children) {
|
|
@@ -630,7 +639,15 @@ const hoistTabSections = (
|
|
|
630
639
|
}
|
|
631
640
|
};
|
|
632
641
|
|
|
633
|
-
|
|
642
|
+
/**
|
|
643
|
+
* A group's directory mode: its own, else the nearest one set above it (see
|
|
644
|
+
* `directory` in `schema.ts`).
|
|
645
|
+
*/
|
|
646
|
+
const toNavNode = (
|
|
647
|
+
node: MutableNode,
|
|
648
|
+
display: SidebarDisplay,
|
|
649
|
+
inheritedDirectory?: DirectoryMode
|
|
650
|
+
): NavNode => {
|
|
634
651
|
if (node.kind === "page") {
|
|
635
652
|
return {
|
|
636
653
|
badge: node.badge,
|
|
@@ -643,9 +660,13 @@ const toNavNode = (node: MutableNode, display: SidebarDisplay): NavNode => {
|
|
|
643
660
|
route: node.route,
|
|
644
661
|
};
|
|
645
662
|
}
|
|
663
|
+
const directory = node.directory ?? inheritedDirectory;
|
|
646
664
|
return {
|
|
647
|
-
children: node.children.map((child) =>
|
|
665
|
+
children: node.children.map((child) =>
|
|
666
|
+
toNavNode(child, display, directory)
|
|
667
|
+
),
|
|
648
668
|
collapsed: node.collapsed,
|
|
669
|
+
directory,
|
|
649
670
|
display: node.display ?? display,
|
|
650
671
|
icon: node.icon,
|
|
651
672
|
kind: "group",
|
|
@@ -805,7 +826,9 @@ const buildFileSystemSidebar = (
|
|
|
805
826
|
sortNodes(root.children, diagnostics);
|
|
806
827
|
hoistPages(root.children, display, true);
|
|
807
828
|
hoistTabSections(root.children, tabPaths, display);
|
|
808
|
-
return root.children.map((child) =>
|
|
829
|
+
return root.children.map((child) =>
|
|
830
|
+
toNavNode(child, display, root.directory)
|
|
831
|
+
);
|
|
809
832
|
};
|
|
810
833
|
|
|
811
834
|
/**
|
|
@@ -932,16 +955,24 @@ const buildConfigSidebar = (
|
|
|
932
955
|
items: SidebarItemConfig[],
|
|
933
956
|
byRoute: Map<string, PageRecord>,
|
|
934
957
|
display: SidebarDisplay,
|
|
935
|
-
basePath: string
|
|
958
|
+
basePath: string,
|
|
959
|
+
inheritedDirectory?: DirectoryMode
|
|
936
960
|
): NavNode[] => {
|
|
937
961
|
const nodes: NavNode[] = [];
|
|
938
962
|
for (const item of items) {
|
|
939
963
|
if (!isPageRef(item) && item.items) {
|
|
964
|
+
const directory = item.directory ?? inheritedDirectory;
|
|
940
965
|
nodes.push({
|
|
941
966
|
badge: item.badge,
|
|
942
|
-
children: buildConfigSidebar(
|
|
967
|
+
children: buildConfigSidebar(
|
|
968
|
+
item.items,
|
|
969
|
+
byRoute,
|
|
970
|
+
display,
|
|
971
|
+
basePath,
|
|
972
|
+
directory
|
|
973
|
+
),
|
|
943
974
|
collapsed: item.collapsed,
|
|
944
|
-
directory
|
|
975
|
+
directory,
|
|
945
976
|
display: item.display ?? display,
|
|
946
977
|
icon: item.icon,
|
|
947
978
|
kind: "group",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page layout modes (`mode` frontmatter), Mintlify's names for what a page
|
|
3
|
+
* shows around its content:
|
|
4
|
+
*
|
|
5
|
+
* - `default`: the sidebar, the page's title and table of contents, and the
|
|
6
|
+
* page-end links, around the prose column.
|
|
7
|
+
* - `wide`: no table of contents; the content takes its width.
|
|
8
|
+
* - `center`: no sidebar or table of contents; a wider column, centered.
|
|
9
|
+
* For changelogs and other pages read top to bottom.
|
|
10
|
+
* - `custom`: only the header. No sidebar, title, breadcrumbs, table of
|
|
11
|
+
* contents, page-end links, or site footer, and the content spans the
|
|
12
|
+
* page, for a landing page written in MDX.
|
|
13
|
+
* - `frame`: `custom`, keeping the sidebar.
|
|
14
|
+
*
|
|
15
|
+
* Mintlify's `assistant` mode, a full-page chat, has no equivalent.
|
|
16
|
+
*/
|
|
17
|
+
export const PAGE_MODES = [
|
|
18
|
+
"default",
|
|
19
|
+
"wide",
|
|
20
|
+
"center",
|
|
21
|
+
"custom",
|
|
22
|
+
"frame",
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
export type PageMode = (typeof PAGE_MODES)[number];
|
|
26
|
+
|
|
27
|
+
/** What a page shows around its content, and how wide the content runs. */
|
|
28
|
+
export interface PageModeLayout {
|
|
29
|
+
/** The page's own chrome: title, description, breadcrumbs, page-end links, and the site footer. */
|
|
30
|
+
chrome: boolean;
|
|
31
|
+
sidebar: boolean;
|
|
32
|
+
toc: boolean;
|
|
33
|
+
/** `content` is the prose measure, `center` a wider centered column, `full` the whole column. */
|
|
34
|
+
width: "content" | "center" | "full";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The layout a mode gives a page. */
|
|
38
|
+
export const pageModeLayout = (mode: PageMode = "default"): PageModeLayout => {
|
|
39
|
+
switch (mode) {
|
|
40
|
+
case "wide": {
|
|
41
|
+
return { chrome: true, sidebar: true, toc: false, width: "full" };
|
|
42
|
+
}
|
|
43
|
+
case "center": {
|
|
44
|
+
return { chrome: true, sidebar: false, toc: false, width: "center" };
|
|
45
|
+
}
|
|
46
|
+
case "custom": {
|
|
47
|
+
return { chrome: false, sidebar: false, toc: false, width: "full" };
|
|
48
|
+
}
|
|
49
|
+
case "frame": {
|
|
50
|
+
return { chrome: false, sidebar: true, toc: false, width: "full" };
|
|
51
|
+
}
|
|
52
|
+
default: {
|
|
53
|
+
return { chrome: true, sidebar: true, toc: true, width: "content" };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isAbsolute, relative } from "pathe";
|
|
2
2
|
|
|
3
|
+
import { withBasePath } from "./base-path.ts";
|
|
3
4
|
import { CHANGELOG_INDEX_ROUTE, hasChangelogIndex } from "./changelog-index.ts";
|
|
4
5
|
import { loadConfig } from "./config.ts";
|
|
5
6
|
import { customStaticRoutes, discoverPages } from "./custom-pages.ts";
|
|
@@ -18,10 +19,15 @@ import { buildManifest } from "./manifest.ts";
|
|
|
18
19
|
import { discoverFolderMeta } from "./meta.ts";
|
|
19
20
|
import type { FolderMetaSource } from "./meta.ts";
|
|
20
21
|
import { resolveProjectContext } from "./project.ts";
|
|
22
|
+
import { pathsUnderPattern } from "./redirect-patterns.ts";
|
|
21
23
|
import type { ResolvedConfig } from "./schema.ts";
|
|
22
24
|
import { normalizeEntry, strippedLineOffset } from "./sources/normalize.ts";
|
|
23
25
|
import { resolveDocsCollection, resolveSources } from "./sources/resolve.ts";
|
|
24
|
-
import type {
|
|
26
|
+
import type {
|
|
27
|
+
ContentSource,
|
|
28
|
+
SourceEntry,
|
|
29
|
+
SourceLoadResult,
|
|
30
|
+
} from "./sources/types.ts";
|
|
25
31
|
import type {
|
|
26
32
|
BlumeManifest,
|
|
27
33
|
ContentGraph,
|
|
@@ -30,6 +36,12 @@ import type {
|
|
|
30
36
|
PageRecord,
|
|
31
37
|
ProjectContext,
|
|
32
38
|
} from "./types.ts";
|
|
39
|
+
import {
|
|
40
|
+
hasVariables,
|
|
41
|
+
substituteVariables,
|
|
42
|
+
undefinedVariables,
|
|
43
|
+
} from "./variables.ts";
|
|
44
|
+
import type { ContentVariables } from "./variables.ts";
|
|
33
45
|
import { versionsDiagnostics } from "./versions.ts";
|
|
34
46
|
|
|
35
47
|
/** Build mode: drafts are kept in `dev` and dropped in `build`. */
|
|
@@ -246,6 +258,85 @@ const isBannerShorthand = (
|
|
|
246
258
|
banner: NonNullable<ResolvedConfig["banner"]>
|
|
247
259
|
): banner is string => typeof banner === "string";
|
|
248
260
|
|
|
261
|
+
/**
|
|
262
|
+
* Report an entry's undefined content variables at their source lines, then
|
|
263
|
+
* replace the defined ones in the text the scan extracts from: the expanded
|
|
264
|
+
* text when includes were spliced (its `origins` map lines back to the file
|
|
265
|
+
* each came from), else the body.
|
|
266
|
+
*/
|
|
267
|
+
const substituteEntryVariables = (
|
|
268
|
+
entry: SourceEntry,
|
|
269
|
+
variables: ContentVariables
|
|
270
|
+
): Diagnostic[] => {
|
|
271
|
+
const { expanded } = entry;
|
|
272
|
+
const text = expanded?.text ?? entry.body.text;
|
|
273
|
+
const offset = expanded ? 0 : strippedLineOffset(entry.raw, entry.body.text);
|
|
274
|
+
const diagnostics = undefinedVariables(text, variables).map(
|
|
275
|
+
({ line, name }): Diagnostic => {
|
|
276
|
+
const origin = expanded?.origins[line - 1];
|
|
277
|
+
return {
|
|
278
|
+
code: "BLUME_UNDEFINED_VARIABLE",
|
|
279
|
+
file: origin?.file ?? entry.sourcePath,
|
|
280
|
+
line: origin?.line ?? line + offset,
|
|
281
|
+
message: `{{${name}}} isn't a defined variable, so it would show as written.`,
|
|
282
|
+
severity: "error",
|
|
283
|
+
suggestion: `Define "${name}" under variables in blume.config.ts, or put it in inline code to show it as written.`,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
if (expanded) {
|
|
288
|
+
expanded.text = substituteVariables(expanded.text, variables);
|
|
289
|
+
} else {
|
|
290
|
+
entry.body.text = substituteVariables(entry.body.text, variables);
|
|
291
|
+
}
|
|
292
|
+
return diagnostics;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
/** {@link substituteEntryVariables} over every loaded entry, when any are defined. */
|
|
296
|
+
const substituteLoadedVariables = (
|
|
297
|
+
loaded: readonly SourceLoadResult[],
|
|
298
|
+
variables: ContentVariables
|
|
299
|
+
): Diagnostic[] =>
|
|
300
|
+
hasVariables(variables)
|
|
301
|
+
? loaded.flatMap(({ entries }) =>
|
|
302
|
+
entries.flatMap((entry) => substituteEntryVariables(entry, variables))
|
|
303
|
+
)
|
|
304
|
+
: [];
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* A pattern redirect that also matches a page. Hosts disagree on which
|
|
308
|
+
* answers (Vercel and Cloudflare apply the rule ahead of the page, Netlify
|
|
309
|
+
* and the Node server serve the page), so the pattern is rejected rather than
|
|
310
|
+
* let the answer depend on the host. `pages` are the served page paths, which
|
|
311
|
+
* carry `basePath`, as the based `from` does.
|
|
312
|
+
*/
|
|
313
|
+
const redirectPageDiagnostics = (
|
|
314
|
+
config: ResolvedConfig,
|
|
315
|
+
pages: readonly string[],
|
|
316
|
+
configFile: string | null
|
|
317
|
+
): Diagnostic[] =>
|
|
318
|
+
config.redirects.flatMap((redirect) => {
|
|
319
|
+
const matched = pathsUnderPattern(
|
|
320
|
+
withBasePath(config.basePath, redirect.from),
|
|
321
|
+
pages
|
|
322
|
+
);
|
|
323
|
+
const [first] = matched;
|
|
324
|
+
if (first === undefined) {
|
|
325
|
+
return [];
|
|
326
|
+
}
|
|
327
|
+
const more = matched.length > 1 ? ` and ${matched.length - 1} more` : "";
|
|
328
|
+
return [
|
|
329
|
+
{
|
|
330
|
+
code: "BLUME_REDIRECT_MATCHES_PAGE",
|
|
331
|
+
file: configFile ?? undefined,
|
|
332
|
+
message: `The redirect from ${redirect.from} also matches the page ${first}${more}, which some hosts would redirect and others would serve.`,
|
|
333
|
+
severity: "error",
|
|
334
|
+
suggestion:
|
|
335
|
+
"Narrow the pattern to the paths that moved, or move the pages out from under it.",
|
|
336
|
+
} satisfies Diagnostic,
|
|
337
|
+
];
|
|
338
|
+
});
|
|
339
|
+
|
|
249
340
|
/** The configured banner link target, when the banner has a link. */
|
|
250
341
|
const bannerLinkHref = (
|
|
251
342
|
banner: ResolvedConfig["banner"]
|
|
@@ -352,6 +443,14 @@ export const scanProject = async (
|
|
|
352
443
|
})
|
|
353
444
|
);
|
|
354
445
|
|
|
446
|
+
// Content variables: an undefined name in prose is an error at its source
|
|
447
|
+
// line, and every defined one is replaced in the text headings, links, and
|
|
448
|
+
// components are extracted from, so they match the rendered page.
|
|
449
|
+
const variableDiagnostics = substituteLoadedVariables(
|
|
450
|
+
loaded,
|
|
451
|
+
config.variables
|
|
452
|
+
);
|
|
453
|
+
|
|
355
454
|
// Folder meta contributed by the sources themselves (the OpenAPI source
|
|
356
455
|
// labels each tag directory with the spec's own tag name). It applies to
|
|
357
456
|
// every locale, so it merges into the shared map — beneath user-authored
|
|
@@ -424,14 +523,15 @@ export const scanProject = async (
|
|
|
424
523
|
const customPages = context.pagesRoot
|
|
425
524
|
? await discoverPages(context.pagesRoot)
|
|
426
525
|
: [];
|
|
526
|
+
const extraRoutes = new Set([
|
|
527
|
+
...customStaticRoutes(customPages),
|
|
528
|
+
...(hasChangelogIndex(pages, config) ? [CHANGELOG_INDEX_ROUTE] : []),
|
|
529
|
+
]);
|
|
427
530
|
const graph = buildContentGraph(pages, {
|
|
428
531
|
bannerHref: bannerLinkHref(config.banner),
|
|
429
532
|
basePath: config.basePath,
|
|
430
533
|
brandHref: logoHref(config.logo),
|
|
431
|
-
extraRoutes
|
|
432
|
-
...customStaticRoutes(customPages),
|
|
433
|
-
...(hasChangelogIndex(pages, config) ? [CHANGELOG_INDEX_ROUTE] : []),
|
|
434
|
-
]),
|
|
534
|
+
extraRoutes,
|
|
435
535
|
folderMeta: folderMeta.meta,
|
|
436
536
|
i18n: config.i18n,
|
|
437
537
|
navigation: config.navigation,
|
|
@@ -453,6 +553,7 @@ export const scanProject = async (
|
|
|
453
553
|
diagnostics: [
|
|
454
554
|
...contentDiagnostics,
|
|
455
555
|
...includeDiagnostics,
|
|
556
|
+
...variableDiagnostics,
|
|
456
557
|
...folderMeta.diagnostics,
|
|
457
558
|
...entryIdDiagnostics(
|
|
458
559
|
pages,
|
|
@@ -462,6 +563,11 @@ export const scanProject = async (
|
|
|
462
563
|
...i18nWarnings,
|
|
463
564
|
...versionWarnings,
|
|
464
565
|
...lastModifiedWarnings,
|
|
566
|
+
...redirectPageDiagnostics(
|
|
567
|
+
config,
|
|
568
|
+
[...manifest.routes.map((route) => route.path), ...extraRoutes],
|
|
569
|
+
context.configFile
|
|
570
|
+
),
|
|
465
571
|
],
|
|
466
572
|
droppedPages,
|
|
467
573
|
graph,
|