blume 2.0.3 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +142 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
- package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
- package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
- package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
- package/dist/cli/chunk-313vnn40.js.map +10 -0
- package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
- package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
- package/dist/cli/chunk-3x6x3pph.js.map +10 -0
- package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
- package/dist/cli/chunk-42t4jxdx.js.map +12 -0
- package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
- package/dist/cli/chunk-54ztw1nj.js.map +10 -0
- package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
- package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
- package/dist/cli/chunk-66w9j7p6.js +322 -0
- package/dist/cli/chunk-66w9j7p6.js.map +14 -0
- package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
- package/dist/cli/chunk-7ppf1rva.js.map +10 -0
- package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
- package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
- package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
- package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
- package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
- package/dist/cli/chunk-cfyg47zg.js.map +10 -0
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
- package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
- package/dist/cli/chunk-e6atmn4h.js.map +36 -0
- package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
- package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
- package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
- package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
- package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
- package/dist/cli/chunk-ehweg4fr.js.map +218 -0
- package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
- package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
- package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
- package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
- package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
- package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
- package/dist/cli/chunk-gb420vvz.js.map +17 -0
- package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
- package/dist/cli/chunk-hebn0tpx.js.map +14 -0
- package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
- package/dist/cli/chunk-htrwgabr.js.map +15 -0
- package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
- package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
- package/dist/cli/chunk-j134vrp2.js +65 -0
- package/dist/cli/chunk-j134vrp2.js.map +10 -0
- package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
- package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
- package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
- package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
- package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
- package/dist/cli/chunk-ncj7w596.js.map +35 -0
- package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
- package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
- package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
- package/dist/cli/chunk-nrns10mj.js.map +10 -0
- package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
- package/dist/cli/chunk-t2m5j4pr.js +104 -0
- package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
- package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
- package/dist/cli/chunk-tphac74f.js +126 -0
- package/dist/cli/chunk-tphac74f.js.map +11 -0
- package/dist/cli/chunk-w1r4vase.js +18 -0
- package/dist/cli/chunk-w1r4vase.js.map +10 -0
- package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
- package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
- package/dist/cli/index.js +31 -20
- package/dist/cli/index.js.map +5 -5
- package/dist/types/ai/agent-surface.d.ts +8 -7
- package/dist/types/ai/ai-catalog.d.ts +7 -0
- package/dist/types/ai/ask-context.d.ts +26 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +16 -0
- package/dist/types/astro/integration.d.ts +9 -0
- package/dist/types/astro/markdown-negotiation.d.ts +3 -0
- package/dist/types/astro/pages.d.ts +10 -0
- package/dist/types/captcha/hcaptcha.d.ts +27 -0
- package/dist/types/captcha/index.d.ts +28 -0
- package/dist/types/captcha/schema.d.ts +29 -0
- package/dist/types/captcha/turnstile.d.ts +28 -0
- package/dist/types/cli/init/scaffold.d.ts +1 -1
- package/dist/types/components/content/api-field.d.ts +62 -0
- package/dist/types/components/content/api-page.d.ts +100 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/code-samples.d.ts +29 -0
- package/dist/types/components/openapi/helpers.d.ts +158 -0
- package/dist/types/components/openapi/security.d.ts +95 -0
- package/dist/types/components/openapi/snippets.d.ts +60 -0
- package/dist/types/consent/ethyca.d.ts +48 -0
- package/dist/types/consent/index.d.ts +37 -0
- package/dist/types/consent/native.d.ts +28 -0
- package/dist/types/consent/osano.d.ts +42 -0
- package/dist/types/consent/schema.d.ts +110 -0
- package/dist/types/core/changelog-index.d.ts +8 -0
- package/dist/types/core/config-input.d.ts +217 -23
- package/dist/types/core/data.d.ts +53 -4
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/i18n-ui.d.ts +88 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/links.d.ts +8 -0
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/probe.d.ts +2 -0
- package/dist/types/core/project-graph.d.ts +6 -0
- package/dist/types/core/redirect-patterns.d.ts +152 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +670 -56
- package/dist/types/core/sources/cache.d.ts +3 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
- package/dist/types/core/sources/contentful.d.ts +17 -1
- package/dist/types/core/sources/lexical.d.ts +5 -0
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/sources/remote.d.ts +37 -10
- package/dist/types/core/sources/sanity.d.ts +1 -1
- package/dist/types/core/types.d.ts +18 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/adapter-output.d.ts +2 -1
- package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
- package/dist/types/deploy/adapters/node.d.ts +58 -23
- package/dist/types/deploy/adapters/registry.d.ts +10 -0
- package/dist/types/deploy/adapters/types.d.ts +3 -2
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/node.d.ts +3 -1
- package/dist/types/deploy/platforms/types.d.ts +18 -7
- package/dist/types/deploy/platforms/vercel.d.ts +26 -1
- package/dist/types/deploy/redirects.d.ts +55 -11
- package/dist/types/deploy/sitemap.d.ts +2 -1
- package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/features.d.ts +3 -2
- package/dist/types/narration/build.d.ts +70 -0
- package/dist/types/narration/provider.d.ts +26 -0
- package/dist/types/narration/script.d.ts +154 -0
- package/dist/types/openapi/checks.d.ts +27 -0
- package/dist/types/openapi/graphql.d.ts +6 -0
- package/dist/types/openapi/model.d.ts +27 -10
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +16 -0
- package/dist/types/openapi/references.d.ts +30 -4
- package/dist/types/ratelimit/cloudflare.d.ts +39 -0
- package/dist/types/ratelimit/index.d.ts +27 -0
- package/dist/types/ratelimit/memory.d.ts +36 -0
- package/dist/types/ratelimit/schema.d.ts +119 -0
- package/dist/types/ratelimit/upstash.d.ts +46 -0
- package/dist/types/ratelimit/wrangler.d.ts +23 -0
- package/dist/types/reference/asyncapi.d.ts +10 -10
- package/dist/types/reference/graphql.d.ts +89 -11
- package/dist/types/reference/index.d.ts +1 -1
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +82 -6
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +144 -36
- package/dist/types/search/adapters/registry.d.ts +3 -0
- package/dist/types/search/adapters/typesense.d.ts +14 -4
- package/dist/types/search/build.d.ts +3 -1
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +13 -9
- package/dist/types/search/sync/algolia.d.ts +5 -2
- package/dist/types/search/sync/index.d.ts +3 -1
- package/dist/types/search/sync/typesense.d.ts +11 -7
- package/dist/types/seo/metatags.d.ts +20 -0
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +54 -0
- package/dist/types/sources/shared.d.ts +3 -0
- package/dist/types/sources/strapi.d.ts +2 -0
- package/docs/01-quickstart.mdx +4 -2
- package/docs/02-deployment.mdx +71 -17
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/advanced/changelog.mdx +13 -2
- package/docs/advanced/skills.mdx +15 -1
- package/docs/cli/audit.mdx +51 -8
- package/docs/cli/doctor.mdx +5 -1
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +1 -0
- package/docs/cli/translate.mdx +1 -0
- package/docs/cli/validate.mdx +4 -3
- package/docs/configuration/analytics.mdx +3 -1
- package/docs/configuration/assistant.mdx +194 -38
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +8 -6
- package/docs/configuration/export.mdx +5 -3
- package/docs/configuration/index.mdx +64 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +90 -0
- package/docs/configuration/search.mdx +63 -12
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +108 -2
- package/docs/content/frontmatter.mdx +80 -2
- package/docs/content/i18n.mdx +39 -4
- package/docs/content/includes.mdx +16 -0
- package/docs/content/meta.mdx +1 -0
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +32 -10
- package/docs/content/sources/contentful.mdx +35 -0
- package/docs/content/sources/custom.mdx +43 -0
- package/docs/content/sources/github-releases.mdx +39 -0
- package/docs/content/sources/index.mdx +91 -0
- package/docs/content/sources/meta.ts +16 -0
- package/docs/content/sources/notion.mdx +32 -0
- package/docs/content/sources/obsidian.mdx +37 -0
- package/docs/content/sources/payload.mdx +31 -0
- package/docs/content/sources/remote-mdx.mdx +44 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +32 -0
- package/docs/content/syntax.mdx +69 -4
- package/docs/content/variables.mdx +41 -0
- package/docs/discoverability/agent-discovery.mdx +29 -2
- package/docs/discoverability/index.mdx +2 -2
- package/docs/discoverability/json-api.mdx +2 -0
- package/docs/discoverability/llms-txt.mdx +2 -2
- package/docs/discoverability/markdown.mdx +3 -1
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +4 -2
- package/docs/references/graphql.mdx +14 -2
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +148 -7
- package/docs/references/scalar.mdx +3 -1
- package/package.json +43 -8
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +7 -7
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +10 -7
- package/skills/blume-migrate/references/starlight.md +11 -8
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +2 -1
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +6 -3
- package/src/ai/ask-context.ts +103 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-limits.ts +13 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/changelog-markdown.ts +11 -6
- package/src/ai/component-markdown.ts +76 -1
- package/src/ai/cors.ts +14 -3
- package/src/ai/index.ts +12 -0
- package/src/ai/llms.ts +6 -2
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/mcp/query.ts +14 -6
- package/src/ai/openapi-components.ts +36 -6
- package/src/ai/relative-links.ts +4 -38
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +35 -2
- package/src/ai/write-skill.ts +97 -0
- package/src/astro/generate.ts +210 -66
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +42 -4
- package/src/astro/markdown-negotiation.ts +3 -0
- package/src/astro/module-types.ts +9 -1
- package/src/astro/pages.ts +23 -0
- package/src/astro/templates.ts +406 -108
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +38 -3
- package/src/audit/checks/contrast.ts +183 -0
- package/src/audit/checks/i18n.ts +2 -3
- package/src/audit/checks/indexability.ts +2 -3
- package/src/audit/checks/links.ts +19 -13
- package/src/audit/checks/network.ts +110 -6
- package/src/audit/checks/redirects.ts +6 -4
- package/src/audit/checks/robots.ts +58 -2
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +5 -0
- package/src/audit/types.ts +4 -1
- package/src/audit/url.ts +14 -5
- package/src/blume-modules.d.ts +12 -1
- package/src/captcha/client.ts +152 -0
- package/src/captcha/hcaptcha.ts +36 -0
- package/src/captcha/index.ts +28 -0
- package/src/captcha/schema.ts +32 -0
- package/src/captcha/turnstile.ts +38 -0
- package/src/captcha/verify.ts +71 -0
- package/src/cli/args.ts +51 -0
- package/src/cli/build-failure.ts +23 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/audit.ts +10 -1
- package/src/cli/commands/dev.ts +18 -2
- package/src/cli/commands/doctor.ts +67 -28
- package/src/cli/commands/eval.ts +36 -4
- package/src/cli/commands/init.ts +6 -4
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/commands/validate.ts +10 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/init/scaffold.ts +3 -3
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +72 -30
- package/src/components/BlumePage.astro +2 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +66 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Color.astro +1 -0
- package/src/components/content/FileTree.astro +1 -0
- package/src/components/content/GithubInfo.astro +1 -0
- package/src/components/content/Panel.astro +1 -0
- package/src/components/content/ParamField.astro +25 -0
- package/src/components/content/RequestExample.astro +17 -0
- package/src/components/content/ResponseExample.astro +17 -0
- package/src/components/content/ResponseField.astro +32 -0
- package/src/components/content/Step.astro +1 -0
- package/src/components/content/Tile.astro +1 -0
- package/src/components/content/Tooltip.astro +1 -0
- package/src/components/content/Tree.astro +1 -0
- package/src/components/content/TypeTable.astro +4 -1
- package/src/components/content/View.astro +21 -0
- package/src/components/content/ViewSwitcher.astro +168 -0
- package/src/components/content/api-field.ts +103 -0
- package/src/components/content/api-page.ts +248 -0
- package/src/components/content/mermaid-element.ts +15 -1
- package/src/components/content/view-switcher.ts +71 -0
- package/src/components/index.ts +2 -0
- package/src/components/islands/Assistant.astro +10 -1
- package/src/components/islands/assistant.tsx +104 -14
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +136 -21
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +6 -2
- package/src/components/layout/ConsentBanner.astro +62 -0
- package/src/components/layout/ConsentHead.astro +38 -0
- package/src/components/layout/Directory.astro +94 -0
- package/src/components/layout/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +122 -80
- package/src/components/layout/LanguageSwitcher.astro +48 -15
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +33 -7
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +71 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +318 -47
- package/src/components/layout/Search.astro +47 -19
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/TableOfContents.astro +24 -17
- package/src/components/layout/consent/native.ts +79 -0
- package/src/components/layout/consent/types.ts +37 -0
- package/src/components/layout/footer-links.ts +53 -0
- package/src/components/layout/footer-socials.ts +87 -0
- package/src/components/layout/head-scripts.ts +6 -1
- package/src/components/layout/locale-redirect.ts +107 -0
- package/src/components/layout/nav-utils.ts +83 -0
- package/src/components/layout/page-feedback.ts +96 -0
- package/src/components/layout/search/algolia.ts +10 -1
- package/src/components/layout/search/analytics.ts +126 -0
- package/src/components/layout/search/endpoint.ts +48 -5
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/pagefind.ts +114 -5
- package/src/components/layout/search/types.ts +32 -0
- package/src/components/layout/search/typesense.ts +19 -3
- package/src/components/openapi/AsyncApiOperation.astro +14 -7
- package/src/components/openapi/Authorization.astro +10 -0
- package/src/components/openapi/GraphqlOperation.astro +5 -0
- package/src/components/openapi/Operation.astro +184 -13
- package/src/components/openapi/ParametersTable.astro +8 -4
- package/src/components/openapi/Playground.astro +7 -1
- package/src/components/openapi/RequestBody.astro +24 -5
- package/src/components/openapi/RequestPanel.astro +59 -7
- package/src/components/openapi/Responses.astro +7 -4
- package/src/components/openapi/SchemaTable.astro +15 -3
- package/src/components/openapi/async-snippets.ts +65 -9
- package/src/components/openapi/async.ts +123 -29
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/graphql-helpers.ts +35 -12
- package/src/components/openapi/helpers.ts +36 -2
- package/src/components/openapi/message-model.ts +54 -11
- package/src/components/openapi/message.ts +14 -4
- package/src/components/openapi/operation-model.ts +16 -7
- package/src/components/openapi/playground-client.ts +24 -5
- package/src/components/openapi/playground-schema.ts +1 -1
- package/src/components/openapi/schema-tree.ts +44 -14
- package/src/components/openapi/security.ts +16 -3
- package/src/components/openapi/snippets.ts +873 -10
- package/src/components/openapi/validate-json.ts +4 -3
- package/src/components/props.ts +6 -0
- package/src/consent/client.ts +95 -0
- package/src/consent/clients.ts +19 -0
- package/src/consent/ethyca.ts +71 -0
- package/src/consent/head.ts +24 -0
- package/src/consent/index.ts +37 -0
- package/src/consent/init.ts +29 -0
- package/src/consent/native.ts +36 -0
- package/src/consent/osano.ts +59 -0
- package/src/consent/schema.ts +30 -0
- package/src/core/builtin-tags.ts +5 -0
- package/src/core/changelog-index.ts +31 -1
- package/src/core/client-address.ts +19 -0
- package/src/core/component-diagnostics.ts +53 -0
- package/src/core/component-overrides.ts +32 -0
- package/src/core/config-input.ts +225 -23
- package/src/core/data.ts +46 -4
- package/src/core/diagnostics.ts +8 -2
- package/src/core/footer.ts +26 -0
- package/src/core/graph.ts +39 -36
- package/src/core/i18n-ui.ts +84 -2
- package/src/core/includes.ts +21 -4
- package/src/core/links.ts +63 -19
- package/src/core/localizable.ts +26 -0
- package/src/core/navigation.ts +43 -12
- package/src/core/page-modes.ts +56 -0
- package/src/core/probe.ts +26 -6
- package/src/core/project-graph.ts +163 -16
- package/src/core/redirect-patterns.ts +520 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +339 -66
- package/src/core/sources/cache.ts +6 -0
- package/src/core/sources/contentful-rich-text.ts +29 -6
- package/src/core/sources/contentful.ts +135 -25
- package/src/core/sources/filesystem.ts +26 -4
- package/src/core/sources/github-releases.ts +12 -1
- package/src/core/sources/lexical.ts +15 -10
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +228 -41
- package/src/core/sources/notion.ts +7 -1
- package/src/core/sources/obsidian.ts +16 -3
- package/src/core/sources/payload.ts +38 -15
- package/src/core/sources/read.ts +8 -3
- package/src/core/sources/remote.ts +72 -15
- package/src/core/sources/resolve.ts +11 -1
- package/src/core/sources/sanity.ts +43 -25
- package/src/core/sources/strapi.ts +2 -2
- package/src/core/types.ts +19 -1
- package/src/core/ui-packs/ar.ts +44 -0
- package/src/core/ui-packs/bg.ts +46 -0
- package/src/core/ui-packs/bn.ts +44 -0
- package/src/core/ui-packs/ca.ts +47 -0
- package/src/core/ui-packs/cs.ts +45 -0
- package/src/core/ui-packs/da.ts +46 -0
- package/src/core/ui-packs/de.ts +47 -0
- package/src/core/ui-packs/el.ts +46 -0
- package/src/core/ui-packs/es.ts +47 -0
- package/src/core/ui-packs/fa.ts +46 -0
- package/src/core/ui-packs/fi.ts +46 -0
- package/src/core/ui-packs/fr.ts +47 -0
- package/src/core/ui-packs/he.ts +44 -0
- package/src/core/ui-packs/hi.ts +45 -0
- package/src/core/ui-packs/hr.ts +46 -0
- package/src/core/ui-packs/hu.ts +45 -0
- package/src/core/ui-packs/id.ts +46 -0
- package/src/core/ui-packs/it.ts +46 -0
- package/src/core/ui-packs/ja.ts +46 -0
- package/src/core/ui-packs/ko.ts +45 -0
- package/src/core/ui-packs/nl.ts +47 -0
- package/src/core/ui-packs/no.ts +45 -0
- package/src/core/ui-packs/pl.ts +46 -0
- package/src/core/ui-packs/pt-br.ts +47 -0
- package/src/core/ui-packs/pt.ts +46 -0
- package/src/core/ui-packs/ro.ts +46 -0
- package/src/core/ui-packs/ru.ts +46 -0
- package/src/core/ui-packs/sk.ts +45 -0
- package/src/core/ui-packs/sr.ts +46 -0
- package/src/core/ui-packs/sv.ts +45 -0
- package/src/core/ui-packs/th.ts +44 -0
- package/src/core/ui-packs/tr.ts +46 -0
- package/src/core/ui-packs/uk.ts +46 -0
- package/src/core/ui-packs/vi.ts +46 -0
- package/src/core/ui-packs/zh-tw.ts +44 -0
- package/src/core/ui-packs/zh.ts +44 -0
- package/src/core/variables.ts +103 -0
- package/src/deploy/adapter-output.ts +7 -2
- package/src/deploy/adapters/cloudflare.ts +7 -5
- package/src/deploy/adapters/node.ts +47 -9
- package/src/deploy/adapters/types.ts +7 -3
- package/src/deploy/artifacts.ts +79 -9
- package/src/deploy/cloudflare-negotiation.ts +35 -5
- package/src/deploy/headers.ts +2 -1
- package/src/deploy/node-headers.ts +63 -9
- package/src/deploy/platforms/cloudflare.ts +45 -9
- package/src/deploy/platforms/netlify.ts +35 -2
- package/src/deploy/platforms/node.ts +12 -2
- package/src/deploy/platforms/types.ts +21 -7
- package/src/deploy/platforms/vercel.ts +149 -17
- package/src/deploy/redirects.ts +151 -24
- package/src/deploy/rss.ts +3 -1
- package/src/deploy/sitemap.ts +39 -5
- package/src/deploy/vercel-negotiation.ts +326 -102
- package/src/eval/agents.ts +18 -1
- package/src/eval/prompts.ts +6 -3
- package/src/eval/report.ts +34 -13
- package/src/eval/run.ts +5 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/features.ts +3 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +28 -5
- package/src/markdown/math.ts +4 -4
- package/src/markdown/relative-links.ts +3 -2
- package/src/markdown/variables.ts +56 -0
- package/src/markdown/views.ts +82 -0
- package/src/narration/build.ts +412 -0
- package/src/narration/player.ts +249 -0
- package/src/narration/provider.ts +29 -0
- package/src/narration/script.ts +592 -0
- package/src/og/card.ts +7 -6
- package/src/openapi/checks.ts +273 -0
- package/src/openapi/graphql-build.ts +21 -0
- package/src/openapi/graphql.ts +11 -0
- package/src/openapi/model.ts +72 -27
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +182 -4
- package/src/openapi/references.ts +64 -8
- package/src/openapi/render-mdx.ts +5 -1
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +40 -15
- package/src/ratelimit/cloudflare.ts +54 -0
- package/src/ratelimit/index.ts +30 -0
- package/src/ratelimit/memory.ts +45 -0
- package/src/ratelimit/runtime.ts +247 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +60 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +20 -3
- package/src/reference/index.ts +1 -0
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +80 -8
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +23 -5
- package/src/registry/registry.ts +7 -0
- package/src/search/adapters/locale-scope.ts +30 -0
- package/src/search/adapters/typesense.ts +14 -4
- package/src/search/build.ts +21 -3
- package/src/search/documents.ts +26 -2
- package/src/search/orama-index.ts +191 -34
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/source-pages.ts +29 -0
- package/src/search/sync/algolia.ts +111 -10
- package/src/search/sync/index.ts +52 -13
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +76 -26
- package/src/seo/metatags.ts +67 -0
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/shared.ts +3 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +85 -6
- package/src/theme/palette.ts +121 -45
- package/src/translate/prompts.ts +1 -0
- package/src/translate/validate.ts +31 -3
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
- package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
- package/dist/cli/chunk-35d4wj9f.js.map +0 -15
- package/dist/cli/chunk-364znk6q.js +0 -75
- package/dist/cli/chunk-364znk6q.js.map +0 -11
- package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
- package/dist/cli/chunk-8ktnccpt.js.map +0 -10
- package/dist/cli/chunk-9t7a85s3.js.map +0 -10
- package/dist/cli/chunk-b07cmahc.js +0 -145
- package/dist/cli/chunk-b07cmahc.js.map +0 -11
- package/dist/cli/chunk-c8chx29p.js.map +0 -36
- package/dist/cli/chunk-e04dxsz1.js +0 -39
- package/dist/cli/chunk-e04dxsz1.js.map +0 -10
- package/dist/cli/chunk-j85vccga.js.map +0 -36
- package/dist/cli/chunk-p3v96n38.js.map +0 -10
- package/dist/cli/chunk-pehfxfta.js.map +0 -10
- package/dist/cli/chunk-pv29h0wf.js.map +0 -190
- package/dist/cli/chunk-q58y5e6a.js.map +0 -10
- package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
- package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
- package/dist/cli/chunk-yfyb25rh.js.map +0 -14
- package/docs/content/sources.mdx +0 -334
- /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
- /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
- /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
- /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
- /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
- /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
- /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
- /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.js.map} +0 -0
|
@@ -2,7 +2,10 @@ import type { JsonValue } from "../../core/adapter.ts";
|
|
|
2
2
|
import type { BlumeProject } from "../../core/project-graph.ts";
|
|
3
3
|
import type { ResolvedConfig } from "../../core/schema.ts";
|
|
4
4
|
import type { ProjectContext } from "../../core/types.ts";
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
DeployAdapterKind,
|
|
7
|
+
ResolvedDeployOptions,
|
|
8
|
+
} from "../adapters/registry.ts";
|
|
6
9
|
import type { DeployOutput } from "../adapters/types.ts";
|
|
7
10
|
|
|
8
11
|
/**
|
|
@@ -15,8 +18,16 @@ import type { DeployOutput } from "../adapters/types.ts";
|
|
|
15
18
|
|
|
16
19
|
/** How the generated `astro.config.mjs` constructs the `@astrojs/*` adapter. */
|
|
17
20
|
export interface AstroAdapterSpec {
|
|
18
|
-
/**
|
|
19
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Top-level `defineConfig` entries the adapter needs beside itself, some
|
|
23
|
+
* of them set from the deployment's own options.
|
|
24
|
+
*/
|
|
25
|
+
config: (options: ResolvedDeployOptions) => Record<string, JsonValue>;
|
|
26
|
+
/**
|
|
27
|
+
* The deployment options `config` reads, which therefore stay out of the
|
|
28
|
+
* passthrough to the `@astrojs/*` constructor.
|
|
29
|
+
*/
|
|
30
|
+
configOptions: string[];
|
|
20
31
|
/** Blume's own constructor options; the user's passthrough is spread over them. */
|
|
21
32
|
options: (context: ProjectContext) => Record<string, JsonValue>;
|
|
22
33
|
/** The package the config imports the adapter from. */
|
|
@@ -115,13 +126,16 @@ export interface DeployPlatform {
|
|
|
115
126
|
/**
|
|
116
127
|
* Whether the adapter moves a server build's client output under
|
|
117
128
|
* `deployment.base` (`dist/client/<base>/`, the directory Astro then hands
|
|
118
|
-
* `astro:build:done`) while the platform keeps serving `
|
|
119
|
-
*
|
|
129
|
+
* `astro:build:done`) while the platform keeps serving `dist/client` as
|
|
130
|
+
* the assets root. The files the platform reads there, like `_headers`,
|
|
120
131
|
* belong above the directory Astro reports.
|
|
121
132
|
*/
|
|
122
133
|
serverClientUnderBase: boolean;
|
|
123
134
|
/** Where a server build's deploy bundle lands. */
|
|
124
135
|
serverOutputDir: (context: ProjectContext) => string;
|
|
125
|
-
/**
|
|
126
|
-
|
|
136
|
+
/**
|
|
137
|
+
* The directory a server build serves as static files, given the normalized
|
|
138
|
+
* `deployment.base` for a platform that serves them from `<dir>/<base>/`.
|
|
139
|
+
*/
|
|
140
|
+
serverStaticDir: (context: ProjectContext, base: string) => string;
|
|
127
141
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
3
|
|
|
4
|
-
import { join } from "pathe";
|
|
4
|
+
import { dirname, join } from "pathe";
|
|
5
5
|
|
|
6
6
|
import { crossOriginDiscoveryPaths } from "../../ai/ai-catalog.ts";
|
|
7
7
|
import {
|
|
@@ -20,7 +20,10 @@ import {
|
|
|
20
20
|
SIGNATURES_DIRECTORY_PATH,
|
|
21
21
|
SIGNATURES_DIRECTORY_TYPE,
|
|
22
22
|
} from "../../ai/web-bot-auth.ts";
|
|
23
|
+
import { mountBasePath, normalizeBasePath } from "../../core/base-path.ts";
|
|
23
24
|
import type { BlumeProject } from "../../core/project-graph.ts";
|
|
25
|
+
import { isPatternPath, regexRedirect } from "../../core/redirect-patterns.ts";
|
|
26
|
+
import type { ResolvedConfig } from "../../core/schema.ts";
|
|
24
27
|
import type { ProjectContext } from "../../core/types.ts";
|
|
25
28
|
import { VERCEL_ADAPTER_PACKAGE } from "../adapters/vercel.ts";
|
|
26
29
|
import {
|
|
@@ -29,8 +32,17 @@ import {
|
|
|
29
32
|
blumeDependencyNames,
|
|
30
33
|
functionBundleVerdict,
|
|
31
34
|
} from "../function-bundle.ts";
|
|
32
|
-
import {
|
|
33
|
-
|
|
35
|
+
import {
|
|
36
|
+
buildVercelConfig,
|
|
37
|
+
platformRedirects,
|
|
38
|
+
vercelPatternRoutes,
|
|
39
|
+
} from "../redirects.ts";
|
|
40
|
+
import {
|
|
41
|
+
injectNegotiationRoutes,
|
|
42
|
+
injectRedirectRoutes,
|
|
43
|
+
rebaseAdapterRoutes,
|
|
44
|
+
} from "../vercel-negotiation.ts";
|
|
45
|
+
import type { VercelRoute } from "../vercel-negotiation.ts";
|
|
34
46
|
import { adapterRoot, toSiteUrl } from "./paths.ts";
|
|
35
47
|
import type { BuildLog, DeployPlatform, RedirectFile } from "./types.ts";
|
|
36
48
|
|
|
@@ -49,6 +61,14 @@ export const VERCEL_JSON_FILE: RedirectFile = {
|
|
|
49
61
|
const buildOutputDir = (context: ProjectContext): string =>
|
|
50
62
|
join(adapterRoot(context), ".vercel", "output");
|
|
51
63
|
|
|
64
|
+
/** The static files a server build serves, under the base's directory. */
|
|
65
|
+
const staticDir = (context: ProjectContext, base: string): string =>
|
|
66
|
+
join(buildOutputDir(context), "static", base);
|
|
67
|
+
|
|
68
|
+
/** The project's normalized `deployment.base`, `""` for none. */
|
|
69
|
+
const deploymentBase = (project: BlumeProject): string =>
|
|
70
|
+
normalizeBasePath(project.config.deployment.options.base);
|
|
71
|
+
|
|
52
72
|
/**
|
|
53
73
|
* Refuse to ship a function bundle that would crash at runtime: a bare import
|
|
54
74
|
* the adapter's dependency trace silently dropped (see
|
|
@@ -92,18 +112,21 @@ export const emitVercelNegotiation = async (
|
|
|
92
112
|
log: BuildLog
|
|
93
113
|
): Promise<void> => {
|
|
94
114
|
const { config, context } = project;
|
|
95
|
-
const
|
|
96
|
-
const configPath = join(outputDir, "config.json");
|
|
115
|
+
const configPath = join(buildOutputDir(context), "config.json");
|
|
97
116
|
if (!existsSync(configPath)) {
|
|
98
117
|
return;
|
|
99
118
|
}
|
|
119
|
+
const base = deploymentBase(project);
|
|
100
120
|
const routePaths = markdownRoutePaths(project);
|
|
121
|
+
// Keyed by the file's path in `static/`, under the base's directory.
|
|
101
122
|
const overrides: Record<string, string> = {};
|
|
102
123
|
if (hasApiCatalog(config)) {
|
|
103
|
-
overrides[API_CATALOG_PATH.slice(1)] =
|
|
124
|
+
overrides[mountBasePath(base, API_CATALOG_PATH).slice(1)] =
|
|
125
|
+
API_CATALOG_TYPE;
|
|
104
126
|
}
|
|
105
127
|
if (config.agents.webBotAuth.keys.length > 0) {
|
|
106
|
-
overrides[SIGNATURES_DIRECTORY_PATH.slice(1)] =
|
|
128
|
+
overrides[mountBasePath(base, SIGNATURES_DIRECTORY_PATH).slice(1)] =
|
|
129
|
+
SIGNATURES_DIRECTORY_TYPE;
|
|
107
130
|
}
|
|
108
131
|
// The homepage rewrite serves `/index.md` from the static layer, so its
|
|
109
132
|
// `x-markdown-tokens` estimate has to ride the routing config; the runtime
|
|
@@ -113,7 +136,7 @@ export const emitVercelNegotiation = async (
|
|
|
113
136
|
// The Markdown and JSON 404 routes point at the prerendered twins; only
|
|
114
137
|
// wire each when the build actually emitted it (a project that owns `/404`
|
|
115
138
|
// gets none).
|
|
116
|
-
const
|
|
139
|
+
const builtDir = staticDir(context, base);
|
|
117
140
|
const injected = injectNegotiationRoutes(
|
|
118
141
|
await readFile(configPath, "utf-8"),
|
|
119
142
|
routePaths,
|
|
@@ -121,13 +144,14 @@ export const emitVercelNegotiation = async (
|
|
|
121
144
|
overrides,
|
|
122
145
|
home ? markdownTokenCount(agentMarkdown(home)) : undefined,
|
|
123
146
|
{
|
|
124
|
-
json: existsSync(join(
|
|
125
|
-
markdown: existsSync(join(
|
|
147
|
+
json: existsSync(join(builtDir, "404.json")),
|
|
148
|
+
markdown: existsSync(join(builtDir, "404.md")),
|
|
126
149
|
},
|
|
127
150
|
crossOriginDiscoveryPaths(config),
|
|
128
151
|
// Downloaded content assets are prerendered static files; only a build
|
|
129
152
|
// that has them needs the SVG sandbox route.
|
|
130
|
-
existsSync(join(
|
|
153
|
+
existsSync(join(builtDir, "blume-assets")),
|
|
154
|
+
base
|
|
131
155
|
);
|
|
132
156
|
if (injected === null) {
|
|
133
157
|
log.warn(
|
|
@@ -141,6 +165,103 @@ export const emitVercelNegotiation = async (
|
|
|
141
165
|
);
|
|
142
166
|
};
|
|
143
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Route the pattern redirects (`/beta/:slug*`) in the adapter's Build Output
|
|
170
|
+
* config: Astro's `redirects` carry only the exact ones, since it can't
|
|
171
|
+
* prerender a pattern's pages, so the adapter never sees these.
|
|
172
|
+
*/
|
|
173
|
+
export const emitVercelPatternRedirects = async (
|
|
174
|
+
project: BlumeProject,
|
|
175
|
+
log: BuildLog
|
|
176
|
+
): Promise<void> => {
|
|
177
|
+
const routes = vercelPatternRoutes(platformRedirects(project));
|
|
178
|
+
const configPath = join(buildOutputDir(project.context), "config.json");
|
|
179
|
+
if (routes.length === 0 || !existsSync(configPath)) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const injected = injectRedirectRoutes(
|
|
183
|
+
await readFile(configPath, "utf-8"),
|
|
184
|
+
routes
|
|
185
|
+
);
|
|
186
|
+
if (injected === null) {
|
|
187
|
+
log.warn(
|
|
188
|
+
"Could not route the pattern redirects in .vercel/output/config.json, so paths they cover answer 404."
|
|
189
|
+
);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
await writeFile(configPath, injected, "utf-8");
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
type Redirect = ResolvedConfig["redirects"][number];
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* The exact redirects as Build Output routes, matched the way the pattern ones
|
|
199
|
+
* are (see `regexRedirect`): the served path, a trailing slash optional.
|
|
200
|
+
*/
|
|
201
|
+
const exactRedirectRoutes = (redirects: Redirect[]): VercelRoute[] =>
|
|
202
|
+
redirects
|
|
203
|
+
.filter((redirect) => !isPatternPath(redirect.from))
|
|
204
|
+
.map(({ from, status, to }) => ({
|
|
205
|
+
headers: { Location: encodeURI(to) },
|
|
206
|
+
src: regexRedirect({ parts: [{ kind: "text", text: from }], status, to })
|
|
207
|
+
.source,
|
|
208
|
+
status,
|
|
209
|
+
}));
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Move a server build's static files under `deployment.base`.
|
|
213
|
+
* `@astrojs/vercel` copies them to the root of the Build Output tree's
|
|
214
|
+
* `static/`, while the pages request `<base>/_astro/…` and link to
|
|
215
|
+
* `<base>/…`, so nothing the site asks for would be found. Moved to
|
|
216
|
+
* `static/<base>/`, they're served at the base, as the routes that
|
|
217
|
+
* {@link rebaseVercelRoutes} moves there expect.
|
|
218
|
+
*/
|
|
219
|
+
export const moveStaticUnderBase = async (
|
|
220
|
+
context: ProjectContext,
|
|
221
|
+
base: string
|
|
222
|
+
): Promise<void> => {
|
|
223
|
+
const root = staticDir(context, "");
|
|
224
|
+
if (!base || !existsSync(root)) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
// Through a sibling, since the target lies inside the directory it moves.
|
|
228
|
+
const staging = join(buildOutputDir(context), "static-unbased");
|
|
229
|
+
await rename(root, staging);
|
|
230
|
+
const target = staticDir(context, base);
|
|
231
|
+
await mkdir(dirname(target), { recursive: true });
|
|
232
|
+
await rename(staging, target);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Move the adapter's routing config under `deployment.base` to match the
|
|
237
|
+
* static files (see `rebaseAdapterRoutes`), its exact redirects rebuilt from
|
|
238
|
+
* the configured ones. Resolves to false when the config can't be read: the
|
|
239
|
+
* adapter's routes would then miss every path under the base.
|
|
240
|
+
*/
|
|
241
|
+
export const rebaseVercelRoutes = async (
|
|
242
|
+
project: BlumeProject,
|
|
243
|
+
log: BuildLog
|
|
244
|
+
): Promise<boolean> => {
|
|
245
|
+
const base = deploymentBase(project);
|
|
246
|
+
const configPath = join(buildOutputDir(project.context), "config.json");
|
|
247
|
+
if (!base || !existsSync(configPath)) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
const rebased = rebaseAdapterRoutes(
|
|
251
|
+
await readFile(configPath, "utf-8"),
|
|
252
|
+
base,
|
|
253
|
+
exactRedirectRoutes(platformRedirects(project))
|
|
254
|
+
);
|
|
255
|
+
if (rebased === null) {
|
|
256
|
+
log.error(
|
|
257
|
+
`Could not move the routes in .vercel/output/config.json under the deployment base "${base}", so the site would not be served there.`
|
|
258
|
+
);
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
await writeFile(configPath, rebased, "utf-8");
|
|
262
|
+
return true;
|
|
263
|
+
};
|
|
264
|
+
|
|
144
265
|
/**
|
|
145
266
|
* Vercel. A server build's Build Output tree lands at `.vercel/output` — at
|
|
146
267
|
* the project root, because the adapter is handed that root up front: its
|
|
@@ -149,11 +270,14 @@ export const emitVercelNegotiation = async (
|
|
|
149
270
|
* Static assets are served from the tree's `static/` half, so the deploy
|
|
150
271
|
* artifacts are written there; headers (the discovery files', the sandbox on
|
|
151
272
|
* downloaded SVGs) arrive through the routing config rather than a
|
|
152
|
-
* `_headers` file, which Vercel never reads.
|
|
273
|
+
* `_headers` file, which Vercel never reads. The adapter ignores
|
|
274
|
+
* `deployment.base`, so under one the build moves the static files and the
|
|
275
|
+
* routes beneath it.
|
|
153
276
|
*/
|
|
154
277
|
export const vercelPlatform: DeployPlatform = {
|
|
155
278
|
astro: {
|
|
156
|
-
config: {},
|
|
279
|
+
config: () => ({}),
|
|
280
|
+
configOptions: [],
|
|
157
281
|
options: () => ({}),
|
|
158
282
|
package: VERCEL_ADAPTER_PACKAGE,
|
|
159
283
|
},
|
|
@@ -176,11 +300,19 @@ export const vercelPlatform: DeployPlatform = {
|
|
|
176
300
|
if (!ok) {
|
|
177
301
|
return false;
|
|
178
302
|
}
|
|
303
|
+
// A verify build moves its static files too, where the budget gate reads
|
|
304
|
+
// them (`serverStaticDir`).
|
|
305
|
+
await moveStaticUnderBase(context, deploymentBase(project));
|
|
179
306
|
// An isolated verify only proves the bundle would ship; the routing
|
|
180
307
|
// config is a deploy artifact and stays untouched.
|
|
181
|
-
if (
|
|
182
|
-
|
|
308
|
+
if (isolated) {
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
if (!(await rebaseVercelRoutes(project, log))) {
|
|
312
|
+
return false;
|
|
183
313
|
}
|
|
314
|
+
await emitVercelNegotiation(project, log);
|
|
315
|
+
await emitVercelPatternRedirects(project, log);
|
|
184
316
|
return true;
|
|
185
317
|
},
|
|
186
318
|
hiddenRuntime: {
|
|
@@ -196,5 +328,5 @@ export const vercelPlatform: DeployPlatform = {
|
|
|
196
328
|
redirectFiles: [VERCEL_JSON_FILE],
|
|
197
329
|
serverClientUnderBase: false,
|
|
198
330
|
serverOutputDir: buildOutputDir,
|
|
199
|
-
serverStaticDir:
|
|
331
|
+
serverStaticDir: staticDir,
|
|
200
332
|
};
|
package/src/deploy/redirects.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
normalizeBasePath,
|
|
3
|
+
normalizePath,
|
|
4
|
+
stripBasePath,
|
|
3
5
|
withAuthoredBasePath,
|
|
4
6
|
withBasePath,
|
|
5
7
|
withComposedBasePath,
|
|
@@ -7,16 +9,29 @@ import {
|
|
|
7
9
|
import { routeSetFor, servesRoute } from "../core/locale-links.ts";
|
|
8
10
|
import type { RouteSet } from "../core/locale-links.ts";
|
|
9
11
|
import type { BlumeProject } from "../core/project-graph.ts";
|
|
12
|
+
import {
|
|
13
|
+
compileRedirects,
|
|
14
|
+
exactFirst,
|
|
15
|
+
expandRedirect,
|
|
16
|
+
isPatternPath,
|
|
17
|
+
underscoreRedirect,
|
|
18
|
+
vercelRedirect,
|
|
19
|
+
} from "../core/redirect-patterns.ts";
|
|
20
|
+
import type { RedirectRule } from "../core/redirect-patterns.ts";
|
|
10
21
|
import type { ResolvedConfig } from "../core/schema.ts";
|
|
11
22
|
import { escapeVercelSource } from "./headers.ts";
|
|
12
23
|
import type { VercelHeader } from "./headers.ts";
|
|
24
|
+
import type { VercelRoute } from "./vercel-negotiation.ts";
|
|
13
25
|
|
|
14
26
|
/**
|
|
15
27
|
* Platform redirect files for a static build. Astro already emits redirect HTML
|
|
16
28
|
* (meta-refresh) pages for static output, but that's a soft client redirect.
|
|
17
29
|
* These give the host a real HTTP 3xx: Netlify/Cloudflare read `_redirects`,
|
|
18
30
|
* Vercel reads `vercel.json`, and `blume-redirects.json` is a structured
|
|
19
|
-
* manifest for anything else (Apache/nginx rules, an edge worker).
|
|
31
|
+
* manifest for anything else (Apache/nginx rules, an edge worker). A pattern
|
|
32
|
+
* redirect (`/beta/:slug*`) gets no redirect page, since Astro can't
|
|
33
|
+
* prerender one for paths it doesn't know; each host file carries it in that
|
|
34
|
+
* host's syntax (see `core/redirect-patterns.ts`).
|
|
20
35
|
*/
|
|
21
36
|
|
|
22
37
|
type Redirect = ResolvedConfig["redirects"][number];
|
|
@@ -97,39 +112,116 @@ export const applyBaseToPlatformRedirects = (
|
|
|
97
112
|
: redirects;
|
|
98
113
|
};
|
|
99
114
|
|
|
115
|
+
/**
|
|
116
|
+
* The raw-Markdown copies Blume serves beside every page (`/guide.md`,
|
|
117
|
+
* `/guide.mdx`; see `rawMarkdownEndpointTemplate`).
|
|
118
|
+
*/
|
|
119
|
+
const MIRROR_EXTENSIONS = [".md", ".mdx"] as const;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Where a page's Markdown copy is served, from the page's served path and the
|
|
123
|
+
* deployment base that path carries: the endpoints name the root `index`.
|
|
124
|
+
*/
|
|
125
|
+
const mirrorPath = (path: string, base: string, extension: string): string => {
|
|
126
|
+
const route = stripBasePath(base, path);
|
|
127
|
+
return `${base}${route === "/" ? "/index" : route}${extension}`;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Based `redirects`, each exact one that moves a page followed by the same
|
|
132
|
+
* redirect for the page's Markdown copies: from a path no page is served at
|
|
133
|
+
* to one a page is, `/old.md` goes to `/new.md` (and `.mdx` alike), where it
|
|
134
|
+
* would otherwise 404 for an agent still reading the old URL. A pattern gets
|
|
135
|
+
* none; one that carries its capture over (`/beta/:slug*` → `/v2/:slug*`)
|
|
136
|
+
* already moves `/beta/guide.md` along. `pages` are the served page routes
|
|
137
|
+
* (carrying `basePath`, not `deployment.base`), and `bases` the deployment
|
|
138
|
+
* base each end carries: Astro's config leaves it off `from` (see
|
|
139
|
+
* {@link applyBaseToAstroRedirects}).
|
|
140
|
+
*/
|
|
141
|
+
export const withMirrorRedirects = (
|
|
142
|
+
redirects: Redirect[],
|
|
143
|
+
pages: RouteSet,
|
|
144
|
+
bases: { from: string; to: string }
|
|
145
|
+
): Redirect[] =>
|
|
146
|
+
redirects.flatMap((redirect) => {
|
|
147
|
+
const from = normalizePath(redirect.from);
|
|
148
|
+
const to = normalizePath(redirect.to);
|
|
149
|
+
const movesPage =
|
|
150
|
+
!isPatternPath(redirect.from) &&
|
|
151
|
+
servesRoute(pages, stripBasePath(bases.to, to)) &&
|
|
152
|
+
!servesRoute(pages, stripBasePath(bases.from, from));
|
|
153
|
+
return movesPage
|
|
154
|
+
? [
|
|
155
|
+
redirect,
|
|
156
|
+
...MIRROR_EXTENSIONS.map((extension) => ({
|
|
157
|
+
from: mirrorPath(from, bases.from, extension),
|
|
158
|
+
status: redirect.status,
|
|
159
|
+
to: mirrorPath(to, bases.to, extension),
|
|
160
|
+
})),
|
|
161
|
+
]
|
|
162
|
+
: [redirect];
|
|
163
|
+
});
|
|
164
|
+
|
|
100
165
|
/**
|
|
101
166
|
* The configured redirects as the host platform matches them, via
|
|
102
|
-
* {@link applyBaseToPlatformRedirects}
|
|
103
|
-
*
|
|
104
|
-
*
|
|
167
|
+
* {@link applyBaseToPlatformRedirects} plus the Markdown copies of each moved
|
|
168
|
+
* page ({@link withMirrorRedirects}), exact paths ahead of patterns: hosts
|
|
169
|
+
* try rules in order, and an exact redirect wins over a pattern that also
|
|
170
|
+
* covers its path. The one basing every consumer must share: the emitted
|
|
171
|
+
* redirect files and the server wrappers all compare these paths against
|
|
172
|
+
* real served URLs.
|
|
105
173
|
*/
|
|
106
174
|
export const platformRedirects = (project: {
|
|
107
175
|
config: ResolvedConfig;
|
|
108
176
|
manifest: Pick<BlumeProject["manifest"], "routes">;
|
|
109
177
|
}): Redirect[] => {
|
|
110
178
|
const { config } = project;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
179
|
+
const base = normalizeBasePath(config.deployment.options.base);
|
|
180
|
+
const pages = routeSetFor(project.manifest.routes);
|
|
181
|
+
return exactFirst(
|
|
182
|
+
withMirrorRedirects(
|
|
183
|
+
applyBaseToPlatformRedirects(
|
|
184
|
+
config.redirects,
|
|
185
|
+
config.basePath,
|
|
186
|
+
base,
|
|
187
|
+
pages
|
|
188
|
+
),
|
|
189
|
+
pages,
|
|
190
|
+
{ from: base, to: base }
|
|
191
|
+
)
|
|
116
192
|
);
|
|
117
193
|
};
|
|
118
194
|
|
|
119
195
|
/**
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
|
|
123
|
-
|
|
196
|
+
* A redirect as the entries a host file lists: itself when its path is
|
|
197
|
+
* exact, else the rules its pattern expands to, in the host's syntax.
|
|
198
|
+
*/
|
|
199
|
+
const hostEntries = <Entry>(
|
|
200
|
+
redirect: Redirect,
|
|
201
|
+
exact: (redirect: Redirect) => Entry,
|
|
202
|
+
pattern: (rule: RedirectRule) => Entry
|
|
203
|
+
): Entry[] => {
|
|
204
|
+
const rules = expandRedirect(redirect);
|
|
205
|
+
return rules.length > 0 ? rules.map(pattern) : [exact(redirect)];
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* `_redirects` text (Netlify + Cloudflare Pages): `from to status` per line,
|
|
210
|
+
* a pattern as `:placeholder`s and a `*` splat the destination reads as
|
|
211
|
+
* `:splat`. `force` appends Netlify's `!` to each status (`301!`), so the rule
|
|
212
|
+
* wins over the redirect page Astro writes at `from`; Cloudflare, which always
|
|
213
|
+
* applies its rules first, rejects a line carrying it.
|
|
124
214
|
*/
|
|
125
215
|
export const buildNetlifyRedirects = (
|
|
126
216
|
redirects: Redirect[],
|
|
127
217
|
force = false
|
|
128
218
|
): string =>
|
|
129
219
|
`${redirects
|
|
130
|
-
.
|
|
131
|
-
(redirect) =>
|
|
132
|
-
|
|
220
|
+
.flatMap((redirect) =>
|
|
221
|
+
hostEntries(redirect, (exact) => exact, underscoreRedirect).map(
|
|
222
|
+
(entry) =>
|
|
223
|
+
`${entry.from} ${entry.to} ${redirect.status}${force ? "!" : ""}`
|
|
224
|
+
)
|
|
133
225
|
)
|
|
134
226
|
.join("\n")}\n`;
|
|
135
227
|
|
|
@@ -145,19 +237,25 @@ interface VercelConfig {
|
|
|
145
237
|
* alternative to the boolean `permanent`) so the configured code ships exactly:
|
|
146
238
|
* `permanent` would silently coerce a 301 to 308 and a 302 to 307, diverging
|
|
147
239
|
* from the `_redirects` file, which preserves exact codes. A `source` is a
|
|
148
|
-
* `path-to-regexp` pattern, so each
|
|
149
|
-
* `/c++-guide` fails the whole config and `/faq(old)` never
|
|
240
|
+
* `path-to-regexp` pattern, so each literal run of a `from` path is escaped:
|
|
241
|
+
* unescaped, `/c++-guide` fails the whole config and `/faq(old)` never
|
|
242
|
+
* matches. A pattern's captures are `path-to-regexp` params.
|
|
150
243
|
*/
|
|
151
244
|
export const buildVercelConfig = (
|
|
152
245
|
redirects: Redirect[],
|
|
153
246
|
headers: readonly VercelHeader[] = []
|
|
154
247
|
): string => {
|
|
155
248
|
const config: VercelConfig = {
|
|
156
|
-
redirects: redirects.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
249
|
+
redirects: redirects.flatMap((redirect) =>
|
|
250
|
+
hostEntries(
|
|
251
|
+
redirect,
|
|
252
|
+
(exact) => ({
|
|
253
|
+
destination: exact.to,
|
|
254
|
+
source: escapeVercelSource(exact.from),
|
|
255
|
+
}),
|
|
256
|
+
(rule) => vercelRedirect(rule, escapeVercelSource)
|
|
257
|
+
).map((entry) => ({ ...entry, statusCode: redirect.status }))
|
|
258
|
+
),
|
|
161
259
|
};
|
|
162
260
|
if (headers.length > 0) {
|
|
163
261
|
config.headers = headers;
|
|
@@ -165,7 +263,36 @@ export const buildVercelConfig = (
|
|
|
165
263
|
return `${JSON.stringify(config, null, 2)}\n`;
|
|
166
264
|
};
|
|
167
265
|
|
|
168
|
-
/**
|
|
266
|
+
/**
|
|
267
|
+
* The pattern redirects as `_redirects` entries, for the `redirects` of a
|
|
268
|
+
* Netlify server build's Frameworks API config (see
|
|
269
|
+
* {@link buildNetlifyRedirects} for the syntax).
|
|
270
|
+
*/
|
|
271
|
+
export const netlifyPatternRedirects = (
|
|
272
|
+
redirects: Redirect[]
|
|
273
|
+
): { from: string; status: number; to: string }[] =>
|
|
274
|
+
redirects.flatMap(expandRedirect).map((rule) => ({
|
|
275
|
+
...underscoreRedirect(rule),
|
|
276
|
+
status: rule.status,
|
|
277
|
+
}));
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* The pattern redirects as Build Output API routes, for a Vercel server
|
|
281
|
+
* build: the adapter routes only the exact redirects Astro's config carries.
|
|
282
|
+
* Each matches the served path, a trailing slash optional, and fills its
|
|
283
|
+
* `Location` from numbered captures, as the adapter's own redirect routes do.
|
|
284
|
+
*/
|
|
285
|
+
export const vercelPatternRoutes = (redirects: Redirect[]): VercelRoute[] =>
|
|
286
|
+
compileRedirects(redirects).map(([src, location, status]) => ({
|
|
287
|
+
headers: { Location: location },
|
|
288
|
+
src,
|
|
289
|
+
status,
|
|
290
|
+
}));
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Structured manifest for hosts that need manual wiring. A pattern stays as
|
|
294
|
+
* configured (`/beta/:slug*`), for the rule it becomes to be written by hand.
|
|
295
|
+
*/
|
|
169
296
|
export const buildRedirectManifest = (redirects: Redirect[]): string =>
|
|
170
297
|
`${JSON.stringify(
|
|
171
298
|
redirects.map((redirect) => ({
|
package/src/deploy/rss.ts
CHANGED
|
@@ -78,7 +78,9 @@ export const buildRssFeeds = (project: BlumeProject): RssFeed[] => {
|
|
|
78
78
|
const items: RssItem[] = pages
|
|
79
79
|
.map((page) => ({
|
|
80
80
|
date: pageDate(page),
|
|
81
|
-
|
|
81
|
+
// A page with only a meta description (a GitHub release, whose
|
|
82
|
+
// summary goes in `seo.description`) still describes its item.
|
|
83
|
+
description: page.description ?? page.meta.seo.description,
|
|
82
84
|
// Encode like the sitemap does: a route with spaces or non-ASCII
|
|
83
85
|
// must still yield a valid <link>/<guid> URL after XML decoding.
|
|
84
86
|
link: encodeURI(`${base}${mountBasePath(deployBase, page.route)}`),
|
package/src/deploy/sitemap.ts
CHANGED
|
@@ -6,7 +6,11 @@ import {
|
|
|
6
6
|
discoverPagesSync,
|
|
7
7
|
hasGeneratedChangelog,
|
|
8
8
|
} from "../astro/pages.ts";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
mountBasePath,
|
|
11
|
+
normalizeBasePath,
|
|
12
|
+
normalizePath,
|
|
13
|
+
} from "../core/base-path.ts";
|
|
10
14
|
import type { BlumeProject } from "../core/project-graph.ts";
|
|
11
15
|
import { siteRoot } from "../core/site-url.ts";
|
|
12
16
|
|
|
@@ -30,6 +34,30 @@ const lastmodTag = (value: string | undefined): string => {
|
|
|
30
34
|
: `<lastmod>${date.toISOString().slice(0, 10)}</lastmod>`;
|
|
31
35
|
};
|
|
32
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Whether a page's own `seo.canonical` names another URL. The sitemap lists
|
|
39
|
+
* canonical URLs only, so such a page stays out — `blume audit` reports a
|
|
40
|
+
* listed one as NON_CANONICAL_IN_SITEMAP and expects it unlisted. Compared by
|
|
41
|
+
* decoded path, as the audit does: `served` is the page's path with the
|
|
42
|
+
* deployment base mounted, which the canonical carries too.
|
|
43
|
+
*/
|
|
44
|
+
const canonicalElsewhere = (
|
|
45
|
+
canonical: string | undefined,
|
|
46
|
+
served: string
|
|
47
|
+
): boolean => {
|
|
48
|
+
if (!canonical) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const { pathname } = new URL(canonical);
|
|
52
|
+
let path = pathname;
|
|
53
|
+
try {
|
|
54
|
+
path = decodeURI(pathname);
|
|
55
|
+
} catch {
|
|
56
|
+
// A malformed escape stays as written; it can't match the served path.
|
|
57
|
+
}
|
|
58
|
+
return normalizePath(path) !== normalizePath(served);
|
|
59
|
+
};
|
|
60
|
+
|
|
33
61
|
/** One emitted sitemap artifact: its dist-root filename and XML body. */
|
|
34
62
|
export interface SitemapFile {
|
|
35
63
|
name: string;
|
|
@@ -62,7 +90,8 @@ ${urls.join("\n")}
|
|
|
62
90
|
* can't see: custom `.astro` pages (most importantly a custom landing `/`) and
|
|
63
91
|
* the generated `/changelog` index. Returns null when the sitemap is disabled
|
|
64
92
|
* or no `site` is configured (absolute URLs are required for a valid sitemap).
|
|
65
|
-
* Drafts, hidden, and `noindex` pages are excluded
|
|
93
|
+
* Drafts, hidden, and `noindex` pages are excluded, and so is a page whose
|
|
94
|
+
* `seo.canonical` points elsewhere.
|
|
66
95
|
*
|
|
67
96
|
* Sites within the per-file URL cap get the single classic `sitemap.xml`;
|
|
68
97
|
* larger sites get `sitemap.xml` as a sitemap index over numbered
|
|
@@ -87,7 +116,9 @@ export const buildSitemapFiles = (
|
|
|
87
116
|
// or when their canonical points at a still-existing latest equivalent —
|
|
88
117
|
// listing a URL whose canonical says "index the other page" invites the
|
|
89
118
|
// noindexed-page-in-sitemap incoherence Docusaurus is known for. A page
|
|
90
|
-
// that exists only in an archived version stays listed (self-canonical)
|
|
119
|
+
// that exists only in an archived version stays listed (self-canonical),
|
|
120
|
+
// and a page's own `seo.canonical` wins over the version's default, as it
|
|
121
|
+
// does in the page head (see `canonicalElsewhere`).
|
|
91
122
|
const { versions } = project.config;
|
|
92
123
|
const archivedById = new Map(
|
|
93
124
|
(versions?.archived ?? []).map((version) => [version.id, version])
|
|
@@ -109,6 +140,7 @@ export const buildSitemapFiles = (
|
|
|
109
140
|
return Boolean(
|
|
110
141
|
archived?.noindex ||
|
|
111
142
|
(archived?.canonical === "latest" &&
|
|
143
|
+
!page.meta.seo.canonical &&
|
|
112
144
|
currentKeys?.has(`${page.versionKey}\u0000${page.locale}`))
|
|
113
145
|
);
|
|
114
146
|
};
|
|
@@ -128,16 +160,18 @@ export const buildSitemapFiles = (
|
|
|
128
160
|
urls.push(` <url><loc>${loc}</loc>${lastmodTag(lastModified)}</url>`);
|
|
129
161
|
};
|
|
130
162
|
for (const page of project.graph.pages) {
|
|
163
|
+
const served = mountBasePath(deployBase, page.route);
|
|
131
164
|
if (
|
|
132
165
|
page.meta.draft ||
|
|
133
166
|
page.meta.sidebar.hidden ||
|
|
134
167
|
page.meta.seo.noindex ||
|
|
135
168
|
ERROR_ROUTES.has(page.route) ||
|
|
136
|
-
archivedExcluded(page)
|
|
169
|
+
archivedExcluded(page) ||
|
|
170
|
+
canonicalElsewhere(page.meta.seo.canonical, served)
|
|
137
171
|
) {
|
|
138
172
|
continue;
|
|
139
173
|
}
|
|
140
|
-
pushUrl(
|
|
174
|
+
pushUrl(served, page.lastModified);
|
|
141
175
|
}
|
|
142
176
|
// Custom `.astro` pages and the generated changelog index mount outside
|
|
143
177
|
// `basePath` (they're injected at their pattern — see `blumeIntegration`), so
|