blume 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -0
- package/dist/cli/{chunk-qwsrynx5.js → chunk-1d7ve1dm.js} +38 -19
- package/dist/cli/{chunk-qwsrynx5.js.map → chunk-1d7ve1dm.js.map} +4 -4
- package/dist/cli/{chunk-s6jhgk0q.js → chunk-2eytanqx.js} +2 -2
- package/dist/cli/{chunk-kdp5q7ke.js → chunk-2hsdwb9n.js} +18 -19
- package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-2hsdwb9n.js.map} +2 -2
- package/dist/cli/{chunk-hdpx1tax.js → chunk-2z928egk.js} +5 -5
- package/dist/cli/{chunk-jwyddg7y.js → chunk-35d4wj9f.js} +30 -24
- package/dist/cli/chunk-35d4wj9f.js.map +15 -0
- package/dist/cli/{chunk-ah61y8py.js → chunk-364znk6q.js} +2 -2
- package/dist/cli/{chunk-jts8mvcz.js → chunk-3em5wd2y.js} +25 -6
- package/dist/cli/{chunk-jts8mvcz.js.map → chunk-3em5wd2y.js.map} +3 -3
- package/dist/cli/{chunk-s1p84fyh.js → chunk-5f86nr5m.js} +63 -22
- package/dist/cli/chunk-5f86nr5m.js.map +11 -0
- package/dist/cli/{chunk-2hn4b8z7.js → chunk-5m5nmvyq.js} +170 -76
- package/dist/cli/chunk-5m5nmvyq.js.map +13 -0
- package/dist/cli/{chunk-epjnccmv.js → chunk-5xvm6tfj.js} +18 -15
- package/dist/cli/chunk-5xvm6tfj.js.map +10 -0
- package/dist/cli/{chunk-fz5wtpmh.js → chunk-6dsbexzp.js} +18 -15
- package/dist/cli/chunk-6dsbexzp.js.map +10 -0
- package/dist/cli/{chunk-vtk4a6dg.js → chunk-8ktnccpt.js} +1 -1
- package/dist/cli/{chunk-6hsn950k.js → chunk-9t7a85s3.js} +178 -48
- package/dist/cli/chunk-9t7a85s3.js.map +10 -0
- package/dist/cli/{chunk-fxypxtvm.js → chunk-a58773jm.js} +2 -2
- package/dist/cli/{chunk-mb2919y2.js → chunk-acanzt5p.js} +17 -6
- package/dist/cli/chunk-acanzt5p.js.map +10 -0
- package/dist/cli/{chunk-27g6wdth.js → chunk-akbpwfxc.js} +90 -26
- package/dist/cli/chunk-akbpwfxc.js.map +10 -0
- package/dist/cli/{chunk-wm7js3j9.js → chunk-b07cmahc.js} +2 -2
- package/dist/cli/{chunk-wgm7m9qk.js → chunk-c8chx29p.js} +179 -51
- package/dist/cli/chunk-c8chx29p.js.map +36 -0
- package/dist/cli/{chunk-qs4q5p4e.js → chunk-crgn1q09.js} +32 -14
- package/dist/cli/chunk-crgn1q09.js.map +10 -0
- package/dist/cli/chunk-e04dxsz1.js +39 -0
- package/dist/cli/chunk-e04dxsz1.js.map +10 -0
- package/dist/cli/{chunk-yt5n7ppj.js → chunk-ey84smr6.js} +17 -7
- package/dist/cli/chunk-ey84smr6.js.map +10 -0
- package/dist/cli/{chunk-f2z5v128.js → chunk-g4hq16wv.js} +14 -15
- package/dist/cli/{chunk-f2z5v128.js.map → chunk-g4hq16wv.js.map} +2 -2
- package/dist/cli/{chunk-fa25z98p.js → chunk-ga0pf4aj.js} +9 -8
- package/dist/cli/chunk-ga0pf4aj.js.map +11 -0
- package/dist/cli/{chunk-kpf8rrjc.js → chunk-hm3vjy5s.js} +109 -58
- package/dist/cli/chunk-hm3vjy5s.js.map +19 -0
- package/dist/cli/{chunk-fs23ddbb.js → chunk-j85vccga.js} +625 -750
- package/dist/cli/chunk-j85vccga.js.map +36 -0
- package/dist/cli/{chunk-ch6g3ar0.js → chunk-p3v96n38.js} +6 -6
- package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-p3v96n38.js.map} +3 -3
- package/dist/cli/{chunk-q5163e60.js → chunk-p73c0m7w.js} +21 -19
- package/dist/cli/chunk-p73c0m7w.js.map +11 -0
- package/dist/cli/{chunk-dh8cwk36.js → chunk-pehfxfta.js} +24 -9
- package/dist/cli/chunk-pehfxfta.js.map +10 -0
- package/dist/cli/{chunk-qkqwkpte.js → chunk-pv29h0wf.js} +3688 -1313
- package/dist/cli/chunk-pv29h0wf.js.map +190 -0
- package/dist/cli/{chunk-6vm74dry.js → chunk-q58y5e6a.js} +10 -10
- package/dist/cli/{chunk-6vm74dry.js.map → chunk-q58y5e6a.js.map} +3 -3
- package/dist/cli/{chunk-zxcczpyx.js → chunk-r20tn01b.js} +1 -1
- package/dist/cli/{chunk-m3vmjgmq.js → chunk-r9rcc4w7.js} +16 -8
- package/dist/cli/chunk-r9rcc4w7.js.map +10 -0
- package/dist/cli/{chunk-5shv93fd.js → chunk-tkacnehg.js} +2 -2
- package/dist/cli/{chunk-zxh4d9vy.js → chunk-tzmab476.js} +4 -4
- package/dist/cli/{chunk-yw7dm696.js → chunk-vg9r4eb9.js} +24 -11
- package/dist/cli/chunk-vg9r4eb9.js.map +14 -0
- package/dist/cli/{chunk-79jhk4py.js → chunk-wrr3j9w9.js} +260 -132
- package/dist/cli/chunk-wrr3j9w9.js.map +35 -0
- package/dist/cli/{chunk-6crbhc3x.js → chunk-yfyb25rh.js} +54 -27
- package/dist/cli/chunk-yfyb25rh.js.map +14 -0
- package/dist/cli/index.js +162 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +7 -0
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/link-headers.d.ts +8 -1
- package/dist/types/ai/openapi-components.d.ts +5 -2
- package/dist/types/ai/relative-links.d.ts +11 -4
- package/dist/types/ai/skills.d.ts +4 -1
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/ai/tar.d.ts +1 -3
- package/dist/types/analytics/databuddy.d.ts +43 -0
- package/dist/types/analytics/index.d.ts +4 -0
- package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
- package/dist/types/analytics/schema.d.ts +28 -0
- package/dist/types/astro/integration.d.ts +3 -2
- package/dist/types/cli/env.d.ts +5 -0
- package/dist/types/cli/init/scaffold.d.ts +19 -3
- package/dist/types/cli/init/starter-spec.d.ts +11 -0
- package/dist/types/core/base-path.d.ts +24 -1
- package/dist/types/core/config-input.d.ts +13 -11
- package/dist/types/core/config.d.ts +2 -2
- package/dist/types/core/directive-diagnostics.d.ts +12 -0
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/heading-markers.d.ts +5 -7
- package/dist/types/core/i18n-ui.d.ts +31 -0
- package/dist/types/core/i18n.d.ts +9 -1
- package/dist/types/core/last-modified.d.ts +10 -0
- package/dist/types/core/links.d.ts +3 -1
- package/dist/types/core/load-module.d.ts +10 -0
- package/dist/types/core/locale-links.d.ts +12 -2
- package/dist/types/core/meta.d.ts +13 -1
- package/dist/types/core/nav-diagnostics.d.ts +10 -0
- package/dist/types/core/navigation.d.ts +38 -0
- package/dist/types/core/ordering-prefix.d.ts +4 -0
- package/dist/types/core/safe-links.d.ts +3 -1
- package/dist/types/core/schema.d.ts +59 -13
- package/dist/types/core/sources/github-releases.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +38 -13
- package/dist/types/core/sources/normalize.d.ts +23 -2
- package/dist/types/core/sources/remote.d.ts +11 -1
- package/dist/types/core/sources/resolve.d.ts +12 -0
- package/dist/types/core/sources/types.d.ts +31 -0
- package/dist/types/core/sources/watch.d.ts +12 -5
- package/dist/types/core/standard-schema.d.ts +5 -0
- package/dist/types/core/types.d.ts +9 -0
- package/dist/types/deploy/adapters/node.d.ts +5 -2
- package/dist/types/deploy/adapters/types.d.ts +7 -0
- package/dist/types/deploy/artifacts.d.ts +6 -4
- package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
- package/dist/types/deploy/headers.d.ts +36 -7
- package/dist/types/deploy/node-headers.d.ts +43 -8
- package/dist/types/deploy/platforms/netlify.d.ts +27 -2
- package/dist/types/deploy/platforms/node.d.ts +6 -5
- package/dist/types/deploy/platforms/types.d.ts +15 -0
- package/dist/types/deploy/platforms/vercel.d.ts +3 -2
- package/dist/types/deploy/redirects.d.ts +31 -15
- package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
- package/dist/types/markdown/directives.d.ts +62 -0
- package/dist/types/markdown/features.d.ts +21 -0
- package/dist/types/markdown/mdast.d.ts +63 -0
- package/dist/types/openapi/asyncapi.d.ts +4 -2
- package/dist/types/openapi/model.d.ts +20 -6
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +20 -9
- package/docs/08-faq.mdx +10 -3
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +7 -5
- package/docs/cli/audit.mdx +19 -3
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +4 -1
- package/docs/cli/translate.mdx +4 -4
- package/docs/cli/version.mdx +1 -1
- package/docs/configuration/analytics.mdx +42 -2
- package/docs/configuration/assistant.mdx +1 -1
- package/docs/configuration/customization.mdx +6 -3
- package/docs/configuration/index.mdx +5 -3
- package/docs/configuration/search.mdx +2 -2
- package/docs/content/components.mdx +2 -2
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +3 -1
- package/docs/content/index.mdx +8 -4
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +7 -3
- package/docs/content/navigation.mdx +29 -4
- package/docs/content/sources.mdx +18 -16
- package/docs/content/syntax.mdx +14 -0
- package/docs/content/versioning.mdx +2 -1
- package/docs/discoverability/agent-discovery.mdx +22 -8
- package/docs/discoverability/index.mdx +4 -3
- package/docs/discoverability/llms-txt.mdx +2 -5
- package/docs/discoverability/markdown.mdx +6 -4
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +3 -2
- package/docs/discoverability/open-graph.mdx +8 -4
- package/docs/discoverability/rss.mdx +4 -2
- package/docs/references/asyncapi.mdx +2 -2
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/openapi.mdx +6 -4
- package/package.json +1 -1
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +6 -6
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +3 -3
- package/skills/blume-migrate/references/monorepo.md +1 -1
- package/skills/blume-migrate/references/nextra.md +2 -2
- package/skills/blume-migrate/references/starlight.md +5 -5
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +9 -4
- package/skills/blume-update-docs/references/audit-checklist.md +1 -1
- package/src/ai/agent-readability.ts +2 -2
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/ai-catalog.ts +6 -2
- package/src/ai/api/handlers.ts +2 -2
- package/src/ai/api/spec.ts +17 -4
- package/src/ai/api-catalog.ts +13 -3
- package/src/ai/ask-context.ts +14 -2
- package/src/ai/ask-data.ts +26 -12
- package/src/ai/changelog-markdown.ts +2 -2
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/link-headers.ts +22 -8
- package/src/ai/llms.ts +22 -10
- package/src/ai/markdown.ts +23 -11
- package/src/ai/mcp/discovery.ts +2 -2
- package/src/ai/mcp/query.ts +2 -2
- package/src/ai/mcp/server.ts +80 -9
- package/src/ai/openapi-components.ts +22 -6
- package/src/ai/relative-links.ts +99 -15
- package/src/ai/serializers.ts +2 -1
- package/src/ai/skills.ts +14 -1
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/tar.ts +139 -12
- package/src/ai/visibility.ts +45 -14
- package/src/analytics/databuddy.ts +67 -0
- package/src/analytics/head.ts +8 -0
- package/src/analytics/index.ts +7 -0
- package/src/analytics/one-dollar-stats.ts +86 -0
- package/src/analytics/posthog.ts +21 -3
- package/src/analytics/schema.ts +4 -0
- package/src/astro/generate.ts +72 -28
- package/src/astro/include-hmr.ts +31 -12
- package/src/astro/include-refresh.ts +19 -8
- package/src/astro/integration.ts +108 -14
- package/src/astro/runtime-modules.ts +28 -13
- package/src/astro/templates.ts +139 -57
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +25 -5
- package/src/audit/checks/content.ts +20 -2
- package/src/audit/checks/i18n.ts +46 -8
- package/src/audit/checks/indexability.ts +39 -19
- package/src/audit/checks/links.ts +22 -1
- package/src/audit/checks/llms.ts +6 -3
- package/src/audit/checks/network.ts +3 -1
- package/src/audit/checks/og-image.ts +10 -0
- package/src/audit/checks/robots.ts +6 -1
- package/src/audit/checks/sitemap.ts +56 -31
- package/src/audit/checks/social.ts +21 -2
- package/src/audit/crawl.ts +88 -15
- package/src/audit/graph.ts +3 -1
- package/src/audit/report.ts +54 -17
- package/src/audit/run.ts +13 -9
- package/src/audit/snapshot.ts +5 -0
- package/src/audit/types.ts +18 -0
- package/src/audit/url.ts +37 -6
- package/src/cli/args.ts +32 -0
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +11 -1
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/doctor.ts +3 -1
- package/src/cli/commands/eval.ts +20 -18
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +18 -18
- package/src/cli/commands/upgrade.ts +11 -0
- package/src/cli/commands/validate.ts +3 -1
- package/src/cli/dev-lock.ts +157 -37
- package/src/cli/eject-scripts.ts +32 -7
- package/src/cli/env.ts +12 -1
- package/src/cli/init/scaffold.ts +117 -11
- package/src/cli/init/starter-spec.ts +235 -0
- package/src/cli/report-format.ts +11 -6
- package/src/components/colors.ts +19 -0
- package/src/components/content/AccordionItem.astro +26 -22
- package/src/components/content/Badge.astro +7 -12
- package/src/components/content/Card.astro +2 -2
- package/src/components/content/Component.astro +11 -5
- package/src/components/content/Expandable.astro +5 -1
- package/src/components/content/Frame.astro +2 -7
- package/src/components/content/GithubInfo.astro +12 -2
- package/src/components/content/Prompt.astro +2 -7
- package/src/components/content/Tab.astro +0 -1
- package/src/components/content/Tabs.astro +58 -5
- package/src/components/content/Tile.astro +1 -1
- package/src/components/content/Tooltip.astro +69 -7
- package/src/components/content/Tree.astro +7 -2
- package/src/components/content/TypeTable.astro +10 -5
- package/src/components/content/Update.astro +8 -2
- package/src/components/content/auto-type-table.ts +4 -1
- package/src/components/content/badge-color.ts +20 -0
- package/src/components/content/base-href.ts +14 -22
- package/src/components/content/inline-markdown.ts +27 -7
- package/src/components/copy-feedback.ts +35 -8
- package/src/components/islands/assistant.tsx +37 -6
- package/src/components/islands/base-path.ts +47 -10
- package/src/components/islands/hooks.ts +42 -21
- package/src/components/islands/webmcp.ts +16 -10
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Breadcrumbs.astro +5 -2
- package/src/components/layout/DiscoveryLinks.astro +9 -5
- package/src/components/layout/Header.astro +23 -10
- package/src/components/layout/LanguageSwitcher.astro +2 -2
- package/src/components/layout/Logo.astro +5 -0
- package/src/components/layout/NavSelector.astro +8 -3
- package/src/components/layout/NavTabMenu.astro +133 -0
- package/src/components/layout/NavTree.astro +31 -12
- package/src/components/layout/NavTreeCache.astro +5 -2
- package/src/components/layout/NavTreeScript.astro +45 -5
- package/src/components/layout/PageActions.astro +4 -3
- package/src/components/layout/PageLayout.astro +28 -13
- package/src/components/layout/Pagination.astro +3 -3
- package/src/components/layout/ReferenceLayout.astro +4 -1
- package/src/components/layout/RootLayout.astro +25 -12
- package/src/components/layout/Search.astro +38 -14
- package/src/components/layout/VersionBanner.astro +2 -2
- package/src/components/layout/analytics-client.ts +14 -0
- package/src/components/layout/toc-active.ts +41 -0
- package/src/components/layout/toc-element.ts +8 -14
- package/src/components/openapi/ApiTagOperations.astro +2 -2
- package/src/components/openapi/AsyncApiOperation.astro +7 -4
- package/src/components/openapi/GraphqlChip.astro +2 -2
- package/src/components/openapi/GraphqlType.astro +11 -3
- package/src/components/openapi/MessageComposer.astro +1 -1
- package/src/components/openapi/Operation.astro +23 -5
- package/src/components/openapi/PanelTabs.astro +4 -1
- package/src/components/openapi/Playground.astro +8 -2
- package/src/components/openapi/RequestPanel.astro +13 -6
- package/src/components/openapi/SchemaProperty.astro +11 -33
- package/src/components/openapi/SchemaTable.astro +34 -52
- package/src/components/openapi/async.ts +38 -6
- package/src/components/openapi/helpers.ts +100 -12
- package/src/components/openapi/message-composer.ts +14 -1
- package/src/components/openapi/message-model.ts +12 -2
- package/src/components/openapi/message.ts +21 -3
- package/src/components/openapi/operation-model.ts +119 -17
- package/src/components/openapi/panel.ts +31 -5
- package/src/components/openapi/param-style.ts +181 -0
- package/src/components/openapi/playground-client.ts +110 -23
- package/src/components/openapi/playground-schema.ts +25 -6
- package/src/components/openapi/request.ts +192 -26
- package/src/components/openapi/schema-tree.ts +209 -0
- package/src/components/openapi/snippets.ts +113 -19
- package/src/components/openapi/validate-json.ts +1 -1
- package/src/components/openapi/ws-client.ts +18 -2
- package/src/core/base-path.ts +69 -8
- package/src/core/config-input.ts +13 -11
- package/src/core/config.ts +18 -4
- package/src/core/diagnostics.ts +219 -30
- package/src/core/directive-diagnostics.ts +99 -0
- package/src/core/frontmatter.ts +21 -18
- package/src/core/graph.ts +120 -11
- package/src/core/heading-markers.ts +5 -18
- package/src/core/i18n-ui.ts +39 -2
- package/src/core/i18n.ts +44 -5
- package/src/core/last-modified.ts +25 -3
- package/src/core/links.ts +7 -4
- package/src/core/load-module.ts +20 -0
- package/src/core/locale-links.ts +22 -18
- package/src/core/manifest.ts +3 -2
- package/src/core/meta.ts +89 -12
- package/src/core/nav-diagnostics.ts +56 -1
- package/src/core/navigation.ts +272 -83
- package/src/core/ordering-prefix.ts +27 -0
- package/src/core/project-graph.ts +50 -6
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +94 -18
- package/src/core/sources/assets.ts +83 -41
- package/src/core/sources/contentful-rich-text.ts +28 -20
- package/src/core/sources/contentful.ts +25 -12
- package/src/core/sources/filesystem.ts +25 -3
- package/src/core/sources/github-releases.ts +131 -11
- package/src/core/sources/lexical.ts +30 -20
- package/src/core/sources/lower.ts +276 -56
- package/src/core/sources/mdx-remote.ts +52 -16
- package/src/core/sources/normalize.ts +456 -119
- package/src/core/sources/notion.ts +77 -34
- package/src/core/sources/obsidian.ts +40 -9
- package/src/core/sources/payload.ts +1 -0
- package/src/core/sources/portable-text.ts +85 -49
- package/src/core/sources/remote.ts +18 -2
- package/src/core/sources/resolve.ts +52 -33
- package/src/core/sources/sanity.ts +1 -0
- package/src/core/sources/strapi-blocks.ts +28 -19
- package/src/core/sources/strapi.ts +1 -0
- package/src/core/sources/types.ts +31 -0
- package/src/core/sources/watch.ts +20 -7
- package/src/core/standard-schema.ts +10 -6
- package/src/core/types.ts +9 -0
- package/src/core/ui-packs/ar.ts +13 -0
- package/src/core/ui-packs/bg.ts +13 -0
- package/src/core/ui-packs/bn.ts +13 -0
- package/src/core/ui-packs/ca.ts +13 -0
- package/src/core/ui-packs/cs.ts +13 -0
- package/src/core/ui-packs/da.ts +13 -0
- package/src/core/ui-packs/de.ts +13 -0
- package/src/core/ui-packs/el.ts +13 -0
- package/src/core/ui-packs/es.ts +13 -0
- package/src/core/ui-packs/fa.ts +13 -0
- package/src/core/ui-packs/fi.ts +13 -0
- package/src/core/ui-packs/fr.ts +13 -0
- package/src/core/ui-packs/he.ts +13 -0
- package/src/core/ui-packs/hi.ts +13 -0
- package/src/core/ui-packs/hr.ts +13 -0
- package/src/core/ui-packs/hu.ts +13 -0
- package/src/core/ui-packs/id.ts +13 -0
- package/src/core/ui-packs/it.ts +13 -0
- package/src/core/ui-packs/ja.ts +13 -0
- package/src/core/ui-packs/ko.ts +13 -0
- package/src/core/ui-packs/nl.ts +13 -0
- package/src/core/ui-packs/no.ts +13 -0
- package/src/core/ui-packs/pl.ts +13 -0
- package/src/core/ui-packs/pt-br.ts +13 -0
- package/src/core/ui-packs/pt.ts +13 -0
- package/src/core/ui-packs/ro.ts +13 -0
- package/src/core/ui-packs/ru.ts +13 -0
- package/src/core/ui-packs/sk.ts +13 -0
- package/src/core/ui-packs/sr.ts +13 -0
- package/src/core/ui-packs/sv.ts +13 -0
- package/src/core/ui-packs/th.ts +13 -0
- package/src/core/ui-packs/tr.ts +13 -0
- package/src/core/ui-packs/uk.ts +13 -0
- package/src/core/ui-packs/vi.ts +13 -0
- package/src/core/ui-packs/zh-tw.ts +13 -0
- package/src/core/ui-packs/zh.ts +13 -0
- package/src/core/version-cut.ts +69 -17
- package/src/core/versions.ts +4 -1
- package/src/deploy/adapters/node.ts +5 -2
- package/src/deploy/adapters/registry.ts +2 -1
- package/src/deploy/adapters/types.ts +13 -1
- package/src/deploy/artifacts.ts +52 -11
- package/src/deploy/cloudflare-negotiation.ts +27 -16
- package/src/deploy/headers.ts +75 -55
- package/src/deploy/node-headers.ts +148 -27
- package/src/deploy/platforms/cloudflare.ts +13 -3
- package/src/deploy/platforms/netlify.ts +83 -5
- package/src/deploy/platforms/node.ts +8 -5
- package/src/deploy/platforms/static.ts +2 -0
- package/src/deploy/platforms/types.ts +15 -0
- package/src/deploy/platforms/vercel.ts +10 -3
- package/src/deploy/redirects.ts +68 -21
- package/src/deploy/robots.ts +2 -2
- package/src/deploy/rss.ts +4 -3
- package/src/deploy/sitemap.ts +7 -5
- package/src/deploy/vercel-negotiation.ts +35 -3
- package/src/eval/agents.ts +10 -2
- package/src/eval/run.ts +25 -0
- package/src/markdown/base-links.ts +74 -29
- package/src/markdown/directives.ts +242 -36
- package/src/markdown/features.ts +17 -0
- package/src/markdown/index.ts +13 -9
- package/src/markdown/mdast.ts +5 -2
- package/src/markdown/relative-links.ts +15 -27
- package/src/markdown/route-snapshot.ts +37 -0
- package/src/og/card.ts +149 -9
- package/src/og/derive.ts +156 -5
- package/src/og/index.ts +1 -0
- package/src/openapi/asyncapi.ts +4 -2
- package/src/openapi/graphql-build.ts +28 -2
- package/src/openapi/model.ts +99 -27
- package/src/openapi/proxy.ts +63 -10
- package/src/openapi/render-mdx.ts +51 -3
- package/src/registry/eject.ts +297 -43
- package/src/search/adapters/version-scope.ts +30 -0
- package/src/search/documents.ts +89 -27
- package/src/search/popular.ts +2 -1
- package/src/search/sync/algolia.ts +36 -2
- package/src/seo/jsonld.ts +7 -3
- package/src/sources/registry.ts +5 -0
- package/src/theme/entry.ts +11 -4
- package/src/translate/agents.ts +6 -1
- package/src/translate/ledger.ts +26 -3
- package/src/translate/meta.ts +76 -24
- package/src/translate/run.ts +14 -8
- package/src/translate/validate.ts +14 -2
- package/src/translate/work-list.ts +91 -19
- package/src/upgrade/upgrade.ts +36 -4
- package/dist/cli/chunk-27g6wdth.js.map +0 -10
- package/dist/cli/chunk-2hn4b8z7.js.map +0 -12
- package/dist/cli/chunk-6crbhc3x.js.map +0 -14
- package/dist/cli/chunk-6hsn950k.js.map +0 -10
- package/dist/cli/chunk-79jhk4py.js.map +0 -35
- package/dist/cli/chunk-82bbrxdn.js +0 -51
- package/dist/cli/chunk-82bbrxdn.js.map +0 -10
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-ce574jw2.js +0 -23
- package/dist/cli/chunk-ce574jw2.js.map +0 -10
- package/dist/cli/chunk-dh8cwk36.js.map +0 -10
- package/dist/cli/chunk-epjnccmv.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-fs23ddbb.js.map +0 -35
- package/dist/cli/chunk-fz5wtpmh.js.map +0 -10
- package/dist/cli/chunk-jwyddg7y.js.map +0 -15
- package/dist/cli/chunk-kpf8rrjc.js.map +0 -19
- package/dist/cli/chunk-m3vmjgmq.js.map +0 -10
- package/dist/cli/chunk-mb2919y2.js.map +0 -10
- package/dist/cli/chunk-q5163e60.js.map +0 -11
- package/dist/cli/chunk-qkqwkpte.js.map +0 -182
- package/dist/cli/chunk-qs4q5p4e.js.map +0 -10
- package/dist/cli/chunk-s1p84fyh.js.map +0 -10
- package/dist/cli/chunk-wgm7m9qk.js.map +0 -36
- package/dist/cli/chunk-yt5n7ppj.js.map +0 -10
- package/dist/cli/chunk-yw7dm696.js.map +0 -14
- /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-2eytanqx.js.map} +0 -0
- /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-2z928egk.js.map} +0 -0
- /package/dist/cli/{chunk-ah61y8py.js.map → chunk-364znk6q.js.map} +0 -0
- /package/dist/cli/{chunk-vtk4a6dg.js.map → chunk-8ktnccpt.js.map} +0 -0
- /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-a58773jm.js.map} +0 -0
- /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-b07cmahc.js.map} +0 -0
- /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-r20tn01b.js.map} +0 -0
- /package/dist/cli/{chunk-5shv93fd.js.map → chunk-tkacnehg.js.map} +0 -0
- /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-tzmab476.js.map} +0 -0
|
@@ -19,28 +19,27 @@ import {
|
|
|
19
19
|
writeAgentReport,
|
|
20
20
|
fixPrompt,
|
|
21
21
|
launchInstalledAgent
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-1d7ve1dm.js";
|
|
23
23
|
import {
|
|
24
|
+
routeSetFor,
|
|
24
25
|
frontmatter_default,
|
|
25
26
|
gradeExternal,
|
|
26
27
|
probeAll,
|
|
28
|
+
applyBaseToAstroRedirects,
|
|
27
29
|
deployPlatform
|
|
28
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-pv29h0wf.js";
|
|
29
31
|
import {
|
|
30
32
|
normalizeBasePath,
|
|
31
33
|
normalizePath,
|
|
32
|
-
withBasePath,
|
|
33
34
|
stripBasePath
|
|
34
|
-
} from "./chunk-
|
|
35
|
-
import {
|
|
36
|
-
deployStaticDir
|
|
37
|
-
} from "./chunk-82bbrxdn.js";
|
|
35
|
+
} from "./chunk-3em5wd2y.js";
|
|
38
36
|
import {
|
|
37
|
+
deployStaticDir,
|
|
39
38
|
examplesRouteBase
|
|
40
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-5m5nmvyq.js";
|
|
41
40
|
import {
|
|
42
41
|
scanProject
|
|
43
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-j85vccga.js";
|
|
44
43
|
|
|
45
44
|
// src/cli/commands/audit.ts
|
|
46
45
|
import { defineCommand } from "citty";
|
|
@@ -71,6 +70,7 @@ var serverRoutes = (context) => {
|
|
|
71
70
|
return mcp?.enabled ? [normalizePath(mcp.route)] : [];
|
|
72
71
|
};
|
|
73
72
|
var isServed = (context, path) => context.byUrl.has(path) || context.files.has(path) || context.files.has(`${path}/index.html`) || serverRoutes(context).includes(path);
|
|
73
|
+
var underBase = (deployBase, path) => !deployBase || path === deployBase || path.startsWith(`${deployBase}/`);
|
|
74
74
|
var NON_HTTP_SCHEME = /^(?!https?:)[a-z][a-z0-9+.-]*:/iu;
|
|
75
75
|
var decodePath = (path) => {
|
|
76
76
|
try {
|
|
@@ -79,6 +79,14 @@ var decodePath = (path) => {
|
|
|
79
79
|
return path;
|
|
80
80
|
}
|
|
81
81
|
};
|
|
82
|
+
var isHttpUrl = (input) => {
|
|
83
|
+
try {
|
|
84
|
+
const { protocol } = new URL(input);
|
|
85
|
+
return protocol === "http:" || protocol === "https:";
|
|
86
|
+
} catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
82
90
|
var siteOrigin = (site) => {
|
|
83
91
|
if (!site) {
|
|
84
92
|
return null;
|
|
@@ -106,10 +114,14 @@ var resolveHref = (pageUrl, href, origin, deployBase = "") => {
|
|
|
106
114
|
return { kind: "ignored" };
|
|
107
115
|
}
|
|
108
116
|
if (origin && parsed.origin === origin) {
|
|
117
|
+
const served = decodePath(parsed.pathname);
|
|
118
|
+
if (!underBase(deployBase, served)) {
|
|
119
|
+
return { kind: "outside-base", path: normalizePath(served) };
|
|
120
|
+
}
|
|
109
121
|
return {
|
|
110
122
|
hash: parsed.hash.slice(1),
|
|
111
123
|
kind: "self-origin",
|
|
112
|
-
path: normalizePath(stripBasePath(deployBase,
|
|
124
|
+
path: normalizePath(stripBasePath(deployBase, served))
|
|
113
125
|
};
|
|
114
126
|
}
|
|
115
127
|
return { kind: "external", url: parsed.toString() };
|
|
@@ -121,14 +133,19 @@ var resolveHref = (pageUrl, href, origin, deployBase = "") => {
|
|
|
121
133
|
} catch {
|
|
122
134
|
return { kind: "ignored" };
|
|
123
135
|
}
|
|
136
|
+
const served = decodePath(resolved.pathname);
|
|
137
|
+
if (target.startsWith("/") && !underBase(deployBase, served)) {
|
|
138
|
+
return { kind: "outside-base", path: normalizePath(served) };
|
|
139
|
+
}
|
|
124
140
|
return {
|
|
125
141
|
hash: resolved.hash.slice(1),
|
|
126
142
|
kind: "internal",
|
|
127
|
-
path: normalizePath(stripBasePath(deployBase,
|
|
143
|
+
path: normalizePath(stripBasePath(deployBase, served))
|
|
128
144
|
};
|
|
129
145
|
};
|
|
130
146
|
|
|
131
147
|
// src/audit/checks/assets.ts
|
|
148
|
+
var VERCEL_IMAGE_ENDPOINT = "/_vercel/image";
|
|
132
149
|
var formatBytes = (bytes) => bytes < 1024 * 1024 ? `${Math.round(bytes / 1024)} kB` : `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
133
150
|
var resolveAsset = (context, page, asset, missingId, kind, found) => {
|
|
134
151
|
if (asset.src.startsWith("http://")) {
|
|
@@ -139,10 +156,18 @@ var resolveAsset = (context, page, asset, missingId, kind, found) => {
|
|
|
139
156
|
return null;
|
|
140
157
|
}
|
|
141
158
|
const origin = siteOrigin(context.project.config.deployment.options.site);
|
|
142
|
-
const
|
|
159
|
+
const deployBase = normalizeBasePath(context.project.config.deployment.options.base);
|
|
160
|
+
const resolved = resolveHref(page.url, asset.src, origin, deployBase);
|
|
143
161
|
if (resolved.kind === "external" || resolved.kind === "ignored") {
|
|
144
162
|
return null;
|
|
145
163
|
}
|
|
164
|
+
if (resolved.path === VERCEL_IMAGE_ENDPOINT) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
if (resolved.kind === "outside-base") {
|
|
168
|
+
found.push(finding(missingId, pageSite(context, page), `Page references ${asset.src}, which is missing deployment.base (${deployBase}), so the deployed site does not serve it.`));
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
146
171
|
const bytes = context.files.get(resolved.path);
|
|
147
172
|
if (bytes === undefined) {
|
|
148
173
|
found.push(finding(missingId, pageSite(context, page), `Page references ${asset.src}, which is not in the build.`));
|
|
@@ -214,6 +239,9 @@ var frontmatterDate = (source) => {
|
|
|
214
239
|
return null;
|
|
215
240
|
}
|
|
216
241
|
};
|
|
242
|
+
var isGeneratedReference = (page) => page.route?.source.name === "openapi";
|
|
243
|
+
var GENERATED_TITLE_FIX = "This page is generated from an API spec, which titles it with the operation's `summary` (the spec's own title on the overview page) — rewrite it there.";
|
|
244
|
+
var GENERATED_DESCRIPTION_FIX = "This page is generated from an API spec, which describes it with the operation's `description` or `summary` (the spec's own description on the overview page) — rewrite it there.";
|
|
217
245
|
var titleChecks = (context, page) => {
|
|
218
246
|
const { titleMin, titleMax } = context.thresholds;
|
|
219
247
|
const [title] = page.titles;
|
|
@@ -229,7 +257,7 @@ var titleChecks = (context, page) => {
|
|
|
229
257
|
const width = stringWidth(title.replaceAll(WHITESPACE, " "));
|
|
230
258
|
if (width > titleMax || width < titleMin) {
|
|
231
259
|
const direction = width > titleMax ? "long" : "short";
|
|
232
|
-
found.push(finding("BLUME_AUDIT_TITLE_LENGTH", pageSite(context, page, ["title"]), `Title renders ${width} columns wide — too ${direction} (aim for ${titleMin}–${titleMax})
|
|
260
|
+
found.push(finding("BLUME_AUDIT_TITLE_LENGTH", pageSite(context, page, ["title"]), `Title renders ${width} columns wide — too ${direction} (aim for ${titleMin}–${titleMax}).`, isGeneratedReference(page) ? GENERATED_TITLE_FIX : undefined));
|
|
233
261
|
}
|
|
234
262
|
return found;
|
|
235
263
|
};
|
|
@@ -251,7 +279,7 @@ var descriptionChecks = (context, page) => {
|
|
|
251
279
|
const width = stringWidth(description.replaceAll(WHITESPACE, " "));
|
|
252
280
|
if (width > descriptionMax || width < descriptionMin) {
|
|
253
281
|
const direction = width > descriptionMax ? "long" : "short";
|
|
254
|
-
found.push(finding("BLUME_AUDIT_DESCRIPTION_LENGTH", pageSite(context, page, ["description"]), `Meta description renders ${width} columns wide — too ${direction} (aim for ${descriptionMin}–${descriptionMax})
|
|
282
|
+
found.push(finding("BLUME_AUDIT_DESCRIPTION_LENGTH", pageSite(context, page, ["description"]), `Meta description renders ${width} columns wide — too ${direction} (aim for ${descriptionMin}–${descriptionMax}).`, isGeneratedReference(page) ? GENERATED_DESCRIPTION_FIX : undefined));
|
|
255
283
|
}
|
|
256
284
|
return found;
|
|
257
285
|
};
|
|
@@ -467,6 +495,94 @@ var duplicateChecks = {
|
|
|
467
495
|
tier: "static"
|
|
468
496
|
};
|
|
469
497
|
|
|
498
|
+
// src/audit/checks/indexability.ts
|
|
499
|
+
var parseCanonical = (canonical) => {
|
|
500
|
+
try {
|
|
501
|
+
return new URL(canonical);
|
|
502
|
+
} catch {
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
var isArchivedLatestCanonical = (context, page, target) => {
|
|
507
|
+
const version = page.route?.version;
|
|
508
|
+
const archived = version ? context.project.config.versions?.archived.find((entry) => entry.id === version) : undefined;
|
|
509
|
+
const latestAlternate = page.route?.versionAlternates.find((alternate) => alternate.version === "");
|
|
510
|
+
return archived?.canonical === "latest" && latestAlternate !== undefined && normalizePath(latestAlternate.path) === target;
|
|
511
|
+
};
|
|
512
|
+
var canonicalChecks = (context, page) => {
|
|
513
|
+
const { site } = context.project.config.deployment.options;
|
|
514
|
+
const origin = siteOrigin(site);
|
|
515
|
+
if (ERROR_ROUTES.has(page.url)) {
|
|
516
|
+
return [];
|
|
517
|
+
}
|
|
518
|
+
if (!page.canonical) {
|
|
519
|
+
return site && page.indexable ? [
|
|
520
|
+
finding("BLUME_AUDIT_CANONICAL_MISSING", pageSite(context, page), "Page has no canonical URL.")
|
|
521
|
+
] : [];
|
|
522
|
+
}
|
|
523
|
+
const canonical = parseCanonical(page.canonical);
|
|
524
|
+
if (!canonical) {
|
|
525
|
+
return [
|
|
526
|
+
finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical "${page.canonical}" is not a valid absolute URL.`)
|
|
527
|
+
];
|
|
528
|
+
}
|
|
529
|
+
const found = [];
|
|
530
|
+
if (origin && canonical.origin !== origin) {
|
|
531
|
+
const sameHost = canonical.host === new URL(origin).host;
|
|
532
|
+
if (sameHost) {
|
|
533
|
+
found.push(finding("BLUME_AUDIT_CANONICAL_PROTOCOL_MISMATCH", pageSite(context, page, ["seo", "canonical"]), `Canonical uses ${canonical.protocol}// but the site is ${new URL(origin).protocol}//.`));
|
|
534
|
+
}
|
|
535
|
+
return found;
|
|
536
|
+
}
|
|
537
|
+
const target = normalizePath(stripBasePath(normalizeBasePath(context.project.config.deployment.options.base), decodePath(canonical.pathname)));
|
|
538
|
+
if (target === normalizePath(page.url)) {
|
|
539
|
+
return found;
|
|
540
|
+
}
|
|
541
|
+
const redirect = context.redirects.find((entry) => normalizePath(entry.from) === target);
|
|
542
|
+
if (redirect) {
|
|
543
|
+
found.push(finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical points at ${target}, which is a redirect to ${redirect.to}.`));
|
|
544
|
+
} else if (context.byUrl.has(target)) {
|
|
545
|
+
if (!(page.route?.fallback === true || isArchivedLatestCanonical(context, page, target))) {
|
|
546
|
+
found.push(finding("BLUME_AUDIT_CANONICAL_NOT_SELF", pageSite(context, page, ["seo", "canonical"]), `Page declares ${target} as its canonical, so it will not be indexed itself.`));
|
|
547
|
+
}
|
|
548
|
+
} else {
|
|
549
|
+
found.push(finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical points at ${target}, which is not a page on this site.`));
|
|
550
|
+
}
|
|
551
|
+
return found;
|
|
552
|
+
};
|
|
553
|
+
var indexabilityChecks = {
|
|
554
|
+
category: "indexability",
|
|
555
|
+
run(context) {
|
|
556
|
+
const found = [];
|
|
557
|
+
if (!context.project.config.deployment.options.site) {
|
|
558
|
+
const { deployment } = context.project.config;
|
|
559
|
+
const site = {
|
|
560
|
+
file: context.project.context.configFile ?? undefined,
|
|
561
|
+
url: "/"
|
|
562
|
+
};
|
|
563
|
+
found.push(deployPlatform(deployment).env ? finding("BLUME_AUDIT_SITE_INFERRED_AT_DEPLOY", site, `deployment.site is not set in this build — on ${deployment.kind} it is inferred from the platform env at deploy time, so canonical URLs, Open Graph images, and the sitemap are only missing from this local artifact.`) : finding("BLUME_AUDIT_SITE_NOT_SET", site, "deployment.site is not set, so no canonical URLs, Open Graph images, or sitemap can be generated."));
|
|
564
|
+
}
|
|
565
|
+
for (const page of context.pages) {
|
|
566
|
+
found.push(...canonicalChecks(context, page));
|
|
567
|
+
if (page.robots && !page.indexable && !ERROR_ROUTES.has(page.url)) {
|
|
568
|
+
found.push(finding("BLUME_AUDIT_ROBOTS_META_UNEXPECTED", pageSite(context, page, ["noindex"]), `Page declares robots "${page.robots}" and will not be indexed.`));
|
|
569
|
+
if (!page.indexable && page.canonical) {
|
|
570
|
+
found.push(finding("BLUME_AUDIT_CANONICAL_ON_NOINDEX", pageSite(context, page, ["noindex"]), `Page is noindex but declares ${page.canonical} as its canonical.`));
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
if (page.route?.draft) {
|
|
574
|
+
found.push(finding("BLUME_AUDIT_DRAFT_PAGE_PUBLISHED", pageSite(context, page, ["draft"]), `${page.url} is marked draft in its front matter but is in the build.`));
|
|
575
|
+
}
|
|
576
|
+
if (page.bytes > context.thresholds.maxHtmlBytes) {
|
|
577
|
+
const mb = (page.bytes / 1024 / 1024).toFixed(1);
|
|
578
|
+
found.push(finding("BLUME_AUDIT_HTML_TOO_LARGE", pageSite(context, page), `Page HTML is ${mb} MB — past Googlebot's 2 MB limit, the rest is not crawled.`));
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return found;
|
|
582
|
+
},
|
|
583
|
+
tier: "static"
|
|
584
|
+
};
|
|
585
|
+
|
|
470
586
|
// src/audit/checks/i18n.ts
|
|
471
587
|
var deployBaseOf = (context) => normalizeBasePath(context.project.config.deployment.options.base);
|
|
472
588
|
var X_DEFAULT = "x-default";
|
|
@@ -480,11 +596,22 @@ var isValidBcp47 = (tag) => {
|
|
|
480
596
|
};
|
|
481
597
|
var alternatePath = (href, deployBase) => {
|
|
482
598
|
try {
|
|
483
|
-
return normalizePath(stripBasePath(deployBase, new URL(href).pathname));
|
|
599
|
+
return normalizePath(stripBasePath(deployBase, decodePath(new URL(href).pathname)));
|
|
484
600
|
} catch {
|
|
485
601
|
return null;
|
|
486
602
|
}
|
|
487
603
|
};
|
|
604
|
+
var isFallbackCopy = (page) => page.route?.fallback === true;
|
|
605
|
+
var canonicalizesElsewhere = (context, target, deployBase) => {
|
|
606
|
+
if (!target.canonical) {
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
const canonical = alternatePath(target.canonical, deployBase);
|
|
610
|
+
if (canonical === normalizePath(target.url)) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
return !(canonical !== null && isArchivedLatestCanonical(context, target, canonical));
|
|
614
|
+
};
|
|
488
615
|
var langChecks = (context, page) => {
|
|
489
616
|
if (!page.lang) {
|
|
490
617
|
return [
|
|
@@ -521,7 +648,7 @@ var hreflangChecks = (context, page) => {
|
|
|
521
648
|
found.push(finding("BLUME_AUDIT_HREFLANG_BAD_TARGET", pageSite(context, page), `hreflang="${alternate.lang}" points at ${path}, which redirects to ${redirect.to}.`));
|
|
522
649
|
} else if (!target) {
|
|
523
650
|
found.push(finding("BLUME_AUDIT_HREFLANG_BAD_TARGET", pageSite(context, page), `hreflang="${alternate.lang}" points at ${path}, which the build does not serve.`));
|
|
524
|
-
} else if (
|
|
651
|
+
} else if (canonicalizesElsewhere(context, target, deployBase)) {
|
|
525
652
|
found.push(finding("BLUME_AUDIT_HREFLANG_BAD_TARGET", pageSite(context, page), `hreflang="${alternate.lang}" points at ${path}, which canonicalizes elsewhere.`));
|
|
526
653
|
}
|
|
527
654
|
}
|
|
@@ -547,6 +674,9 @@ var returnTagChecks = (context) => {
|
|
|
547
674
|
const found = [];
|
|
548
675
|
const deployBase = deployBaseOf(context);
|
|
549
676
|
for (const page of context.pages) {
|
|
677
|
+
if (isFallbackCopy(page)) {
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
550
680
|
for (const alternate of page.hreflang) {
|
|
551
681
|
if (alternate.lang === X_DEFAULT) {
|
|
552
682
|
continue;
|
|
@@ -573,7 +703,7 @@ var i18nChecks = {
|
|
|
573
703
|
const found = [];
|
|
574
704
|
for (const page of context.pages) {
|
|
575
705
|
found.push(...langChecks(context, page));
|
|
576
|
-
if (page.hreflang.length > 0) {
|
|
706
|
+
if (page.hreflang.length > 0 && !isFallbackCopy(page)) {
|
|
577
707
|
found.push(...hreflangChecks(context, page));
|
|
578
708
|
}
|
|
579
709
|
}
|
|
@@ -583,92 +713,6 @@ var i18nChecks = {
|
|
|
583
713
|
tier: "static"
|
|
584
714
|
};
|
|
585
715
|
|
|
586
|
-
// src/audit/checks/indexability.ts
|
|
587
|
-
var parseCanonical = (canonical) => {
|
|
588
|
-
try {
|
|
589
|
-
return new URL(canonical);
|
|
590
|
-
} catch {
|
|
591
|
-
return null;
|
|
592
|
-
}
|
|
593
|
-
};
|
|
594
|
-
var canonicalChecks = (context, page) => {
|
|
595
|
-
const { site } = context.project.config.deployment.options;
|
|
596
|
-
const origin = siteOrigin(site);
|
|
597
|
-
if (ERROR_ROUTES.has(page.url)) {
|
|
598
|
-
return [];
|
|
599
|
-
}
|
|
600
|
-
if (!page.canonical) {
|
|
601
|
-
return site ? [
|
|
602
|
-
finding("BLUME_AUDIT_CANONICAL_MISSING", pageSite(context, page), "Page has no canonical URL.")
|
|
603
|
-
] : [];
|
|
604
|
-
}
|
|
605
|
-
const canonical = parseCanonical(page.canonical);
|
|
606
|
-
if (!canonical) {
|
|
607
|
-
return [
|
|
608
|
-
finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical "${page.canonical}" is not a valid absolute URL.`)
|
|
609
|
-
];
|
|
610
|
-
}
|
|
611
|
-
const found = [];
|
|
612
|
-
if (origin && canonical.origin !== origin) {
|
|
613
|
-
const sameHost = canonical.host === new URL(origin).host;
|
|
614
|
-
if (sameHost) {
|
|
615
|
-
found.push(finding("BLUME_AUDIT_CANONICAL_PROTOCOL_MISMATCH", pageSite(context, page, ["seo", "canonical"]), `Canonical uses ${canonical.protocol}// but the site is ${new URL(origin).protocol}//.`));
|
|
616
|
-
}
|
|
617
|
-
return found;
|
|
618
|
-
}
|
|
619
|
-
const target = normalizePath(stripBasePath(normalizeBasePath(context.project.config.deployment.options.base), decodePath(canonical.pathname)));
|
|
620
|
-
if (target === normalizePath(page.url)) {
|
|
621
|
-
return found;
|
|
622
|
-
}
|
|
623
|
-
const redirect = context.redirects.find((entry) => normalizePath(entry.from) === target);
|
|
624
|
-
if (redirect) {
|
|
625
|
-
found.push(finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical points at ${target}, which is a redirect to ${redirect.to}.`));
|
|
626
|
-
} else if (context.byUrl.has(target)) {
|
|
627
|
-
const version = page.route?.version;
|
|
628
|
-
const archived = version ? context.project.config.versions?.archived.find((entry) => entry.id === version) : undefined;
|
|
629
|
-
const latestAlternate = page.route?.versionAlternates.find((alternate) => alternate.version === "");
|
|
630
|
-
const intentional = archived?.canonical === "latest" && latestAlternate !== undefined && normalizePath(latestAlternate.path) === target;
|
|
631
|
-
if (!intentional) {
|
|
632
|
-
found.push(finding("BLUME_AUDIT_CANONICAL_NOT_SELF", pageSite(context, page, ["seo", "canonical"]), `Page declares ${target} as its canonical, so it will not be indexed itself.`));
|
|
633
|
-
}
|
|
634
|
-
} else {
|
|
635
|
-
found.push(finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical points at ${target}, which is not a page on this site.`));
|
|
636
|
-
}
|
|
637
|
-
return found;
|
|
638
|
-
};
|
|
639
|
-
var indexabilityChecks = {
|
|
640
|
-
category: "indexability",
|
|
641
|
-
run(context) {
|
|
642
|
-
const found = [];
|
|
643
|
-
if (!context.project.config.deployment.options.site) {
|
|
644
|
-
const { deployment } = context.project.config;
|
|
645
|
-
const site = {
|
|
646
|
-
file: context.project.context.configFile ?? undefined,
|
|
647
|
-
url: "/"
|
|
648
|
-
};
|
|
649
|
-
found.push(deployPlatform(deployment).env ? finding("BLUME_AUDIT_SITE_INFERRED_AT_DEPLOY", site, `deployment.site is not set in this build — on ${deployment.kind} it is inferred from the platform env at deploy time, so canonical URLs, Open Graph images, and the sitemap are only missing from this local artifact.`) : finding("BLUME_AUDIT_SITE_NOT_SET", site, "deployment.site is not set, so no canonical URLs, Open Graph images, or sitemap can be generated."));
|
|
650
|
-
}
|
|
651
|
-
for (const page of context.pages) {
|
|
652
|
-
found.push(...canonicalChecks(context, page));
|
|
653
|
-
if (page.robots && !page.indexable && !ERROR_ROUTES.has(page.url)) {
|
|
654
|
-
found.push(finding("BLUME_AUDIT_ROBOTS_META_UNEXPECTED", pageSite(context, page, ["noindex"]), `Page declares robots "${page.robots}" and will not be indexed.`));
|
|
655
|
-
if (!page.indexable && page.canonical) {
|
|
656
|
-
found.push(finding("BLUME_AUDIT_CANONICAL_ON_NOINDEX", pageSite(context, page, ["noindex"]), `Page is noindex but declares ${page.canonical} as its canonical.`));
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
if (page.route?.draft) {
|
|
660
|
-
found.push(finding("BLUME_AUDIT_DRAFT_PAGE_PUBLISHED", pageSite(context, page, ["draft"]), `${page.url} is marked draft in its front matter but is in the build.`));
|
|
661
|
-
}
|
|
662
|
-
if (page.bytes > context.thresholds.maxHtmlBytes) {
|
|
663
|
-
const mb = (page.bytes / 1024 / 1024).toFixed(1);
|
|
664
|
-
found.push(finding("BLUME_AUDIT_HTML_TOO_LARGE", pageSite(context, page), `Page HTML is ${mb} MB — past Googlebot's 2 MB limit, the rest is not crawled.`));
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return found;
|
|
668
|
-
},
|
|
669
|
-
tier: "static"
|
|
670
|
-
};
|
|
671
|
-
|
|
672
716
|
// src/audit/graph.ts
|
|
673
717
|
var add = (map, key, value) => {
|
|
674
718
|
const existing = map.get(key);
|
|
@@ -699,10 +743,11 @@ var buildGraph = (pages, origin, deployBase = "") => {
|
|
|
699
743
|
}
|
|
700
744
|
return graph;
|
|
701
745
|
};
|
|
702
|
-
var orphanPages = (pages, graph, homeUrl = "/") => pages.filter((page) => page.indexable && page.url !== "/" && page.url !== homeUrl && (graph.contentIn.get(page.url)?.size ?? 0) === 0);
|
|
746
|
+
var orphanPages = (pages, graph, homeUrl = "/") => pages.filter((page) => page.indexable && page.route?.fallback !== true && page.url !== "/" && page.url !== homeUrl && (graph.contentIn.get(page.url)?.size ?? 0) === 0);
|
|
703
747
|
|
|
704
748
|
// src/audit/checks/links.ts
|
|
705
749
|
var MAGIC_FRAGMENTS = new Set(["", "top"]);
|
|
750
|
+
var FRAGMENT_DIRECTIVE = ":~:";
|
|
706
751
|
var anchorResolves = (target, fragment) => {
|
|
707
752
|
if (MAGIC_FRAGMENTS.has(fragment)) {
|
|
708
753
|
return true;
|
|
@@ -723,7 +768,8 @@ var linkChecks = {
|
|
|
723
768
|
const brokenChrome = new Map;
|
|
724
769
|
const redirectedChrome = new Map;
|
|
725
770
|
const brokenChromeAnchors = new Map;
|
|
726
|
-
const checkAnchor = (page, link, target,
|
|
771
|
+
const checkAnchor = (page, link, target, hash) => {
|
|
772
|
+
const [fragment = ""] = hash.split(FRAGMENT_DIRECTIVE);
|
|
727
773
|
if (anchorResolves(target, fragment)) {
|
|
728
774
|
return;
|
|
729
775
|
}
|
|
@@ -746,6 +792,14 @@ var linkChecks = {
|
|
|
746
792
|
if (resolved.kind === "external" || resolved.kind === "ignored") {
|
|
747
793
|
return;
|
|
748
794
|
}
|
|
795
|
+
if (resolved.kind === "outside-base") {
|
|
796
|
+
if (link.content) {
|
|
797
|
+
found.push(finding("BLUME_AUDIT_LINK_TO_BROKEN", pageSite(context, page), `Link to ${link.href} is missing deployment.base (${deployBase}), so the deployed site does not serve it.`));
|
|
798
|
+
} else if (!brokenChrome.has(resolved.path)) {
|
|
799
|
+
brokenChrome.set(resolved.path, page);
|
|
800
|
+
}
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
749
803
|
const anchorTarget = resolved.hash ? context.byUrl.get(resolved.path) : undefined;
|
|
750
804
|
if (anchorTarget) {
|
|
751
805
|
checkAnchor(page, link, anchorTarget, resolved.hash);
|
|
@@ -858,7 +912,7 @@ var llmsChecks = {
|
|
|
858
912
|
}
|
|
859
913
|
for (const page of context.pages) {
|
|
860
914
|
const { route } = page;
|
|
861
|
-
if (!route || route.hidden || route.draft || !page.indexable || ERROR_ROUTES.has(page.url) || !openapi && route.source.name === "openapi" || listed.has(normalizePath(page.url))) {
|
|
915
|
+
if (!route || route.hidden || route.draft || route.aiExclude || route.fallback || !page.indexable || ERROR_ROUTES.has(page.url) || !openapi && route.source.name === "openapi" || listed.has(normalizePath(page.url))) {
|
|
862
916
|
continue;
|
|
863
917
|
}
|
|
864
918
|
found.push(finding("BLUME_AUDIT_LLMS_TXT_PAGE_MISSING", pageSite(context, page), `${page.url} is built and indexable but is not listed in llms.txt.`));
|
|
@@ -934,7 +988,7 @@ var networkChecks = {
|
|
|
934
988
|
found.push(...servedPageChecks(context, page, result, origin));
|
|
935
989
|
}
|
|
936
990
|
const robots = results.get(robotsUrl);
|
|
937
|
-
if (robots && !robots.ok) {
|
|
991
|
+
if (context.project.config.seo.robots && robots && !robots.ok) {
|
|
938
992
|
found.push(finding("BLUME_AUDIT_ROBOTS_NOT_ACCESSIBLE", { url: "/robots.txt" }, `robots.txt is not reachable at ${robotsUrl}.`));
|
|
939
993
|
}
|
|
940
994
|
const sitemap = results.get(sitemapUrl);
|
|
@@ -1046,6 +1100,10 @@ var ogImageChecks = {
|
|
|
1046
1100
|
if (resolved.kind === "external" || resolved.kind === "ignored") {
|
|
1047
1101
|
continue;
|
|
1048
1102
|
}
|
|
1103
|
+
if (resolved.kind === "outside-base") {
|
|
1104
|
+
found.push(finding("BLUME_AUDIT_OG_IMAGE_BROKEN", pageSite(context, page, ["seo", "image"]), `og:image points at ${resolved.path}, which is missing deployment.base (${deployBase}), so the deployed site does not serve it.`));
|
|
1105
|
+
continue;
|
|
1106
|
+
}
|
|
1049
1107
|
const { path } = resolved;
|
|
1050
1108
|
if (!(context.files.has(path) || context.files.has(`${path}/index.html`))) {
|
|
1051
1109
|
found.push(finding("BLUME_AUDIT_OG_IMAGE_BROKEN", pageSite(context, page, ["seo", "image"]), `og:image points at ${path}, which is not in the build.`));
|
|
@@ -1117,7 +1175,7 @@ var robotsChecks = {
|
|
|
1117
1175
|
];
|
|
1118
1176
|
}
|
|
1119
1177
|
const found = robots.invalid.map((line) => finding("BLUME_AUDIT_ROBOTS_INVALID", { file: robots.file, line: line.line, url: "/robots.txt" }, `robots.txt line ${line.line} is not a directive: "${line.text}"`));
|
|
1120
|
-
if (site && robots.sitemaps.length === 0) {
|
|
1178
|
+
if (site && context.project.config.seo.sitemap && robots.sitemaps.length === 0) {
|
|
1121
1179
|
found.push(finding("BLUME_AUDIT_ROBOTS_SITEMAP_MISSING", { file: robots.file, url: "/robots.txt" }, "robots.txt does not declare a Sitemap."));
|
|
1122
1180
|
}
|
|
1123
1181
|
const parser = robotsParser(`${MATCH_ORIGIN}/robots.txt`, robots.raw);
|
|
@@ -1195,6 +1253,15 @@ var checkListedUrl = (context, loc, origin, file, deployBase) => {
|
|
|
1195
1253
|
}
|
|
1196
1254
|
return found;
|
|
1197
1255
|
};
|
|
1256
|
+
var unlistedPages = (context, listed, deployBase) => context.pages.flatMap((page) => {
|
|
1257
|
+
const canonical = page.canonical ? canonicalPath(page.canonical, deployBase) : null;
|
|
1258
|
+
if (!page.indexable || page.route?.fallback || canonical && canonical !== normalizePath(page.url) || ERROR_ROUTES2.has(page.url) || listed.has(normalizePath(page.url))) {
|
|
1259
|
+
return [];
|
|
1260
|
+
}
|
|
1261
|
+
return [
|
|
1262
|
+
finding("BLUME_AUDIT_INDEXABLE_PAGE_NOT_IN_SITEMAP", pageSite(context, page), `${page.url} is built and indexable but is not listed in sitemap.xml.`)
|
|
1263
|
+
];
|
|
1264
|
+
});
|
|
1198
1265
|
var sitemapChecks = {
|
|
1199
1266
|
category: "sitemap",
|
|
1200
1267
|
run(context) {
|
|
@@ -1210,11 +1277,21 @@ var sitemapChecks = {
|
|
|
1210
1277
|
}
|
|
1211
1278
|
const found = [];
|
|
1212
1279
|
if (sitemap.error) {
|
|
1213
|
-
found.push(finding("BLUME_AUDIT_SITEMAP_INVALID", { file: sitemap.file, url: "/sitemap.xml" }, `sitemap.xml is not a valid urlset: ${sitemap.error}`));
|
|
1280
|
+
found.push(finding("BLUME_AUDIT_SITEMAP_INVALID", { file: sitemap.file, url: "/sitemap.xml" }, `sitemap.xml is not a valid urlset or sitemap index: ${sitemap.error}`));
|
|
1214
1281
|
return found;
|
|
1215
1282
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1283
|
+
const parts = sitemap.parts ?? [
|
|
1284
|
+
{
|
|
1285
|
+
bytes: sitemap.bytes,
|
|
1286
|
+
file: sitemap.file,
|
|
1287
|
+
url: "/sitemap.xml",
|
|
1288
|
+
urls: sitemap.urls.length
|
|
1289
|
+
}
|
|
1290
|
+
];
|
|
1291
|
+
for (const part of parts) {
|
|
1292
|
+
if (part.bytes > MAX_SITEMAP_BYTES || part.urls > MAX_SITEMAP_URLS) {
|
|
1293
|
+
found.push(finding("BLUME_AUDIT_SITEMAP_TOO_LARGE", { file: part.file, url: part.url }, `${part.url.slice(1)} holds ${part.urls} URLs in ${Math.round(part.bytes / 1024 / 1024)} MB.`));
|
|
1294
|
+
}
|
|
1218
1295
|
}
|
|
1219
1296
|
for (const [loc, lastmod] of sitemap.lastmod ?? []) {
|
|
1220
1297
|
const time = Date.parse(lastmod);
|
|
@@ -1230,12 +1307,7 @@ var sitemapChecks = {
|
|
|
1230
1307
|
for (const loc of sitemap.urls) {
|
|
1231
1308
|
found.push(...checkListedUrl(context, loc, origin, sitemap.file, deployBase));
|
|
1232
1309
|
}
|
|
1233
|
-
|
|
1234
|
-
if (!page.indexable || ERROR_ROUTES2.has(page.url) || listed.has(normalizePath(page.url))) {
|
|
1235
|
-
continue;
|
|
1236
|
-
}
|
|
1237
|
-
found.push(finding("BLUME_AUDIT_INDEXABLE_PAGE_NOT_IN_SITEMAP", pageSite(context, page), `${page.url} is built and indexable but is not listed in sitemap.xml.`));
|
|
1238
|
-
}
|
|
1310
|
+
found.push(...unlistedPages(context, listed, deployBase));
|
|
1239
1311
|
return found;
|
|
1240
1312
|
},
|
|
1241
1313
|
tier: "static"
|
|
@@ -1317,6 +1389,16 @@ var URL_STYLE = [
|
|
|
1317
1389
|
{ name: "underscores", test: /_/u },
|
|
1318
1390
|
{ name: "spaces", test: /%20| /u }
|
|
1319
1391
|
];
|
|
1392
|
+
var authoredPath = (context, url) => {
|
|
1393
|
+
const { basePath, i18n } = context.project.config;
|
|
1394
|
+
if (!i18n) {
|
|
1395
|
+
return url;
|
|
1396
|
+
}
|
|
1397
|
+
const base = normalizeBasePath(basePath);
|
|
1398
|
+
const [, first = "", ...rest] = stripBasePath(base, url).split("/");
|
|
1399
|
+
const isLocale = i18n.locales.some((locale) => locale.code === first);
|
|
1400
|
+
return isLocale ? `${base}/${rest.join("/")}` : url;
|
|
1401
|
+
};
|
|
1320
1402
|
var DOTTED_HOST = /^\/\/[^/]*\./u;
|
|
1321
1403
|
var doubledSlash = (href) => {
|
|
1322
1404
|
if (href.startsWith("//")) {
|
|
@@ -1343,7 +1425,8 @@ var urlChecks = {
|
|
|
1343
1425
|
doubled.set(href, page);
|
|
1344
1426
|
}
|
|
1345
1427
|
}
|
|
1346
|
-
const
|
|
1428
|
+
const authored = authoredPath(context, page.url);
|
|
1429
|
+
const untidy = URL_STYLE.filter((style) => style.test.test(authored));
|
|
1347
1430
|
if (untidy.length > 0) {
|
|
1348
1431
|
found.push(finding("BLUME_AUDIT_URL_STYLE", pageSite(context, page), `URL ${page.url} contains ${untidy.map((style) => style.name).join(" and ")}.`));
|
|
1349
1432
|
}
|
|
@@ -1495,7 +1578,7 @@ var buildSnapshot = (options) => {
|
|
|
1495
1578
|
scripts: collectAssets(document, "script[src]", "src"),
|
|
1496
1579
|
source: route?.sourcePath,
|
|
1497
1580
|
styles: collectAssets(document, 'link[rel="stylesheet"][href]', "href"),
|
|
1498
|
-
titles: document.querySelectorAll("title").map((title) => title.text.trim()).filter((text) => text.length > 0),
|
|
1581
|
+
titles: document.querySelectorAll("title").filter((title) => !title.closest("svg")).map((title) => title.text.trim()).filter((text) => text.length > 0),
|
|
1499
1582
|
twitter: prefixedMeta(document, "name", "twitter:"),
|
|
1500
1583
|
url,
|
|
1501
1584
|
viewport: document.querySelector('meta[name="viewport"]')?.getAttribute("content")?.trim() ?? null,
|
|
@@ -1538,6 +1621,7 @@ var sitemapParser = new XMLParser({
|
|
|
1538
1621
|
removeNSPrefix: true
|
|
1539
1622
|
});
|
|
1540
1623
|
var isUrlsetElement = (value) => typeof value === "object" && value !== null;
|
|
1624
|
+
var isSitemapIndexElement = (value) => typeof value === "object" && value !== null;
|
|
1541
1625
|
var isUrlEntry = (value) => typeof value === "object" && value !== null;
|
|
1542
1626
|
var isText = (value) => typeof value === "string";
|
|
1543
1627
|
var parseSitemap = (file, xml, bytes) => {
|
|
@@ -1549,8 +1633,14 @@ var parseSitemap = (file, xml, bytes) => {
|
|
|
1549
1633
|
doc.error = "no <urlset> element";
|
|
1550
1634
|
return doc;
|
|
1551
1635
|
}
|
|
1636
|
+
if (Object.hasOwn(parsed, "sitemapindex")) {
|
|
1637
|
+
const { sitemapindex } = parsed;
|
|
1638
|
+
const children = isSitemapIndexElement(sitemapindex) ? [sitemapindex.sitemap].flat() : [];
|
|
1639
|
+
doc.sitemaps = children.flatMap((child) => isUrlEntry(child) && isText(child.loc) && child.loc.trim() ? [child.loc.trim()] : []);
|
|
1640
|
+
return doc;
|
|
1641
|
+
}
|
|
1552
1642
|
if (!Object.hasOwn(parsed, "urlset")) {
|
|
1553
|
-
doc.error =
|
|
1643
|
+
doc.error = "no <urlset> element";
|
|
1554
1644
|
return doc;
|
|
1555
1645
|
}
|
|
1556
1646
|
const { urlset } = parsed;
|
|
@@ -1615,8 +1705,47 @@ var readIfPresent = async (file) => {
|
|
|
1615
1705
|
return null;
|
|
1616
1706
|
}
|
|
1617
1707
|
};
|
|
1708
|
+
var readSitemap = async (staticDir, files, deployBase) => {
|
|
1709
|
+
const file = join2(staticDir, "sitemap.xml");
|
|
1710
|
+
const xml = await readIfPresent(file);
|
|
1711
|
+
if (xml === null) {
|
|
1712
|
+
return null;
|
|
1713
|
+
}
|
|
1714
|
+
const doc = parseSitemap(file, xml, files.get("/sitemap.xml") ?? Buffer.byteLength(xml, "utf-8"));
|
|
1715
|
+
if (!doc.sitemaps) {
|
|
1716
|
+
return doc;
|
|
1717
|
+
}
|
|
1718
|
+
doc.parts = [];
|
|
1719
|
+
for (const loc of doc.sitemaps) {
|
|
1720
|
+
let url;
|
|
1721
|
+
try {
|
|
1722
|
+
url = stripBasePath(deployBase, decodeURI(new URL(loc).pathname));
|
|
1723
|
+
} catch {
|
|
1724
|
+
doc.error = `the sitemap index lists "${loc}", which is not a valid absolute URL`;
|
|
1725
|
+
return doc;
|
|
1726
|
+
}
|
|
1727
|
+
const childFile = join2(staticDir, url);
|
|
1728
|
+
const childXml = await readIfPresent(childFile);
|
|
1729
|
+
const child = childXml === null ? null : parseSitemap(childFile, childXml, files.get(url) ?? Buffer.byteLength(childXml, "utf-8"));
|
|
1730
|
+
if (!child || child.error || child.sitemaps) {
|
|
1731
|
+
doc.error = `the sitemap index lists ${loc}, which is not a urlset in the build`;
|
|
1732
|
+
return doc;
|
|
1733
|
+
}
|
|
1734
|
+
doc.urls.push(...child.urls);
|
|
1735
|
+
for (const [key, value] of child.lastmod ?? []) {
|
|
1736
|
+
doc.lastmod?.set(key, value);
|
|
1737
|
+
}
|
|
1738
|
+
doc.parts.push({
|
|
1739
|
+
bytes: child.bytes,
|
|
1740
|
+
file: childFile,
|
|
1741
|
+
url,
|
|
1742
|
+
urls: child.urls.length
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
return doc;
|
|
1746
|
+
};
|
|
1618
1747
|
var crawlStaticDir = async (options) => {
|
|
1619
|
-
const { staticDir, manifest, basePath } = options;
|
|
1748
|
+
const { staticDir, manifest, basePath, deployBase = "" } = options;
|
|
1620
1749
|
const routes = routeIndex(manifest, basePath);
|
|
1621
1750
|
const htmlFiles = await glob("**/*.html", { absolute: true, cwd: staticDir });
|
|
1622
1751
|
const snapshots = await pMap(htmlFiles.toSorted(), async (file) => {
|
|
@@ -1636,8 +1765,6 @@ var crawlStaticDir = async (options) => {
|
|
|
1636
1765
|
});
|
|
1637
1766
|
}, { concurrency: CRAWL_CONCURRENCY });
|
|
1638
1767
|
const pages = snapshots.filter((page) => page !== null);
|
|
1639
|
-
const sitemapFile = join2(staticDir, "sitemap.xml");
|
|
1640
|
-
const sitemapXml = await readIfPresent(sitemapFile);
|
|
1641
1768
|
const robotsFile = join2(staticDir, "robots.txt");
|
|
1642
1769
|
const robotsTxt = await readIfPresent(robotsFile);
|
|
1643
1770
|
const llmsFile = join2(staticDir, "llms.txt");
|
|
@@ -1648,7 +1775,7 @@ var crawlStaticDir = async (options) => {
|
|
|
1648
1775
|
llms: llmsText === null ? null : parseLlms(llmsFile, llmsText),
|
|
1649
1776
|
pages,
|
|
1650
1777
|
robots: robotsTxt === null ? null : parseRobots(robotsFile, robotsTxt),
|
|
1651
|
-
sitemap:
|
|
1778
|
+
sitemap: await readSitemap(staticDir, files, deployBase)
|
|
1652
1779
|
};
|
|
1653
1780
|
};
|
|
1654
1781
|
|
|
@@ -1775,6 +1902,7 @@ var runAudit = async (options) => {
|
|
|
1775
1902
|
const basePath = normalizeBasePath(project.config.basePath);
|
|
1776
1903
|
const crawl = await crawlStaticDir({
|
|
1777
1904
|
basePath,
|
|
1905
|
+
deployBase: normalizeBasePath(project.config.deployment.options.base),
|
|
1778
1906
|
manifest: project.manifest,
|
|
1779
1907
|
staticDir
|
|
1780
1908
|
});
|
|
@@ -1791,11 +1919,7 @@ var runAudit = async (options) => {
|
|
|
1791
1919
|
origin,
|
|
1792
1920
|
pages: crawl.pages,
|
|
1793
1921
|
project,
|
|
1794
|
-
redirects: resolveRedirects(project.config.redirects.
|
|
1795
|
-
...redirect,
|
|
1796
|
-
from: withBasePath(basePath, redirect.from),
|
|
1797
|
-
to: withBasePath(basePath, redirect.to)
|
|
1798
|
-
})), (path) => isServed({ byUrl, files: crawl.files, project }, path)),
|
|
1922
|
+
redirects: resolveRedirects(applyBaseToAstroRedirects(project.config.redirects, basePath, "", routeSetFor(project.manifest.routes)), (path) => isServed({ byUrl, files: crawl.files, project }, path)),
|
|
1799
1923
|
robots: crawl.robots,
|
|
1800
1924
|
sitemap: crawl.sitemap,
|
|
1801
1925
|
sources: await readSources(crawl.pages),
|
|
@@ -1924,6 +2048,10 @@ var auditCommand = defineCommand({
|
|
|
1924
2048
|
logger.error(`--json and --${agent} are mutually exclusive.`);
|
|
1925
2049
|
process.exit(1);
|
|
1926
2050
|
}
|
|
2051
|
+
if (args.url !== undefined && !isHttpUrl(args.url)) {
|
|
2052
|
+
logger.error(`Invalid --url "${args.url}": pass the deployment's full URL, scheme included (e.g. https://${args.url}).`);
|
|
2053
|
+
process.exit(1);
|
|
2054
|
+
}
|
|
1927
2055
|
const only = splitTerms(args.only);
|
|
1928
2056
|
const skip = splitTerms(args.skip);
|
|
1929
2057
|
rejectUnknownTerms([...only, ...skip]);
|
|
@@ -1976,7 +2104,7 @@ var auditCommand = defineCommand({
|
|
|
1976
2104
|
}
|
|
1977
2105
|
process.stderr.write(formatReport(result, root, { verbose: args.verbose }));
|
|
1978
2106
|
if (shouldFail(result, gate)) {
|
|
1979
|
-
process.
|
|
2107
|
+
process.exitCode = 1;
|
|
1980
2108
|
}
|
|
1981
2109
|
}
|
|
1982
2110
|
});
|
|
@@ -1985,5 +2113,5 @@ export {
|
|
|
1985
2113
|
shouldFail
|
|
1986
2114
|
};
|
|
1987
2115
|
|
|
1988
|
-
//# debugId=
|
|
1989
|
-
//# sourceMappingURL=chunk-
|
|
2116
|
+
//# debugId=E1B16241D184BD6E64756E2164756E21
|
|
2117
|
+
//# sourceMappingURL=chunk-wrr3j9w9.js.map
|