blume 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +110 -0
- package/README.md +2 -2
- package/dist/cli/{chunk-f2972sbt.js → chunk-00gs3wqs.js} +1 -1
- package/dist/cli/{chunk-fa25z98p.js → chunk-273ygyr4.js} +4 -3
- package/dist/cli/chunk-273ygyr4.js.map +11 -0
- package/dist/cli/{chunk-pat2zzwc.js → chunk-3yce002v.js} +21 -8
- package/dist/cli/{chunk-pat2zzwc.js.map → chunk-3yce002v.js.map} +4 -4
- package/dist/cli/{chunk-d1tadaw7.js → chunk-4e9b9ra6.js} +17 -7
- package/dist/cli/chunk-4e9b9ra6.js.map +10 -0
- package/dist/cli/{chunk-zg2gtj10.js → chunk-5r8g91qn.js} +352 -676
- package/dist/cli/chunk-5r8g91qn.js.map +34 -0
- package/dist/cli/{chunk-11j0384y.js → chunk-6dtt0zfn.js} +14 -14
- package/dist/cli/{chunk-11j0384y.js.map → chunk-6dtt0zfn.js.map} +3 -3
- package/dist/cli/{chunk-bw22s759.js → chunk-6k4ftwze.js} +38 -19
- package/dist/cli/{chunk-bw22s759.js.map → chunk-6k4ftwze.js.map} +4 -4
- package/dist/cli/{chunk-sqn5t4q0.js → chunk-7mbqtmgb.js} +16 -7
- package/dist/cli/chunk-7mbqtmgb.js.map +10 -0
- package/dist/cli/{chunk-79njf86q.js → chunk-7vtckvaw.js} +21 -19
- package/dist/cli/chunk-7vtckvaw.js.map +11 -0
- package/dist/cli/{chunk-fh5hj5jt.js → chunk-8g8ytmgx.js} +17 -18
- package/dist/cli/{chunk-fh5hj5jt.js.map → chunk-8g8ytmgx.js.map} +2 -2
- package/dist/cli/{chunk-1w8dp3qb.js → chunk-91ws1n6j.js} +18 -15
- package/dist/cli/chunk-91ws1n6j.js.map +10 -0
- package/dist/cli/{chunk-7ez8ny0t.js → chunk-bbnwccaz.js} +2 -2
- package/dist/cli/{chunk-5a2z0198.js → chunk-bfwp9vp6.js} +18 -10
- package/dist/cli/chunk-bfwp9vp6.js.map +10 -0
- package/dist/cli/{chunk-ernrthtr.js → chunk-d1v5rhy0.js} +14 -15
- package/dist/cli/{chunk-ernrthtr.js.map → chunk-d1v5rhy0.js.map} +2 -2
- package/dist/cli/{chunk-a9kptbw5.js → chunk-ddndchfr.js} +21 -6
- package/dist/cli/chunk-ddndchfr.js.map +14 -0
- package/dist/cli/{chunk-zxccj738.js → chunk-esh98wmb.js} +1 -1
- package/dist/cli/{chunk-88cpgt6h.js → chunk-fsmrqk8a.js} +1 -1
- package/dist/cli/{chunk-b5aj94ah.js → chunk-g698a744.js} +5 -5
- package/dist/cli/{chunk-jts8mvcz.js → chunk-gs7r695n.js} +9 -3
- package/dist/cli/{chunk-jts8mvcz.js.map → chunk-gs7r695n.js.map} +3 -3
- package/dist/cli/{chunk-41za066z.js → chunk-h2ez8dzb.js} +4 -4
- package/dist/cli/{chunk-by2290sx.js → chunk-h7k3nq3v.js} +2 -2
- package/dist/cli/{chunk-j8mw0za6.js → chunk-hqp2ajnh.js} +252 -123
- package/dist/cli/chunk-hqp2ajnh.js.map +35 -0
- package/dist/cli/{chunk-mnqj32sj.js → chunk-hr8ne106.js} +119 -50
- package/dist/cli/chunk-hr8ne106.js.map +13 -0
- package/dist/cli/{chunk-mwt1k8n7.js → chunk-j85scx15.js} +74 -30
- package/dist/cli/chunk-j85scx15.js.map +10 -0
- package/dist/cli/{chunk-z01ze5c1.js → chunk-k7pj68a8.js} +63 -22
- package/dist/cli/chunk-k7pj68a8.js.map +11 -0
- package/dist/cli/{chunk-2q1dwty4.js → chunk-mqc662a6.js} +8 -8
- package/dist/cli/{chunk-2q1dwty4.js.map → chunk-mqc662a6.js.map} +4 -4
- package/dist/cli/{chunk-y3e45rc8.js → chunk-n1yg3tj3.js} +4 -4
- package/dist/cli/{chunk-bctazmbk.js → chunk-nfcyttvj.js} +17 -6
- package/dist/cli/chunk-nfcyttvj.js.map +10 -0
- package/dist/cli/{chunk-6k8vp3ta.js → chunk-pbg5a4s3.js} +60 -28
- package/dist/cli/chunk-pbg5a4s3.js.map +19 -0
- package/dist/cli/{chunk-d80hr03s.js → chunk-ppzjqwx2.js} +24 -17
- package/dist/cli/{chunk-d80hr03s.js.map → chunk-ppzjqwx2.js.map} +4 -4
- package/dist/cli/{chunk-beat36xx.js → chunk-qkb5a8sa.js} +25 -10
- package/dist/cli/chunk-qkb5a8sa.js.map +10 -0
- package/dist/cli/{chunk-bnbmcwfb.js → chunk-sqw4ekg1.js} +5 -5
- package/dist/cli/{chunk-bnbmcwfb.js.map → chunk-sqw4ekg1.js.map} +3 -3
- package/dist/cli/{chunk-xaz13gwg.js → chunk-v6ya5kcb.js} +3268 -1150
- package/dist/cli/chunk-v6ya5kcb.js.map +189 -0
- package/dist/cli/{chunk-tzne8qfq.js → chunk-w4bxdvsa.js} +18 -15
- package/dist/cli/chunk-w4bxdvsa.js.map +10 -0
- package/dist/cli/{chunk-f7t03s3g.js → chunk-wdrt2k2v.js} +2 -2
- package/dist/cli/{chunk-z1f5arsg.js → chunk-xh43dwgw.js} +170 -55
- package/dist/cli/chunk-xh43dwgw.js.map +36 -0
- package/dist/cli/{chunk-pnnvybbk.js → chunk-zp79m0ts.js} +5 -5
- package/dist/cli/{chunk-pnnvybbk.js.map → chunk-zp79m0ts.js.map} +2 -2
- package/dist/cli/index.js +160 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-readability.d.ts +1 -1
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api/paths.d.ts +1 -1
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +14 -7
- package/dist/types/ai/ask.d.ts +43 -43
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/index.d.ts +3 -3
- package/dist/types/ai/openapi-components.d.ts +1 -1
- package/dist/types/ai/relative-links.d.ts +9 -4
- package/dist/types/ai/serializers.d.ts +1 -1
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/ai/visibility.d.ts +1 -1
- package/dist/types/analytics/databuddy.d.ts +43 -0
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/schema.d.ts +14 -0
- 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 +9 -0
- package/dist/types/core/config-input.d.ts +21 -21
- package/dist/types/core/config.d.ts +5 -5
- package/dist/types/core/data.d.ts +3 -3
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/i18n-ui.d.ts +37 -8
- package/dist/types/core/i18n.d.ts +7 -1
- 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 +5 -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 +57 -18
- package/dist/types/core/sources/github-releases.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +14 -2
- package/dist/types/core/sources/normalize.d.ts +10 -1
- 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/types.d.ts +9 -0
- package/dist/types/core/unrecognized-keys.d.ts +1 -1
- package/dist/types/deploy/adapters/node.d.ts +5 -2
- package/dist/types/deploy/adapters/types.d.ts +7 -0
- package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
- package/dist/types/deploy/headers.d.ts +31 -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 +7 -0
- package/dist/types/deploy/platforms/vercel.d.ts +3 -2
- package/dist/types/deploy/redirects.d.ts +7 -2
- package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
- package/dist/types/openapi/model.d.ts +20 -6
- package/dist/types/search/documents.d.ts +1 -1
- package/dist/types/search/orama-index.d.ts +1 -1
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +21 -12
- package/docs/03-upgrading.mdx +22 -9
- package/docs/04-migrating.mdx +4 -4
- package/docs/08-faq.mdx +12 -5
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +5 -3
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +5 -5
- package/docs/cli/doctor.mdx +4 -4
- package/docs/cli/evals.mdx +9 -9
- package/docs/cli/index.mdx +6 -3
- package/docs/cli/translate.mdx +8 -8
- package/docs/configuration/analytics.mdx +23 -2
- package/docs/configuration/{ask-ai.mdx → assistant.mdx} +20 -20
- package/docs/configuration/customization.mdx +5 -4
- package/docs/configuration/index.mdx +7 -5
- package/docs/configuration/meta.ts +1 -1
- package/docs/configuration/search.mdx +2 -2
- package/docs/content/components.mdx +1 -1
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +3 -3
- package/docs/content/index.mdx +4 -2
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +5 -3
- package/docs/content/navigation.mdx +29 -4
- package/docs/content/sources.mdx +18 -12
- package/docs/content/versioning.mdx +1 -0
- package/docs/discoverability/agent-discovery.mdx +22 -8
- package/docs/discoverability/index.mdx +3 -3
- package/docs/discoverability/llms-txt.mdx +2 -5
- package/docs/discoverability/markdown.mdx +5 -3
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +3 -2
- package/docs/discoverability/open-graph.mdx +6 -4
- package/docs/discoverability/rss.mdx +3 -1
- package/docs/index.mdx +2 -2
- package/docs/references/asyncapi.mdx +1 -1
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/openapi.mdx +3 -3
- package/package.json +1 -1
- package/skills/blume/SKILL.md +5 -5
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +6 -6
- 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 +1 -1
- package/skills/blume-migrate/references/starlight.md +5 -5
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +2 -2
- package/skills/blume-update-docs/references/audit-checklist.md +1 -1
- package/src/ai/agent-readability.ts +4 -4
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/api/paths.ts +1 -1
- package/src/ai/api/spec.ts +15 -2
- package/src/ai/api-catalog.ts +7 -1
- package/src/ai/ask-context.ts +21 -9
- package/src/ai/ask-data.ts +28 -14
- package/src/ai/ask.ts +84 -71
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/cors.ts +3 -3
- package/src/ai/index.ts +16 -16
- package/src/ai/link-headers.ts +8 -3
- package/src/ai/llms.ts +4 -3
- package/src/ai/markdown.ts +23 -11
- package/src/ai/mcp/server.ts +78 -7
- package/src/ai/openapi-components.ts +1 -1
- package/src/ai/relative-links.ts +78 -10
- package/src/ai/serializers.ts +1 -1
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/visibility.ts +46 -15
- package/src/analytics/databuddy.ts +67 -0
- package/src/analytics/head.ts +4 -0
- package/src/analytics/index.ts +2 -0
- package/src/analytics/posthog.ts +21 -3
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +90 -45
- package/src/astro/module-types.ts +1 -1
- package/src/astro/runtime-deps.ts +6 -6
- package/src/astro/templates.ts +87 -49
- 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 +14 -0
- 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/report.ts +54 -17
- package/src/audit/run.ts +1 -0
- package/src/audit/types.ts +18 -0
- package/src/audit/url.ts +37 -6
- package/src/blume-modules.d.ts +2 -2
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +8 -1
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/doctor.ts +7 -5
- package/src/cli/commands/eval.ts +4 -10
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/migrate.ts +2 -2
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +12 -9
- package/src/cli/commands/upgrade.ts +13 -2
- 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/required-secrets.ts +3 -3
- package/src/components/content/AccordionItem.astro +26 -22
- package/src/components/content/Badge.astro +2 -9
- package/src/components/content/Card.astro +2 -2
- package/src/components/content/Component.astro +9 -3
- 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/Tabs.astro +54 -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 +17 -0
- package/src/components/content/base-href.ts +18 -3
- package/src/components/content/inline-markdown.ts +27 -7
- package/src/components/copy-feedback.ts +36 -9
- package/src/components/islands/{AskAI.astro → Assistant.astro} +10 -10
- package/src/components/islands/{ask-ai.tsx → assistant.tsx} +39 -25
- package/src/components/islands/hooks.ts +21 -14
- package/src/components/islands/webmcp.ts +12 -8
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Header.astro +32 -19
- package/src/components/layout/Logo.astro +5 -0
- package/src/components/layout/NavSelector.astro +6 -1
- package/src/components/layout/NavTabMenu.astro +133 -0
- package/src/components/layout/NavTree.astro +15 -6
- package/src/components/layout/NavTreeCache.astro +5 -2
- package/src/components/layout/NavTreeScript.astro +45 -5
- package/src/components/layout/PageLayout.astro +28 -14
- package/src/components/layout/Pagination.astro +7 -7
- package/src/components/layout/ReferenceLayout.astro +5 -2
- package/src/components/layout/RootLayout.astro +27 -14
- package/src/components/layout/Search.astro +18 -14
- package/src/components/layout/analytics-client.ts +3 -1
- package/src/components/layout/drawer-inert.ts +1 -1
- package/src/components/openapi/GraphqlType.astro +11 -3
- package/src/components/openapi/MessageComposer.astro +1 -1
- package/src/components/openapi/Operation.astro +21 -5
- package/src/components/openapi/PanelTabs.astro +4 -1
- package/src/components/openapi/Playground.astro +8 -2
- package/src/components/openapi/RequestPanel.astro +9 -5
- package/src/components/openapi/SchemaProperty.astro +11 -33
- package/src/components/openapi/SchemaTable.astro +27 -52
- package/src/components/openapi/description.ts +2 -2
- package/src/components/openapi/helpers.ts +90 -12
- package/src/components/openapi/message-composer.ts +8 -0
- package/src/components/openapi/message-model.ts +12 -2
- package/src/components/openapi/message.ts +4 -1
- package/src/components/openapi/operation-model.ts +40 -8
- package/src/components/openapi/panel.ts +29 -5
- package/src/components/openapi/playground-client.ts +37 -7
- package/src/components/openapi/playground-schema.ts +25 -6
- package/src/components/openapi/request.ts +2 -0
- package/src/components/openapi/schema-tree.ts +203 -0
- package/src/components/openapi/snippets.ts +30 -15
- package/src/components/openapi/validate-json.ts +1 -1
- package/src/core/base-path.ts +15 -0
- package/src/core/code-fences.ts +1 -1
- package/src/core/config-input.ts +23 -23
- package/src/core/config.ts +21 -7
- package/src/core/data.ts +3 -3
- package/src/core/diagnostics.ts +217 -30
- package/src/core/graph.ts +120 -11
- package/src/core/i18n-ui.ts +74 -11
- package/src/core/i18n.ts +13 -2
- package/src/core/links.ts +7 -4
- package/src/core/load-module.ts +20 -0
- package/src/core/locale-links.ts +17 -17
- package/src/core/manifest.ts +3 -2
- package/src/core/meta.ts +69 -6
- package/src/core/nav-diagnostics.ts +56 -1
- package/src/core/navigation.ts +245 -76
- package/src/core/ordering-prefix.ts +27 -0
- package/src/core/project-graph.ts +23 -1
- package/src/core/request-body.ts +1 -1
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +95 -34
- package/src/core/server-features.ts +2 -2
- package/src/core/sources/assets.ts +83 -41
- package/src/core/sources/contentful-rich-text.ts +3 -2
- package/src/core/sources/contentful.ts +25 -12
- package/src/core/sources/filesystem.ts +5 -1
- package/src/core/sources/github-releases.ts +106 -5
- package/src/core/sources/lexical.ts +9 -4
- package/src/core/sources/lower.ts +79 -26
- package/src/core/sources/mdx-remote.ts +1 -0
- package/src/core/sources/normalize.ts +132 -30
- package/src/core/sources/notion.ts +26 -10
- package/src/core/sources/obsidian.ts +17 -3
- package/src/core/sources/payload.ts +1 -0
- package/src/core/sources/portable-text.ts +63 -44
- 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 +9 -4
- package/src/core/sources/strapi.ts +1 -0
- package/src/core/sources/types.ts +31 -0
- package/src/core/types.ts +9 -0
- package/src/core/ui-packs/ar.ts +17 -5
- package/src/core/ui-packs/bg.ts +17 -5
- package/src/core/ui-packs/bn.ts +17 -5
- package/src/core/ui-packs/ca.ts +17 -5
- package/src/core/ui-packs/cs.ts +17 -5
- package/src/core/ui-packs/da.ts +17 -5
- package/src/core/ui-packs/de.ts +17 -5
- package/src/core/ui-packs/el.ts +17 -5
- package/src/core/ui-packs/es.ts +17 -5
- package/src/core/ui-packs/fa.ts +17 -5
- package/src/core/ui-packs/fi.ts +17 -5
- package/src/core/ui-packs/fr.ts +17 -5
- package/src/core/ui-packs/he.ts +17 -5
- package/src/core/ui-packs/hi.ts +17 -5
- package/src/core/ui-packs/hr.ts +17 -5
- package/src/core/ui-packs/hu.ts +17 -5
- package/src/core/ui-packs/id.ts +17 -5
- package/src/core/ui-packs/it.ts +17 -5
- package/src/core/ui-packs/ja.ts +17 -5
- package/src/core/ui-packs/ko.ts +17 -5
- package/src/core/ui-packs/nl.ts +17 -5
- package/src/core/ui-packs/no.ts +17 -5
- package/src/core/ui-packs/pl.ts +17 -5
- package/src/core/ui-packs/pt-br.ts +17 -5
- package/src/core/ui-packs/pt.ts +17 -5
- package/src/core/ui-packs/ro.ts +17 -5
- package/src/core/ui-packs/ru.ts +17 -5
- package/src/core/ui-packs/sk.ts +17 -5
- package/src/core/ui-packs/sr.ts +17 -5
- package/src/core/ui-packs/sv.ts +17 -5
- package/src/core/ui-packs/th.ts +17 -5
- package/src/core/ui-packs/tr.ts +17 -5
- package/src/core/ui-packs/uk.ts +17 -5
- package/src/core/ui-packs/vi.ts +17 -5
- package/src/core/ui-packs/zh-tw.ts +17 -5
- package/src/core/ui-packs/zh.ts +17 -5
- package/src/core/unrecognized-keys.ts +1 -1
- package/src/core/version-cut.ts +17 -2
- 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 +25 -5
- package/src/deploy/cloudflare-negotiation.ts +23 -4
- package/src/deploy/headers.ts +67 -51
- package/src/deploy/node-headers.ts +148 -27
- package/src/deploy/platforms/cloudflare.ts +1 -0
- package/src/deploy/platforms/netlify.ts +82 -5
- package/src/deploy/platforms/node.ts +7 -5
- package/src/deploy/platforms/static.ts +1 -0
- package/src/deploy/platforms/types.ts +7 -0
- package/src/deploy/platforms/vercel.ts +9 -3
- package/src/deploy/redirects.ts +14 -3
- 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 +55 -8
- package/src/markdown/index.ts +6 -3
- package/src/markdown/relative-links.ts +3 -23
- package/src/markdown/route-snapshot.ts +37 -0
- package/src/og/card.ts +20 -4
- package/src/og/derive.ts +145 -4
- package/src/openapi/graphql-build.ts +28 -2
- package/src/openapi/model.ts +77 -13
- package/src/openapi/render-mdx.ts +10 -1
- package/src/registry/eject.ts +135 -37
- package/src/search/documents.ts +24 -3
- package/src/search/orama-index.ts +1 -1
- package/src/search/sync/algolia.ts +36 -2
- 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 +11 -3
- package/src/translate/report.ts +1 -1
- package/src/translate/run.ts +11 -5
- package/src/translate/validate.ts +10 -1
- package/src/translate/work-list.ts +36 -3
- package/src/upgrade/upgrade.ts +37 -5
- package/dist/cli/chunk-1w8dp3qb.js.map +0 -10
- package/dist/cli/chunk-5a2z0198.js.map +0 -10
- package/dist/cli/chunk-6k8vp3ta.js.map +0 -19
- package/dist/cli/chunk-79njf86q.js.map +0 -11
- package/dist/cli/chunk-a9kptbw5.js.map +0 -14
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-bctazmbk.js.map +0 -10
- package/dist/cli/chunk-beat36xx.js.map +0 -10
- package/dist/cli/chunk-d1tadaw7.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-j8mw0za6.js.map +0 -35
- package/dist/cli/chunk-mnqj32sj.js.map +0 -12
- package/dist/cli/chunk-mwt1k8n7.js.map +0 -10
- package/dist/cli/chunk-nk3ts2xk.js +0 -51
- package/dist/cli/chunk-nk3ts2xk.js.map +0 -10
- package/dist/cli/chunk-sqn5t4q0.js.map +0 -10
- package/dist/cli/chunk-tzne8qfq.js.map +0 -10
- package/dist/cli/chunk-xaz13gwg.js.map +0 -182
- package/dist/cli/chunk-z01ze5c1.js.map +0 -10
- package/dist/cli/chunk-z1f5arsg.js.map +0 -36
- package/dist/cli/chunk-zg2gtj10.js.map +0 -35
- /package/dist/cli/{chunk-f2972sbt.js.map → chunk-00gs3wqs.js.map} +0 -0
- /package/dist/cli/{chunk-7ez8ny0t.js.map → chunk-bbnwccaz.js.map} +0 -0
- /package/dist/cli/{chunk-zxccj738.js.map → chunk-esh98wmb.js.map} +0 -0
- /package/dist/cli/{chunk-88cpgt6h.js.map → chunk-fsmrqk8a.js.map} +0 -0
- /package/dist/cli/{chunk-b5aj94ah.js.map → chunk-g698a744.js.map} +0 -0
- /package/dist/cli/{chunk-41za066z.js.map → chunk-h2ez8dzb.js.map} +0 -0
- /package/dist/cli/{chunk-by2290sx.js.map → chunk-h7k3nq3v.js.map} +0 -0
- /package/dist/cli/{chunk-y3e45rc8.js.map → chunk-n1yg3tj3.js.map} +0 -0
- /package/dist/cli/{chunk-f7t03s3g.js.map → chunk-wdrt2k2v.js.map} +0 -0
|
@@ -19,28 +19,26 @@ import {
|
|
|
19
19
|
writeAgentReport,
|
|
20
20
|
fixPrompt,
|
|
21
21
|
launchInstalledAgent
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-6k4ftwze.js";
|
|
23
23
|
import {
|
|
24
24
|
frontmatter_default,
|
|
25
25
|
gradeExternal,
|
|
26
26
|
probeAll,
|
|
27
27
|
deployPlatform
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-v6ya5kcb.js";
|
|
29
29
|
import {
|
|
30
30
|
normalizeBasePath,
|
|
31
31
|
normalizePath,
|
|
32
32
|
withBasePath,
|
|
33
33
|
stripBasePath
|
|
34
|
-
} from "./chunk-
|
|
35
|
-
import {
|
|
36
|
-
deployStaticDir
|
|
37
|
-
} from "./chunk-nk3ts2xk.js";
|
|
34
|
+
} from "./chunk-gs7r695n.js";
|
|
38
35
|
import {
|
|
36
|
+
deployStaticDir,
|
|
39
37
|
examplesRouteBase
|
|
40
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-hr8ne106.js";
|
|
41
39
|
import {
|
|
42
40
|
scanProject
|
|
43
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-5r8g91qn.js";
|
|
44
42
|
|
|
45
43
|
// src/cli/commands/audit.ts
|
|
46
44
|
import { defineCommand } from "citty";
|
|
@@ -71,6 +69,7 @@ var serverRoutes = (context) => {
|
|
|
71
69
|
return mcp?.enabled ? [normalizePath(mcp.route)] : [];
|
|
72
70
|
};
|
|
73
71
|
var isServed = (context, path) => context.byUrl.has(path) || context.files.has(path) || context.files.has(`${path}/index.html`) || serverRoutes(context).includes(path);
|
|
72
|
+
var underBase = (deployBase, path) => !deployBase || path === deployBase || path.startsWith(`${deployBase}/`);
|
|
74
73
|
var NON_HTTP_SCHEME = /^(?!https?:)[a-z][a-z0-9+.-]*:/iu;
|
|
75
74
|
var decodePath = (path) => {
|
|
76
75
|
try {
|
|
@@ -79,6 +78,14 @@ var decodePath = (path) => {
|
|
|
79
78
|
return path;
|
|
80
79
|
}
|
|
81
80
|
};
|
|
81
|
+
var isHttpUrl = (input) => {
|
|
82
|
+
try {
|
|
83
|
+
const { protocol } = new URL(input);
|
|
84
|
+
return protocol === "http:" || protocol === "https:";
|
|
85
|
+
} catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
82
89
|
var siteOrigin = (site) => {
|
|
83
90
|
if (!site) {
|
|
84
91
|
return null;
|
|
@@ -106,10 +113,14 @@ var resolveHref = (pageUrl, href, origin, deployBase = "") => {
|
|
|
106
113
|
return { kind: "ignored" };
|
|
107
114
|
}
|
|
108
115
|
if (origin && parsed.origin === origin) {
|
|
116
|
+
const served = decodePath(parsed.pathname);
|
|
117
|
+
if (!underBase(deployBase, served)) {
|
|
118
|
+
return { kind: "outside-base", path: normalizePath(served) };
|
|
119
|
+
}
|
|
109
120
|
return {
|
|
110
121
|
hash: parsed.hash.slice(1),
|
|
111
122
|
kind: "self-origin",
|
|
112
|
-
path: normalizePath(stripBasePath(deployBase,
|
|
123
|
+
path: normalizePath(stripBasePath(deployBase, served))
|
|
113
124
|
};
|
|
114
125
|
}
|
|
115
126
|
return { kind: "external", url: parsed.toString() };
|
|
@@ -121,14 +132,19 @@ var resolveHref = (pageUrl, href, origin, deployBase = "") => {
|
|
|
121
132
|
} catch {
|
|
122
133
|
return { kind: "ignored" };
|
|
123
134
|
}
|
|
135
|
+
const served = decodePath(resolved.pathname);
|
|
136
|
+
if (target.startsWith("/") && !underBase(deployBase, served)) {
|
|
137
|
+
return { kind: "outside-base", path: normalizePath(served) };
|
|
138
|
+
}
|
|
124
139
|
return {
|
|
125
140
|
hash: resolved.hash.slice(1),
|
|
126
141
|
kind: "internal",
|
|
127
|
-
path: normalizePath(stripBasePath(deployBase,
|
|
142
|
+
path: normalizePath(stripBasePath(deployBase, served))
|
|
128
143
|
};
|
|
129
144
|
};
|
|
130
145
|
|
|
131
146
|
// src/audit/checks/assets.ts
|
|
147
|
+
var VERCEL_IMAGE_ENDPOINT = "/_vercel/image";
|
|
132
148
|
var formatBytes = (bytes) => bytes < 1024 * 1024 ? `${Math.round(bytes / 1024)} kB` : `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
133
149
|
var resolveAsset = (context, page, asset, missingId, kind, found) => {
|
|
134
150
|
if (asset.src.startsWith("http://")) {
|
|
@@ -139,10 +155,18 @@ var resolveAsset = (context, page, asset, missingId, kind, found) => {
|
|
|
139
155
|
return null;
|
|
140
156
|
}
|
|
141
157
|
const origin = siteOrigin(context.project.config.deployment.options.site);
|
|
142
|
-
const
|
|
158
|
+
const deployBase = normalizeBasePath(context.project.config.deployment.options.base);
|
|
159
|
+
const resolved = resolveHref(page.url, asset.src, origin, deployBase);
|
|
143
160
|
if (resolved.kind === "external" || resolved.kind === "ignored") {
|
|
144
161
|
return null;
|
|
145
162
|
}
|
|
163
|
+
if (resolved.path === VERCEL_IMAGE_ENDPOINT) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
if (resolved.kind === "outside-base") {
|
|
167
|
+
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.`));
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
146
170
|
const bytes = context.files.get(resolved.path);
|
|
147
171
|
if (bytes === undefined) {
|
|
148
172
|
found.push(finding(missingId, pageSite(context, page), `Page references ${asset.src}, which is not in the build.`));
|
|
@@ -214,6 +238,9 @@ var frontmatterDate = (source) => {
|
|
|
214
238
|
return null;
|
|
215
239
|
}
|
|
216
240
|
};
|
|
241
|
+
var isGeneratedReference = (page) => page.route?.source.name === "openapi";
|
|
242
|
+
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.";
|
|
243
|
+
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
244
|
var titleChecks = (context, page) => {
|
|
218
245
|
const { titleMin, titleMax } = context.thresholds;
|
|
219
246
|
const [title] = page.titles;
|
|
@@ -229,7 +256,7 @@ var titleChecks = (context, page) => {
|
|
|
229
256
|
const width = stringWidth(title.replaceAll(WHITESPACE, " "));
|
|
230
257
|
if (width > titleMax || width < titleMin) {
|
|
231
258
|
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})
|
|
259
|
+
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
260
|
}
|
|
234
261
|
return found;
|
|
235
262
|
};
|
|
@@ -251,7 +278,7 @@ var descriptionChecks = (context, page) => {
|
|
|
251
278
|
const width = stringWidth(description.replaceAll(WHITESPACE, " "));
|
|
252
279
|
if (width > descriptionMax || width < descriptionMin) {
|
|
253
280
|
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})
|
|
281
|
+
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
282
|
}
|
|
256
283
|
return found;
|
|
257
284
|
};
|
|
@@ -467,6 +494,94 @@ var duplicateChecks = {
|
|
|
467
494
|
tier: "static"
|
|
468
495
|
};
|
|
469
496
|
|
|
497
|
+
// src/audit/checks/indexability.ts
|
|
498
|
+
var parseCanonical = (canonical) => {
|
|
499
|
+
try {
|
|
500
|
+
return new URL(canonical);
|
|
501
|
+
} catch {
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
var isArchivedLatestCanonical = (context, page, target) => {
|
|
506
|
+
const version = page.route?.version;
|
|
507
|
+
const archived = version ? context.project.config.versions?.archived.find((entry) => entry.id === version) : undefined;
|
|
508
|
+
const latestAlternate = page.route?.versionAlternates.find((alternate) => alternate.version === "");
|
|
509
|
+
return archived?.canonical === "latest" && latestAlternate !== undefined && normalizePath(latestAlternate.path) === target;
|
|
510
|
+
};
|
|
511
|
+
var canonicalChecks = (context, page) => {
|
|
512
|
+
const { site } = context.project.config.deployment.options;
|
|
513
|
+
const origin = siteOrigin(site);
|
|
514
|
+
if (ERROR_ROUTES.has(page.url)) {
|
|
515
|
+
return [];
|
|
516
|
+
}
|
|
517
|
+
if (!page.canonical) {
|
|
518
|
+
return site && page.indexable ? [
|
|
519
|
+
finding("BLUME_AUDIT_CANONICAL_MISSING", pageSite(context, page), "Page has no canonical URL.")
|
|
520
|
+
] : [];
|
|
521
|
+
}
|
|
522
|
+
const canonical = parseCanonical(page.canonical);
|
|
523
|
+
if (!canonical) {
|
|
524
|
+
return [
|
|
525
|
+
finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical "${page.canonical}" is not a valid absolute URL.`)
|
|
526
|
+
];
|
|
527
|
+
}
|
|
528
|
+
const found = [];
|
|
529
|
+
if (origin && canonical.origin !== origin) {
|
|
530
|
+
const sameHost = canonical.host === new URL(origin).host;
|
|
531
|
+
if (sameHost) {
|
|
532
|
+
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}//.`));
|
|
533
|
+
}
|
|
534
|
+
return found;
|
|
535
|
+
}
|
|
536
|
+
const target = normalizePath(stripBasePath(normalizeBasePath(context.project.config.deployment.options.base), decodePath(canonical.pathname)));
|
|
537
|
+
if (target === normalizePath(page.url)) {
|
|
538
|
+
return found;
|
|
539
|
+
}
|
|
540
|
+
const redirect = context.redirects.find((entry) => normalizePath(entry.from) === target);
|
|
541
|
+
if (redirect) {
|
|
542
|
+
found.push(finding("BLUME_AUDIT_CANONICAL_BAD_TARGET", pageSite(context, page, ["seo", "canonical"]), `Canonical points at ${target}, which is a redirect to ${redirect.to}.`));
|
|
543
|
+
} else if (context.byUrl.has(target)) {
|
|
544
|
+
if (!(page.route?.fallback === true || isArchivedLatestCanonical(context, page, target))) {
|
|
545
|
+
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.`));
|
|
546
|
+
}
|
|
547
|
+
} else {
|
|
548
|
+
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.`));
|
|
549
|
+
}
|
|
550
|
+
return found;
|
|
551
|
+
};
|
|
552
|
+
var indexabilityChecks = {
|
|
553
|
+
category: "indexability",
|
|
554
|
+
run(context) {
|
|
555
|
+
const found = [];
|
|
556
|
+
if (!context.project.config.deployment.options.site) {
|
|
557
|
+
const { deployment } = context.project.config;
|
|
558
|
+
const site = {
|
|
559
|
+
file: context.project.context.configFile ?? undefined,
|
|
560
|
+
url: "/"
|
|
561
|
+
};
|
|
562
|
+
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."));
|
|
563
|
+
}
|
|
564
|
+
for (const page of context.pages) {
|
|
565
|
+
found.push(...canonicalChecks(context, page));
|
|
566
|
+
if (page.robots && !page.indexable && !ERROR_ROUTES.has(page.url)) {
|
|
567
|
+
found.push(finding("BLUME_AUDIT_ROBOTS_META_UNEXPECTED", pageSite(context, page, ["noindex"]), `Page declares robots "${page.robots}" and will not be indexed.`));
|
|
568
|
+
if (!page.indexable && page.canonical) {
|
|
569
|
+
found.push(finding("BLUME_AUDIT_CANONICAL_ON_NOINDEX", pageSite(context, page, ["noindex"]), `Page is noindex but declares ${page.canonical} as its canonical.`));
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (page.route?.draft) {
|
|
573
|
+
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.`));
|
|
574
|
+
}
|
|
575
|
+
if (page.bytes > context.thresholds.maxHtmlBytes) {
|
|
576
|
+
const mb = (page.bytes / 1024 / 1024).toFixed(1);
|
|
577
|
+
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.`));
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return found;
|
|
581
|
+
},
|
|
582
|
+
tier: "static"
|
|
583
|
+
};
|
|
584
|
+
|
|
470
585
|
// src/audit/checks/i18n.ts
|
|
471
586
|
var deployBaseOf = (context) => normalizeBasePath(context.project.config.deployment.options.base);
|
|
472
587
|
var X_DEFAULT = "x-default";
|
|
@@ -480,11 +595,22 @@ var isValidBcp47 = (tag) => {
|
|
|
480
595
|
};
|
|
481
596
|
var alternatePath = (href, deployBase) => {
|
|
482
597
|
try {
|
|
483
|
-
return normalizePath(stripBasePath(deployBase, new URL(href).pathname));
|
|
598
|
+
return normalizePath(stripBasePath(deployBase, decodePath(new URL(href).pathname)));
|
|
484
599
|
} catch {
|
|
485
600
|
return null;
|
|
486
601
|
}
|
|
487
602
|
};
|
|
603
|
+
var isFallbackCopy = (page) => page.route?.fallback === true;
|
|
604
|
+
var canonicalizesElsewhere = (context, target, deployBase) => {
|
|
605
|
+
if (!target.canonical) {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
const canonical = alternatePath(target.canonical, deployBase);
|
|
609
|
+
if (canonical === normalizePath(target.url)) {
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
return !(canonical !== null && isArchivedLatestCanonical(context, target, canonical));
|
|
613
|
+
};
|
|
488
614
|
var langChecks = (context, page) => {
|
|
489
615
|
if (!page.lang) {
|
|
490
616
|
return [
|
|
@@ -521,7 +647,7 @@ var hreflangChecks = (context, page) => {
|
|
|
521
647
|
found.push(finding("BLUME_AUDIT_HREFLANG_BAD_TARGET", pageSite(context, page), `hreflang="${alternate.lang}" points at ${path}, which redirects to ${redirect.to}.`));
|
|
522
648
|
} else if (!target) {
|
|
523
649
|
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 (
|
|
650
|
+
} else if (canonicalizesElsewhere(context, target, deployBase)) {
|
|
525
651
|
found.push(finding("BLUME_AUDIT_HREFLANG_BAD_TARGET", pageSite(context, page), `hreflang="${alternate.lang}" points at ${path}, which canonicalizes elsewhere.`));
|
|
526
652
|
}
|
|
527
653
|
}
|
|
@@ -547,6 +673,9 @@ var returnTagChecks = (context) => {
|
|
|
547
673
|
const found = [];
|
|
548
674
|
const deployBase = deployBaseOf(context);
|
|
549
675
|
for (const page of context.pages) {
|
|
676
|
+
if (isFallbackCopy(page)) {
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
550
679
|
for (const alternate of page.hreflang) {
|
|
551
680
|
if (alternate.lang === X_DEFAULT) {
|
|
552
681
|
continue;
|
|
@@ -573,7 +702,7 @@ var i18nChecks = {
|
|
|
573
702
|
const found = [];
|
|
574
703
|
for (const page of context.pages) {
|
|
575
704
|
found.push(...langChecks(context, page));
|
|
576
|
-
if (page.hreflang.length > 0) {
|
|
705
|
+
if (page.hreflang.length > 0 && !isFallbackCopy(page)) {
|
|
577
706
|
found.push(...hreflangChecks(context, page));
|
|
578
707
|
}
|
|
579
708
|
}
|
|
@@ -583,92 +712,6 @@ var i18nChecks = {
|
|
|
583
712
|
tier: "static"
|
|
584
713
|
};
|
|
585
714
|
|
|
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
715
|
// src/audit/graph.ts
|
|
673
716
|
var add = (map, key, value) => {
|
|
674
717
|
const existing = map.get(key);
|
|
@@ -746,6 +789,14 @@ var linkChecks = {
|
|
|
746
789
|
if (resolved.kind === "external" || resolved.kind === "ignored") {
|
|
747
790
|
return;
|
|
748
791
|
}
|
|
792
|
+
if (resolved.kind === "outside-base") {
|
|
793
|
+
if (link.content) {
|
|
794
|
+
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.`));
|
|
795
|
+
} else if (!brokenChrome.has(resolved.path)) {
|
|
796
|
+
brokenChrome.set(resolved.path, page);
|
|
797
|
+
}
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
749
800
|
const anchorTarget = resolved.hash ? context.byUrl.get(resolved.path) : undefined;
|
|
750
801
|
if (anchorTarget) {
|
|
751
802
|
checkAnchor(page, link, anchorTarget, resolved.hash);
|
|
@@ -858,7 +909,7 @@ var llmsChecks = {
|
|
|
858
909
|
}
|
|
859
910
|
for (const page of context.pages) {
|
|
860
911
|
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))) {
|
|
912
|
+
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
913
|
continue;
|
|
863
914
|
}
|
|
864
915
|
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 +985,7 @@ var networkChecks = {
|
|
|
934
985
|
found.push(...servedPageChecks(context, page, result, origin));
|
|
935
986
|
}
|
|
936
987
|
const robots = results.get(robotsUrl);
|
|
937
|
-
if (robots && !robots.ok) {
|
|
988
|
+
if (context.project.config.seo.robots && robots && !robots.ok) {
|
|
938
989
|
found.push(finding("BLUME_AUDIT_ROBOTS_NOT_ACCESSIBLE", { url: "/robots.txt" }, `robots.txt is not reachable at ${robotsUrl}.`));
|
|
939
990
|
}
|
|
940
991
|
const sitemap = results.get(sitemapUrl);
|
|
@@ -1046,6 +1097,10 @@ var ogImageChecks = {
|
|
|
1046
1097
|
if (resolved.kind === "external" || resolved.kind === "ignored") {
|
|
1047
1098
|
continue;
|
|
1048
1099
|
}
|
|
1100
|
+
if (resolved.kind === "outside-base") {
|
|
1101
|
+
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.`));
|
|
1102
|
+
continue;
|
|
1103
|
+
}
|
|
1049
1104
|
const { path } = resolved;
|
|
1050
1105
|
if (!(context.files.has(path) || context.files.has(`${path}/index.html`))) {
|
|
1051
1106
|
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 +1172,7 @@ var robotsChecks = {
|
|
|
1117
1172
|
];
|
|
1118
1173
|
}
|
|
1119
1174
|
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) {
|
|
1175
|
+
if (site && context.project.config.seo.sitemap && robots.sitemaps.length === 0) {
|
|
1121
1176
|
found.push(finding("BLUME_AUDIT_ROBOTS_SITEMAP_MISSING", { file: robots.file, url: "/robots.txt" }, "robots.txt does not declare a Sitemap."));
|
|
1122
1177
|
}
|
|
1123
1178
|
const parser = robotsParser(`${MATCH_ORIGIN}/robots.txt`, robots.raw);
|
|
@@ -1195,6 +1250,15 @@ var checkListedUrl = (context, loc, origin, file, deployBase) => {
|
|
|
1195
1250
|
}
|
|
1196
1251
|
return found;
|
|
1197
1252
|
};
|
|
1253
|
+
var unlistedPages = (context, listed, deployBase) => context.pages.flatMap((page) => {
|
|
1254
|
+
const canonical = page.canonical ? canonicalPath(page.canonical, deployBase) : null;
|
|
1255
|
+
if (!page.indexable || page.route?.fallback || canonical && canonical !== normalizePath(page.url) || ERROR_ROUTES2.has(page.url) || listed.has(normalizePath(page.url))) {
|
|
1256
|
+
return [];
|
|
1257
|
+
}
|
|
1258
|
+
return [
|
|
1259
|
+
finding("BLUME_AUDIT_INDEXABLE_PAGE_NOT_IN_SITEMAP", pageSite(context, page), `${page.url} is built and indexable but is not listed in sitemap.xml.`)
|
|
1260
|
+
];
|
|
1261
|
+
});
|
|
1198
1262
|
var sitemapChecks = {
|
|
1199
1263
|
category: "sitemap",
|
|
1200
1264
|
run(context) {
|
|
@@ -1210,11 +1274,21 @@ var sitemapChecks = {
|
|
|
1210
1274
|
}
|
|
1211
1275
|
const found = [];
|
|
1212
1276
|
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}`));
|
|
1277
|
+
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
1278
|
return found;
|
|
1215
1279
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1280
|
+
const parts = sitemap.parts ?? [
|
|
1281
|
+
{
|
|
1282
|
+
bytes: sitemap.bytes,
|
|
1283
|
+
file: sitemap.file,
|
|
1284
|
+
url: "/sitemap.xml",
|
|
1285
|
+
urls: sitemap.urls.length
|
|
1286
|
+
}
|
|
1287
|
+
];
|
|
1288
|
+
for (const part of parts) {
|
|
1289
|
+
if (part.bytes > MAX_SITEMAP_BYTES || part.urls > MAX_SITEMAP_URLS) {
|
|
1290
|
+
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.`));
|
|
1291
|
+
}
|
|
1218
1292
|
}
|
|
1219
1293
|
for (const [loc, lastmod] of sitemap.lastmod ?? []) {
|
|
1220
1294
|
const time = Date.parse(lastmod);
|
|
@@ -1230,12 +1304,7 @@ var sitemapChecks = {
|
|
|
1230
1304
|
for (const loc of sitemap.urls) {
|
|
1231
1305
|
found.push(...checkListedUrl(context, loc, origin, sitemap.file, deployBase));
|
|
1232
1306
|
}
|
|
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
|
-
}
|
|
1307
|
+
found.push(...unlistedPages(context, listed, deployBase));
|
|
1239
1308
|
return found;
|
|
1240
1309
|
},
|
|
1241
1310
|
tier: "static"
|
|
@@ -1317,6 +1386,16 @@ var URL_STYLE = [
|
|
|
1317
1386
|
{ name: "underscores", test: /_/u },
|
|
1318
1387
|
{ name: "spaces", test: /%20| /u }
|
|
1319
1388
|
];
|
|
1389
|
+
var authoredPath = (context, url) => {
|
|
1390
|
+
const { basePath, i18n } = context.project.config;
|
|
1391
|
+
if (!i18n) {
|
|
1392
|
+
return url;
|
|
1393
|
+
}
|
|
1394
|
+
const base = normalizeBasePath(basePath);
|
|
1395
|
+
const [, first = "", ...rest] = stripBasePath(base, url).split("/");
|
|
1396
|
+
const isLocale = i18n.locales.some((locale) => locale.code === first);
|
|
1397
|
+
return isLocale ? `${base}/${rest.join("/")}` : url;
|
|
1398
|
+
};
|
|
1320
1399
|
var DOTTED_HOST = /^\/\/[^/]*\./u;
|
|
1321
1400
|
var doubledSlash = (href) => {
|
|
1322
1401
|
if (href.startsWith("//")) {
|
|
@@ -1343,7 +1422,8 @@ var urlChecks = {
|
|
|
1343
1422
|
doubled.set(href, page);
|
|
1344
1423
|
}
|
|
1345
1424
|
}
|
|
1346
|
-
const
|
|
1425
|
+
const authored = authoredPath(context, page.url);
|
|
1426
|
+
const untidy = URL_STYLE.filter((style) => style.test.test(authored));
|
|
1347
1427
|
if (untidy.length > 0) {
|
|
1348
1428
|
found.push(finding("BLUME_AUDIT_URL_STYLE", pageSite(context, page), `URL ${page.url} contains ${untidy.map((style) => style.name).join(" and ")}.`));
|
|
1349
1429
|
}
|
|
@@ -1538,6 +1618,7 @@ var sitemapParser = new XMLParser({
|
|
|
1538
1618
|
removeNSPrefix: true
|
|
1539
1619
|
});
|
|
1540
1620
|
var isUrlsetElement = (value) => typeof value === "object" && value !== null;
|
|
1621
|
+
var isSitemapIndexElement = (value) => typeof value === "object" && value !== null;
|
|
1541
1622
|
var isUrlEntry = (value) => typeof value === "object" && value !== null;
|
|
1542
1623
|
var isText = (value) => typeof value === "string";
|
|
1543
1624
|
var parseSitemap = (file, xml, bytes) => {
|
|
@@ -1549,8 +1630,14 @@ var parseSitemap = (file, xml, bytes) => {
|
|
|
1549
1630
|
doc.error = "no <urlset> element";
|
|
1550
1631
|
return doc;
|
|
1551
1632
|
}
|
|
1633
|
+
if (Object.hasOwn(parsed, "sitemapindex")) {
|
|
1634
|
+
const { sitemapindex } = parsed;
|
|
1635
|
+
const children = isSitemapIndexElement(sitemapindex) ? [sitemapindex.sitemap].flat() : [];
|
|
1636
|
+
doc.sitemaps = children.flatMap((child) => isUrlEntry(child) && isText(child.loc) && child.loc.trim() ? [child.loc.trim()] : []);
|
|
1637
|
+
return doc;
|
|
1638
|
+
}
|
|
1552
1639
|
if (!Object.hasOwn(parsed, "urlset")) {
|
|
1553
|
-
doc.error =
|
|
1640
|
+
doc.error = "no <urlset> element";
|
|
1554
1641
|
return doc;
|
|
1555
1642
|
}
|
|
1556
1643
|
const { urlset } = parsed;
|
|
@@ -1615,8 +1702,47 @@ var readIfPresent = async (file) => {
|
|
|
1615
1702
|
return null;
|
|
1616
1703
|
}
|
|
1617
1704
|
};
|
|
1705
|
+
var readSitemap = async (staticDir, files, deployBase) => {
|
|
1706
|
+
const file = join2(staticDir, "sitemap.xml");
|
|
1707
|
+
const xml = await readIfPresent(file);
|
|
1708
|
+
if (xml === null) {
|
|
1709
|
+
return null;
|
|
1710
|
+
}
|
|
1711
|
+
const doc = parseSitemap(file, xml, files.get("/sitemap.xml") ?? Buffer.byteLength(xml, "utf-8"));
|
|
1712
|
+
if (!doc.sitemaps) {
|
|
1713
|
+
return doc;
|
|
1714
|
+
}
|
|
1715
|
+
doc.parts = [];
|
|
1716
|
+
for (const loc of doc.sitemaps) {
|
|
1717
|
+
let url;
|
|
1718
|
+
try {
|
|
1719
|
+
url = stripBasePath(deployBase, decodeURI(new URL(loc).pathname));
|
|
1720
|
+
} catch {
|
|
1721
|
+
doc.error = `the sitemap index lists "${loc}", which is not a valid absolute URL`;
|
|
1722
|
+
return doc;
|
|
1723
|
+
}
|
|
1724
|
+
const childFile = join2(staticDir, url);
|
|
1725
|
+
const childXml = await readIfPresent(childFile);
|
|
1726
|
+
const child = childXml === null ? null : parseSitemap(childFile, childXml, files.get(url) ?? Buffer.byteLength(childXml, "utf-8"));
|
|
1727
|
+
if (!child || child.error || child.sitemaps) {
|
|
1728
|
+
doc.error = `the sitemap index lists ${loc}, which is not a urlset in the build`;
|
|
1729
|
+
return doc;
|
|
1730
|
+
}
|
|
1731
|
+
doc.urls.push(...child.urls);
|
|
1732
|
+
for (const [key, value] of child.lastmod ?? []) {
|
|
1733
|
+
doc.lastmod?.set(key, value);
|
|
1734
|
+
}
|
|
1735
|
+
doc.parts.push({
|
|
1736
|
+
bytes: child.bytes,
|
|
1737
|
+
file: childFile,
|
|
1738
|
+
url,
|
|
1739
|
+
urls: child.urls.length
|
|
1740
|
+
});
|
|
1741
|
+
}
|
|
1742
|
+
return doc;
|
|
1743
|
+
};
|
|
1618
1744
|
var crawlStaticDir = async (options) => {
|
|
1619
|
-
const { staticDir, manifest, basePath } = options;
|
|
1745
|
+
const { staticDir, manifest, basePath, deployBase = "" } = options;
|
|
1620
1746
|
const routes = routeIndex(manifest, basePath);
|
|
1621
1747
|
const htmlFiles = await glob("**/*.html", { absolute: true, cwd: staticDir });
|
|
1622
1748
|
const snapshots = await pMap(htmlFiles.toSorted(), async (file) => {
|
|
@@ -1636,8 +1762,6 @@ var crawlStaticDir = async (options) => {
|
|
|
1636
1762
|
});
|
|
1637
1763
|
}, { concurrency: CRAWL_CONCURRENCY });
|
|
1638
1764
|
const pages = snapshots.filter((page) => page !== null);
|
|
1639
|
-
const sitemapFile = join2(staticDir, "sitemap.xml");
|
|
1640
|
-
const sitemapXml = await readIfPresent(sitemapFile);
|
|
1641
1765
|
const robotsFile = join2(staticDir, "robots.txt");
|
|
1642
1766
|
const robotsTxt = await readIfPresent(robotsFile);
|
|
1643
1767
|
const llmsFile = join2(staticDir, "llms.txt");
|
|
@@ -1648,7 +1772,7 @@ var crawlStaticDir = async (options) => {
|
|
|
1648
1772
|
llms: llmsText === null ? null : parseLlms(llmsFile, llmsText),
|
|
1649
1773
|
pages,
|
|
1650
1774
|
robots: robotsTxt === null ? null : parseRobots(robotsFile, robotsTxt),
|
|
1651
|
-
sitemap:
|
|
1775
|
+
sitemap: await readSitemap(staticDir, files, deployBase)
|
|
1652
1776
|
};
|
|
1653
1777
|
};
|
|
1654
1778
|
|
|
@@ -1775,6 +1899,7 @@ var runAudit = async (options) => {
|
|
|
1775
1899
|
const basePath = normalizeBasePath(project.config.basePath);
|
|
1776
1900
|
const crawl = await crawlStaticDir({
|
|
1777
1901
|
basePath,
|
|
1902
|
+
deployBase: normalizeBasePath(project.config.deployment.options.base),
|
|
1778
1903
|
manifest: project.manifest,
|
|
1779
1904
|
staticDir
|
|
1780
1905
|
});
|
|
@@ -1916,7 +2041,7 @@ var auditCommand = defineCommand({
|
|
|
1916
2041
|
}
|
|
1917
2042
|
const agents = Object.keys(AGENTS).filter((kind) => args[kind]);
|
|
1918
2043
|
if (agents.length > 1) {
|
|
1919
|
-
logger.error("Pass at most one of --
|
|
2044
|
+
logger.error("Pass at most one of --codex or --claude.");
|
|
1920
2045
|
process.exit(1);
|
|
1921
2046
|
}
|
|
1922
2047
|
const [agent] = agents;
|
|
@@ -1924,6 +2049,10 @@ var auditCommand = defineCommand({
|
|
|
1924
2049
|
logger.error(`--json and --${agent} are mutually exclusive.`);
|
|
1925
2050
|
process.exit(1);
|
|
1926
2051
|
}
|
|
2052
|
+
if (args.url !== undefined && !isHttpUrl(args.url)) {
|
|
2053
|
+
logger.error(`Invalid --url "${args.url}": pass the deployment's full URL, scheme included (e.g. https://${args.url}).`);
|
|
2054
|
+
process.exit(1);
|
|
2055
|
+
}
|
|
1927
2056
|
const only = splitTerms(args.only);
|
|
1928
2057
|
const skip = splitTerms(args.skip);
|
|
1929
2058
|
rejectUnknownTerms([...only, ...skip]);
|
|
@@ -1985,5 +2114,5 @@ export {
|
|
|
1985
2114
|
shouldFail
|
|
1986
2115
|
};
|
|
1987
2116
|
|
|
1988
|
-
//# debugId=
|
|
1989
|
-
//# sourceMappingURL=chunk-
|
|
2117
|
+
//# debugId=B39D0173C92838E764756E2164756E21
|
|
2118
|
+
//# sourceMappingURL=chunk-hqp2ajnh.js.map
|