blume 2.0.3 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +142 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-5f86nr5m.js → chunk-073rdvgb.js} +21 -48
- package/dist/cli/{chunk-5f86nr5m.js.map → chunk-073rdvgb.js.map} +4 -5
- package/dist/cli/{chunk-ga0pf4aj.js → chunk-0n9xkp3d.js} +12 -3
- package/dist/cli/{chunk-ga0pf4aj.js.map → chunk-0n9xkp3d.js.map} +3 -3
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-9t7a85s3.js → chunk-313vnn40.js} +30 -19
- package/dist/cli/chunk-313vnn40.js.map +10 -0
- package/dist/cli/{chunk-tkacnehg.js → chunk-3v3ffbrj.js} +2 -2
- package/dist/cli/{chunk-q58y5e6a.js → chunk-3x6x3pph.js} +46 -24
- package/dist/cli/chunk-3x6x3pph.js.map +10 -0
- package/dist/cli/{chunk-1d7ve1dm.js → chunk-42t4jxdx.js} +37 -5
- package/dist/cli/chunk-42t4jxdx.js.map +12 -0
- package/dist/cli/{chunk-8ktnccpt.js → chunk-54ztw1nj.js} +21 -2
- package/dist/cli/chunk-54ztw1nj.js.map +10 -0
- package/dist/cli/{chunk-hm3vjy5s.js → chunk-5vjtgs6e.js} +28 -10
- package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-5vjtgs6e.js.map} +4 -4
- package/dist/cli/chunk-66w9j7p6.js +322 -0
- package/dist/cli/chunk-66w9j7p6.js.map +14 -0
- package/dist/cli/{chunk-2hsdwb9n.js → chunk-7ppf1rva.js} +34 -18
- package/dist/cli/chunk-7ppf1rva.js.map +10 -0
- package/dist/cli/{chunk-r9rcc4w7.js → chunk-8y2kmjv8.js} +7 -7
- package/dist/cli/{chunk-r20tn01b.js → chunk-c1y538kd.js} +8 -2
- package/dist/cli/{chunk-r20tn01b.js.map → chunk-c1y538kd.js.map} +3 -3
- package/dist/cli/{chunk-2eytanqx.js → chunk-c887fj0s.js} +2 -2
- package/dist/cli/{chunk-p3v96n38.js → chunk-cfyg47zg.js} +16 -6
- package/dist/cli/chunk-cfyg47zg.js.map +10 -0
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-akbpwfxc.js → chunk-dzwehpy7.js} +2 -2
- package/dist/cli/{chunk-wrr3j9w9.js → chunk-e6atmn4h.js} +299 -72
- package/dist/cli/chunk-e6atmn4h.js.map +36 -0
- package/dist/cli/{chunk-tzmab476.js → chunk-e8xw9qkh.js} +8 -6
- package/dist/cli/{chunk-tzmab476.js.map → chunk-e8xw9qkh.js.map} +3 -3
- package/dist/cli/{chunk-6dsbexzp.js → chunk-e9q7a2ak.js} +17 -15
- package/dist/cli/{chunk-6dsbexzp.js.map → chunk-e9q7a2ak.js.map} +2 -2
- package/dist/cli/{chunk-pv29h0wf.js → chunk-ehweg4fr.js} +5155 -1249
- package/dist/cli/chunk-ehweg4fr.js.map +218 -0
- package/dist/cli/{chunk-c8chx29p.js → chunk-ep6nd0rn.js} +390 -318
- package/dist/cli/chunk-ep6nd0rn.js.map +36 -0
- package/dist/cli/{chunk-p73c0m7w.js → chunk-fdrkhpjy.js} +18 -15
- package/dist/cli/{chunk-p73c0m7w.js.map → chunk-fdrkhpjy.js.map} +3 -3
- package/dist/cli/{chunk-2z928egk.js → chunk-ft9vfys6.js} +5 -5
- package/dist/cli/{chunk-5m5nmvyq.js → chunk-gb420vvz.js} +316 -79
- package/dist/cli/chunk-gb420vvz.js.map +17 -0
- package/dist/cli/{chunk-vg9r4eb9.js → chunk-hebn0tpx.js} +86 -13
- package/dist/cli/chunk-hebn0tpx.js.map +14 -0
- package/dist/cli/{chunk-35d4wj9f.js → chunk-htrwgabr.js} +41 -23
- package/dist/cli/chunk-htrwgabr.js.map +15 -0
- package/dist/cli/{chunk-g4hq16wv.js → chunk-hx3xqnk9.js} +16 -14
- package/dist/cli/{chunk-g4hq16wv.js.map → chunk-hx3xqnk9.js.map} +2 -2
- package/dist/cli/chunk-j134vrp2.js +65 -0
- package/dist/cli/chunk-j134vrp2.js.map +10 -0
- package/dist/cli/{chunk-a58773jm.js → chunk-kma9f6sf.js} +2 -2
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-ey84smr6.js → chunk-mrcccgnh.js} +6 -6
- package/dist/cli/{chunk-ey84smr6.js.map → chunk-mrcccgnh.js.map} +1 -1
- package/dist/cli/{chunk-yfyb25rh.js → chunk-n0v7m8ry.js} +24 -8
- package/dist/cli/chunk-n0v7m8ry.js.map +14 -0
- package/dist/cli/{chunk-j85vccga.js → chunk-ncj7w596.js} +576 -367
- package/dist/cli/chunk-ncj7w596.js.map +35 -0
- package/dist/cli/{chunk-5xvm6tfj.js → chunk-nq1d20w2.js} +17 -15
- package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-nq1d20w2.js.map} +2 -2
- package/dist/cli/{chunk-pehfxfta.js → chunk-nrns10mj.js} +6 -98
- package/dist/cli/chunk-nrns10mj.js.map +10 -0
- package/dist/cli/{chunk-crgn1q09.js → chunk-sds923fa.js} +4 -4
- package/dist/cli/chunk-t2m5j4pr.js +104 -0
- package/dist/cli/chunk-t2m5j4pr.js.map +11 -0
- package/dist/cli/{chunk-acanzt5p.js → chunk-tdqhyxfz.js} +6 -6
- package/dist/cli/chunk-tphac74f.js +126 -0
- package/dist/cli/chunk-tphac74f.js.map +11 -0
- package/dist/cli/chunk-w1r4vase.js +18 -0
- package/dist/cli/chunk-w1r4vase.js.map +10 -0
- package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
- package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
- package/dist/cli/index.js +31 -20
- package/dist/cli/index.js.map +5 -5
- package/dist/types/ai/agent-surface.d.ts +8 -7
- package/dist/types/ai/ai-catalog.d.ts +7 -0
- package/dist/types/ai/ask-context.d.ts +26 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +16 -0
- package/dist/types/astro/integration.d.ts +9 -0
- package/dist/types/astro/markdown-negotiation.d.ts +3 -0
- package/dist/types/astro/pages.d.ts +10 -0
- package/dist/types/captcha/hcaptcha.d.ts +27 -0
- package/dist/types/captcha/index.d.ts +28 -0
- package/dist/types/captcha/schema.d.ts +29 -0
- package/dist/types/captcha/turnstile.d.ts +28 -0
- package/dist/types/cli/init/scaffold.d.ts +1 -1
- package/dist/types/components/content/api-field.d.ts +62 -0
- package/dist/types/components/content/api-page.d.ts +100 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/code-samples.d.ts +29 -0
- package/dist/types/components/openapi/helpers.d.ts +158 -0
- package/dist/types/components/openapi/security.d.ts +95 -0
- package/dist/types/components/openapi/snippets.d.ts +60 -0
- package/dist/types/consent/ethyca.d.ts +48 -0
- package/dist/types/consent/index.d.ts +37 -0
- package/dist/types/consent/native.d.ts +28 -0
- package/dist/types/consent/osano.d.ts +42 -0
- package/dist/types/consent/schema.d.ts +110 -0
- package/dist/types/core/changelog-index.d.ts +8 -0
- package/dist/types/core/config-input.d.ts +217 -23
- package/dist/types/core/data.d.ts +53 -4
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/i18n-ui.d.ts +88 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/links.d.ts +8 -0
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/probe.d.ts +2 -0
- package/dist/types/core/project-graph.d.ts +6 -0
- package/dist/types/core/redirect-patterns.d.ts +152 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +670 -56
- package/dist/types/core/sources/cache.d.ts +3 -0
- package/dist/types/core/sources/contentful-rich-text.d.ts +11 -2
- package/dist/types/core/sources/contentful.d.ts +17 -1
- package/dist/types/core/sources/lexical.d.ts +5 -0
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/sources/remote.d.ts +37 -10
- package/dist/types/core/sources/sanity.d.ts +1 -1
- package/dist/types/core/types.d.ts +18 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/adapter-output.d.ts +2 -1
- package/dist/types/deploy/adapters/cloudflare.d.ts +7 -5
- package/dist/types/deploy/adapters/node.d.ts +58 -23
- package/dist/types/deploy/adapters/registry.d.ts +10 -0
- package/dist/types/deploy/adapters/types.d.ts +3 -2
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +15 -7
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/node.d.ts +3 -1
- package/dist/types/deploy/platforms/types.d.ts +18 -7
- package/dist/types/deploy/platforms/vercel.d.ts +26 -1
- package/dist/types/deploy/redirects.d.ts +55 -11
- package/dist/types/deploy/sitemap.d.ts +2 -1
- package/dist/types/deploy/vercel-negotiation.d.ts +51 -21
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/features.d.ts +3 -2
- package/dist/types/narration/build.d.ts +70 -0
- package/dist/types/narration/provider.d.ts +26 -0
- package/dist/types/narration/script.d.ts +154 -0
- package/dist/types/openapi/checks.d.ts +27 -0
- package/dist/types/openapi/graphql.d.ts +6 -0
- package/dist/types/openapi/model.d.ts +27 -10
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +16 -0
- package/dist/types/openapi/references.d.ts +30 -4
- package/dist/types/ratelimit/cloudflare.d.ts +39 -0
- package/dist/types/ratelimit/index.d.ts +27 -0
- package/dist/types/ratelimit/memory.d.ts +36 -0
- package/dist/types/ratelimit/schema.d.ts +119 -0
- package/dist/types/ratelimit/upstash.d.ts +46 -0
- package/dist/types/ratelimit/wrangler.d.ts +23 -0
- package/dist/types/reference/asyncapi.d.ts +10 -10
- package/dist/types/reference/graphql.d.ts +89 -11
- package/dist/types/reference/index.d.ts +1 -1
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +82 -6
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +144 -36
- package/dist/types/search/adapters/registry.d.ts +3 -0
- package/dist/types/search/adapters/typesense.d.ts +14 -4
- package/dist/types/search/build.d.ts +3 -1
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +13 -9
- package/dist/types/search/sync/algolia.d.ts +5 -2
- package/dist/types/search/sync/index.d.ts +3 -1
- package/dist/types/search/sync/typesense.d.ts +11 -7
- package/dist/types/seo/metatags.d.ts +20 -0
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +54 -0
- package/dist/types/sources/shared.d.ts +3 -0
- package/dist/types/sources/strapi.d.ts +2 -0
- package/docs/01-quickstart.mdx +4 -2
- package/docs/02-deployment.mdx +71 -17
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/advanced/changelog.mdx +13 -2
- package/docs/advanced/skills.mdx +15 -1
- package/docs/cli/audit.mdx +51 -8
- package/docs/cli/doctor.mdx +5 -1
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +1 -0
- package/docs/cli/translate.mdx +1 -0
- package/docs/cli/validate.mdx +4 -3
- package/docs/configuration/analytics.mdx +3 -1
- package/docs/configuration/assistant.mdx +194 -38
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +8 -6
- package/docs/configuration/export.mdx +5 -3
- package/docs/configuration/index.mdx +64 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +90 -0
- package/docs/configuration/search.mdx +63 -12
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +108 -2
- package/docs/content/frontmatter.mdx +80 -2
- package/docs/content/i18n.mdx +39 -4
- package/docs/content/includes.mdx +16 -0
- package/docs/content/meta.mdx +1 -0
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +32 -10
- package/docs/content/sources/contentful.mdx +35 -0
- package/docs/content/sources/custom.mdx +43 -0
- package/docs/content/sources/github-releases.mdx +39 -0
- package/docs/content/sources/index.mdx +91 -0
- package/docs/content/sources/meta.ts +16 -0
- package/docs/content/sources/notion.mdx +32 -0
- package/docs/content/sources/obsidian.mdx +37 -0
- package/docs/content/sources/payload.mdx +31 -0
- package/docs/content/sources/remote-mdx.mdx +44 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +32 -0
- package/docs/content/syntax.mdx +69 -4
- package/docs/content/variables.mdx +41 -0
- package/docs/discoverability/agent-discovery.mdx +29 -2
- package/docs/discoverability/index.mdx +2 -2
- package/docs/discoverability/json-api.mdx +2 -0
- package/docs/discoverability/llms-txt.mdx +2 -2
- package/docs/discoverability/markdown.mdx +3 -1
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +4 -2
- package/docs/references/graphql.mdx +14 -2
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +148 -7
- package/docs/references/scalar.mdx +3 -1
- package/package.json +43 -8
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +7 -7
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +10 -7
- package/skills/blume-migrate/references/starlight.md +11 -8
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +2 -1
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +6 -3
- package/src/ai/ask-context.ts +103 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-limits.ts +13 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/changelog-markdown.ts +11 -6
- package/src/ai/component-markdown.ts +76 -1
- package/src/ai/cors.ts +14 -3
- package/src/ai/index.ts +12 -0
- package/src/ai/llms.ts +6 -2
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/mcp/query.ts +14 -6
- package/src/ai/openapi-components.ts +36 -6
- package/src/ai/relative-links.ts +4 -38
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +35 -2
- package/src/ai/write-skill.ts +97 -0
- package/src/astro/generate.ts +210 -66
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +42 -4
- package/src/astro/markdown-negotiation.ts +3 -0
- package/src/astro/module-types.ts +9 -1
- package/src/astro/pages.ts +23 -0
- package/src/astro/templates.ts +406 -108
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +38 -3
- package/src/audit/checks/contrast.ts +183 -0
- package/src/audit/checks/i18n.ts +2 -3
- package/src/audit/checks/indexability.ts +2 -3
- package/src/audit/checks/links.ts +19 -13
- package/src/audit/checks/network.ts +110 -6
- package/src/audit/checks/redirects.ts +6 -4
- package/src/audit/checks/robots.ts +58 -2
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +5 -0
- package/src/audit/types.ts +4 -1
- package/src/audit/url.ts +14 -5
- package/src/blume-modules.d.ts +12 -1
- package/src/captcha/client.ts +152 -0
- package/src/captcha/hcaptcha.ts +36 -0
- package/src/captcha/index.ts +28 -0
- package/src/captcha/schema.ts +32 -0
- package/src/captcha/turnstile.ts +38 -0
- package/src/captcha/verify.ts +71 -0
- package/src/cli/args.ts +51 -0
- package/src/cli/build-failure.ts +23 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/audit.ts +10 -1
- package/src/cli/commands/dev.ts +18 -2
- package/src/cli/commands/doctor.ts +67 -28
- package/src/cli/commands/eval.ts +36 -4
- package/src/cli/commands/init.ts +6 -4
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/commands/validate.ts +10 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/init/scaffold.ts +3 -3
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +72 -30
- package/src/components/BlumePage.astro +2 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +66 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Color.astro +1 -0
- package/src/components/content/FileTree.astro +1 -0
- package/src/components/content/GithubInfo.astro +1 -0
- package/src/components/content/Panel.astro +1 -0
- package/src/components/content/ParamField.astro +25 -0
- package/src/components/content/RequestExample.astro +17 -0
- package/src/components/content/ResponseExample.astro +17 -0
- package/src/components/content/ResponseField.astro +32 -0
- package/src/components/content/Step.astro +1 -0
- package/src/components/content/Tile.astro +1 -0
- package/src/components/content/Tooltip.astro +1 -0
- package/src/components/content/Tree.astro +1 -0
- package/src/components/content/TypeTable.astro +4 -1
- package/src/components/content/View.astro +21 -0
- package/src/components/content/ViewSwitcher.astro +168 -0
- package/src/components/content/api-field.ts +103 -0
- package/src/components/content/api-page.ts +248 -0
- package/src/components/content/mermaid-element.ts +15 -1
- package/src/components/content/view-switcher.ts +71 -0
- package/src/components/index.ts +2 -0
- package/src/components/islands/Assistant.astro +10 -1
- package/src/components/islands/assistant.tsx +104 -14
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +136 -21
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +6 -2
- package/src/components/layout/ConsentBanner.astro +62 -0
- package/src/components/layout/ConsentHead.astro +38 -0
- package/src/components/layout/Directory.astro +94 -0
- package/src/components/layout/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +122 -80
- package/src/components/layout/LanguageSwitcher.astro +48 -15
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +33 -7
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +71 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +318 -47
- package/src/components/layout/Search.astro +47 -19
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/TableOfContents.astro +24 -17
- package/src/components/layout/consent/native.ts +79 -0
- package/src/components/layout/consent/types.ts +37 -0
- package/src/components/layout/footer-links.ts +53 -0
- package/src/components/layout/footer-socials.ts +87 -0
- package/src/components/layout/head-scripts.ts +6 -1
- package/src/components/layout/locale-redirect.ts +107 -0
- package/src/components/layout/nav-utils.ts +83 -0
- package/src/components/layout/page-feedback.ts +96 -0
- package/src/components/layout/search/algolia.ts +10 -1
- package/src/components/layout/search/analytics.ts +126 -0
- package/src/components/layout/search/endpoint.ts +48 -5
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/pagefind.ts +114 -5
- package/src/components/layout/search/types.ts +32 -0
- package/src/components/layout/search/typesense.ts +19 -3
- package/src/components/openapi/AsyncApiOperation.astro +14 -7
- package/src/components/openapi/Authorization.astro +10 -0
- package/src/components/openapi/GraphqlOperation.astro +5 -0
- package/src/components/openapi/Operation.astro +184 -13
- package/src/components/openapi/ParametersTable.astro +8 -4
- package/src/components/openapi/Playground.astro +7 -1
- package/src/components/openapi/RequestBody.astro +24 -5
- package/src/components/openapi/RequestPanel.astro +59 -7
- package/src/components/openapi/Responses.astro +7 -4
- package/src/components/openapi/SchemaTable.astro +15 -3
- package/src/components/openapi/async-snippets.ts +65 -9
- package/src/components/openapi/async.ts +123 -29
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/graphql-helpers.ts +35 -12
- package/src/components/openapi/helpers.ts +36 -2
- package/src/components/openapi/message-model.ts +54 -11
- package/src/components/openapi/message.ts +14 -4
- package/src/components/openapi/operation-model.ts +16 -7
- package/src/components/openapi/playground-client.ts +24 -5
- package/src/components/openapi/playground-schema.ts +1 -1
- package/src/components/openapi/schema-tree.ts +44 -14
- package/src/components/openapi/security.ts +16 -3
- package/src/components/openapi/snippets.ts +873 -10
- package/src/components/openapi/validate-json.ts +4 -3
- package/src/components/props.ts +6 -0
- package/src/consent/client.ts +95 -0
- package/src/consent/clients.ts +19 -0
- package/src/consent/ethyca.ts +71 -0
- package/src/consent/head.ts +24 -0
- package/src/consent/index.ts +37 -0
- package/src/consent/init.ts +29 -0
- package/src/consent/native.ts +36 -0
- package/src/consent/osano.ts +59 -0
- package/src/consent/schema.ts +30 -0
- package/src/core/builtin-tags.ts +5 -0
- package/src/core/changelog-index.ts +31 -1
- package/src/core/client-address.ts +19 -0
- package/src/core/component-diagnostics.ts +53 -0
- package/src/core/component-overrides.ts +32 -0
- package/src/core/config-input.ts +225 -23
- package/src/core/data.ts +46 -4
- package/src/core/diagnostics.ts +8 -2
- package/src/core/footer.ts +26 -0
- package/src/core/graph.ts +39 -36
- package/src/core/i18n-ui.ts +84 -2
- package/src/core/includes.ts +21 -4
- package/src/core/links.ts +63 -19
- package/src/core/localizable.ts +26 -0
- package/src/core/navigation.ts +43 -12
- package/src/core/page-modes.ts +56 -0
- package/src/core/probe.ts +26 -6
- package/src/core/project-graph.ts +163 -16
- package/src/core/redirect-patterns.ts +520 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +339 -66
- package/src/core/sources/cache.ts +6 -0
- package/src/core/sources/contentful-rich-text.ts +29 -6
- package/src/core/sources/contentful.ts +135 -25
- package/src/core/sources/filesystem.ts +26 -4
- package/src/core/sources/github-releases.ts +12 -1
- package/src/core/sources/lexical.ts +15 -10
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +228 -41
- package/src/core/sources/notion.ts +7 -1
- package/src/core/sources/obsidian.ts +16 -3
- package/src/core/sources/payload.ts +38 -15
- package/src/core/sources/read.ts +8 -3
- package/src/core/sources/remote.ts +72 -15
- package/src/core/sources/resolve.ts +11 -1
- package/src/core/sources/sanity.ts +43 -25
- package/src/core/sources/strapi.ts +2 -2
- package/src/core/types.ts +19 -1
- package/src/core/ui-packs/ar.ts +44 -0
- package/src/core/ui-packs/bg.ts +46 -0
- package/src/core/ui-packs/bn.ts +44 -0
- package/src/core/ui-packs/ca.ts +47 -0
- package/src/core/ui-packs/cs.ts +45 -0
- package/src/core/ui-packs/da.ts +46 -0
- package/src/core/ui-packs/de.ts +47 -0
- package/src/core/ui-packs/el.ts +46 -0
- package/src/core/ui-packs/es.ts +47 -0
- package/src/core/ui-packs/fa.ts +46 -0
- package/src/core/ui-packs/fi.ts +46 -0
- package/src/core/ui-packs/fr.ts +47 -0
- package/src/core/ui-packs/he.ts +44 -0
- package/src/core/ui-packs/hi.ts +45 -0
- package/src/core/ui-packs/hr.ts +46 -0
- package/src/core/ui-packs/hu.ts +45 -0
- package/src/core/ui-packs/id.ts +46 -0
- package/src/core/ui-packs/it.ts +46 -0
- package/src/core/ui-packs/ja.ts +46 -0
- package/src/core/ui-packs/ko.ts +45 -0
- package/src/core/ui-packs/nl.ts +47 -0
- package/src/core/ui-packs/no.ts +45 -0
- package/src/core/ui-packs/pl.ts +46 -0
- package/src/core/ui-packs/pt-br.ts +47 -0
- package/src/core/ui-packs/pt.ts +46 -0
- package/src/core/ui-packs/ro.ts +46 -0
- package/src/core/ui-packs/ru.ts +46 -0
- package/src/core/ui-packs/sk.ts +45 -0
- package/src/core/ui-packs/sr.ts +46 -0
- package/src/core/ui-packs/sv.ts +45 -0
- package/src/core/ui-packs/th.ts +44 -0
- package/src/core/ui-packs/tr.ts +46 -0
- package/src/core/ui-packs/uk.ts +46 -0
- package/src/core/ui-packs/vi.ts +46 -0
- package/src/core/ui-packs/zh-tw.ts +44 -0
- package/src/core/ui-packs/zh.ts +44 -0
- package/src/core/variables.ts +103 -0
- package/src/deploy/adapter-output.ts +7 -2
- package/src/deploy/adapters/cloudflare.ts +7 -5
- package/src/deploy/adapters/node.ts +47 -9
- package/src/deploy/adapters/types.ts +7 -3
- package/src/deploy/artifacts.ts +79 -9
- package/src/deploy/cloudflare-negotiation.ts +35 -5
- package/src/deploy/headers.ts +2 -1
- package/src/deploy/node-headers.ts +63 -9
- package/src/deploy/platforms/cloudflare.ts +45 -9
- package/src/deploy/platforms/netlify.ts +35 -2
- package/src/deploy/platforms/node.ts +12 -2
- package/src/deploy/platforms/types.ts +21 -7
- package/src/deploy/platforms/vercel.ts +149 -17
- package/src/deploy/redirects.ts +151 -24
- package/src/deploy/rss.ts +3 -1
- package/src/deploy/sitemap.ts +39 -5
- package/src/deploy/vercel-negotiation.ts +326 -102
- package/src/eval/agents.ts +18 -1
- package/src/eval/prompts.ts +6 -3
- package/src/eval/report.ts +34 -13
- package/src/eval/run.ts +5 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/features.ts +3 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +28 -5
- package/src/markdown/math.ts +4 -4
- package/src/markdown/relative-links.ts +3 -2
- package/src/markdown/variables.ts +56 -0
- package/src/markdown/views.ts +82 -0
- package/src/narration/build.ts +412 -0
- package/src/narration/player.ts +249 -0
- package/src/narration/provider.ts +29 -0
- package/src/narration/script.ts +592 -0
- package/src/og/card.ts +7 -6
- package/src/openapi/checks.ts +273 -0
- package/src/openapi/graphql-build.ts +21 -0
- package/src/openapi/graphql.ts +11 -0
- package/src/openapi/model.ts +72 -27
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +182 -4
- package/src/openapi/references.ts +64 -8
- package/src/openapi/render-mdx.ts +5 -1
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +40 -15
- package/src/ratelimit/cloudflare.ts +54 -0
- package/src/ratelimit/index.ts +30 -0
- package/src/ratelimit/memory.ts +45 -0
- package/src/ratelimit/runtime.ts +247 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +60 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +20 -3
- package/src/reference/index.ts +1 -0
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +80 -8
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +23 -5
- package/src/registry/registry.ts +7 -0
- package/src/search/adapters/locale-scope.ts +30 -0
- package/src/search/adapters/typesense.ts +14 -4
- package/src/search/build.ts +21 -3
- package/src/search/documents.ts +26 -2
- package/src/search/orama-index.ts +191 -34
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/source-pages.ts +29 -0
- package/src/search/sync/algolia.ts +111 -10
- package/src/search/sync/index.ts +52 -13
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +76 -26
- package/src/seo/metatags.ts +67 -0
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/shared.ts +3 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +85 -6
- package/src/theme/palette.ts +121 -45
- package/src/translate/prompts.ts +1 -0
- package/src/translate/validate.ts +31 -3
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-1d7ve1dm.js.map +0 -12
- package/dist/cli/chunk-2hsdwb9n.js.map +0 -10
- package/dist/cli/chunk-35d4wj9f.js.map +0 -15
- package/dist/cli/chunk-364znk6q.js +0 -75
- package/dist/cli/chunk-364znk6q.js.map +0 -11
- package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
- package/dist/cli/chunk-8ktnccpt.js.map +0 -10
- package/dist/cli/chunk-9t7a85s3.js.map +0 -10
- package/dist/cli/chunk-b07cmahc.js +0 -145
- package/dist/cli/chunk-b07cmahc.js.map +0 -11
- package/dist/cli/chunk-c8chx29p.js.map +0 -36
- package/dist/cli/chunk-e04dxsz1.js +0 -39
- package/dist/cli/chunk-e04dxsz1.js.map +0 -10
- package/dist/cli/chunk-j85vccga.js.map +0 -36
- package/dist/cli/chunk-p3v96n38.js.map +0 -10
- package/dist/cli/chunk-pehfxfta.js.map +0 -10
- package/dist/cli/chunk-pv29h0wf.js.map +0 -190
- package/dist/cli/chunk-q58y5e6a.js.map +0 -10
- package/dist/cli/chunk-vg9r4eb9.js.map +0 -14
- package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
- package/dist/cli/chunk-yfyb25rh.js.map +0 -14
- package/docs/content/sources.mdx +0 -334
- /package/dist/cli/{chunk-tkacnehg.js.map → chunk-3v3ffbrj.js.map} +0 -0
- /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-8y2kmjv8.js.map} +0 -0
- /package/dist/cli/{chunk-2eytanqx.js.map → chunk-c887fj0s.js.map} +0 -0
- /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-dzwehpy7.js.map} +0 -0
- /package/dist/cli/{chunk-2z928egk.js.map → chunk-ft9vfys6.js.map} +0 -0
- /package/dist/cli/{chunk-a58773jm.js.map → chunk-kma9f6sf.js.map} +0 -0
- /package/dist/cli/{chunk-crgn1q09.js.map → chunk-sds923fa.js.map} +0 -0
- /package/dist/cli/{chunk-acanzt5p.js.map → chunk-tdqhyxfz.js.map} +0 -0
|
@@ -4,9 +4,10 @@ import type { ValidationSchema } from "./request.ts";
|
|
|
4
4
|
* Minimal JSON-schema validation for the playground body editor. Client-safe
|
|
5
5
|
* and dependency-free by design: the server prunes the operation's schema into
|
|
6
6
|
* the tiny `ValidationSchema` subset (`operation-model.ts`), so a full
|
|
7
|
-
* draft-2020 validator would be dead weight in the browser bundle.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* draft-2020 validator would be dead weight in the browser bundle. The checks
|
|
8
|
+
* catch the common "typo'd a required field" mistakes, and any error they
|
|
9
|
+
* report blocks the Try it send (`playground-client.ts`) and the event
|
|
10
|
+
* composer's connect and send (`message-composer.ts`).
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
/** An already-parsed JSON object — string keys, parsed-JSON values. */
|
package/src/components/props.ts
CHANGED
|
@@ -44,9 +44,15 @@ export type FrameProps = ComponentProps<
|
|
|
44
44
|
export type PanelProps = ComponentProps<
|
|
45
45
|
typeof import("./content/Panel.astro").default
|
|
46
46
|
>;
|
|
47
|
+
export type ParamFieldProps = ComponentProps<
|
|
48
|
+
typeof import("./content/ParamField.astro").default
|
|
49
|
+
>;
|
|
47
50
|
export type PromptProps = ComponentProps<
|
|
48
51
|
typeof import("./content/Prompt.astro").default
|
|
49
52
|
>;
|
|
53
|
+
export type ResponseFieldProps = ComponentProps<
|
|
54
|
+
typeof import("./content/ResponseField.astro").default
|
|
55
|
+
>;
|
|
50
56
|
export type StepProps = ComponentProps<
|
|
51
57
|
typeof import("./content/Step.astro").default
|
|
52
58
|
>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser half of the consent layer (`consent` in `blume.config.ts`),
|
|
3
|
+
* bundled into every layout by `ConsentHead.astro` and started once per real
|
|
4
|
+
* page load. It answers `window.blumeConsent` (see `init.ts`):
|
|
5
|
+
*
|
|
6
|
+
* - Analytics scripts wait in the page as `<script type="text/plain"
|
|
7
|
+
* data-blume-consent="analytics">` (see `Analytics.astro`). Once the reader
|
|
8
|
+
* allows analytics, each one runs, once per page load: the client router
|
|
9
|
+
* brings the held tags back on every navigation, and running them again
|
|
10
|
+
* would count every visit twice.
|
|
11
|
+
* - A reader who takes consent back after the scripts ran gets a reload, the
|
|
12
|
+
* one way to stop scripts that already started.
|
|
13
|
+
* - Any element with `data-blume-consent-open` (the footer's Cookie settings
|
|
14
|
+
* link) reopens the adapter's preferences.
|
|
15
|
+
* - An adapter with a browser module (`native()`'s banner, say) is started
|
|
16
|
+
* from here once the runtime is listening; see `consent/clients.ts`.
|
|
17
|
+
*/
|
|
18
|
+
import type { BlumeConsent } from "../components/layout/consent/types.ts";
|
|
19
|
+
|
|
20
|
+
/** The window, with the state the init script puts on it. */
|
|
21
|
+
type ConsentWindow = Window & { blumeConsent?: BlumeConsent };
|
|
22
|
+
|
|
23
|
+
/** Analytics tags held until the reader allows analytics. */
|
|
24
|
+
export const HELD_SCRIPTS =
|
|
25
|
+
'script[type="text/plain"][data-blume-consent="analytics"]';
|
|
26
|
+
|
|
27
|
+
const OPEN = "[data-blume-consent-open]";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Run each held tag the page hasn't run yet, as a new `<script>` beside it
|
|
31
|
+
* with the same attributes and body. `ran` is keyed by the tag's markup,
|
|
32
|
+
* which is the same on every page, so a tag the router brings back is
|
|
33
|
+
* skipped.
|
|
34
|
+
*/
|
|
35
|
+
export const runHeldScripts = (ran: Set<string>): void => {
|
|
36
|
+
for (const held of document.querySelectorAll(HELD_SCRIPTS)) {
|
|
37
|
+
const key = held.outerHTML;
|
|
38
|
+
if (ran.has(key)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
ran.add(key);
|
|
42
|
+
const script = document.createElement("script");
|
|
43
|
+
for (const { name, value } of held.attributes) {
|
|
44
|
+
if (name !== "type" && name !== "data-blume-consent") {
|
|
45
|
+
script.setAttribute(name, value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// A created script is async unless told otherwise; keep the tags in
|
|
49
|
+
// document order, as the parser would have, unless one asked for async.
|
|
50
|
+
if (!held.hasAttribute("async")) {
|
|
51
|
+
script.async = false;
|
|
52
|
+
}
|
|
53
|
+
script.text = held.textContent ?? "";
|
|
54
|
+
held.after(script);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Start the consent runtime on this page load, then the configured adapter's
|
|
60
|
+
* browser module (`startClient`, from the generated `blume:consent-client`;
|
|
61
|
+
* none for a hosted manager, whose `<head>` tags report its answers).
|
|
62
|
+
*/
|
|
63
|
+
export const startConsent = (
|
|
64
|
+
startClient: (consent: BlumeConsent) => void = () => {
|
|
65
|
+
// No browser module: a hosted manager's <head> tags report its answers.
|
|
66
|
+
}
|
|
67
|
+
): void => {
|
|
68
|
+
// SAFETY: ConsentWindow only adds the optional state the init script
|
|
69
|
+
// creates; it's checked before use.
|
|
70
|
+
const consent = (window as ConsentWindow).blumeConsent;
|
|
71
|
+
if (!consent) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const ran = new Set<string>();
|
|
75
|
+
const run = () => {
|
|
76
|
+
if (consent.analytics === true) {
|
|
77
|
+
runHeldScripts(ran);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
window.addEventListener("blume:consent", () => {
|
|
81
|
+
if (consent.analytics === true) {
|
|
82
|
+
runHeldScripts(ran);
|
|
83
|
+
} else if (ran.size > 0) {
|
|
84
|
+
location.reload();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
document.addEventListener("click", (event) => {
|
|
88
|
+
if (event.target instanceof Element && event.target.closest(OPEN)) {
|
|
89
|
+
consent.open?.();
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
startClient(consent);
|
|
93
|
+
run();
|
|
94
|
+
document.addEventListener("astro:after-swap", run);
|
|
95
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser module each consent adapter brings, by `kind`. The generated
|
|
3
|
+
* `blume:consent-client` (see `consentClientTemplate`) imports the configured
|
|
4
|
+
* adapter's, so a site bundles only its own adapter's browser code, the way
|
|
5
|
+
* `blume:search-client` does for search.
|
|
6
|
+
*
|
|
7
|
+
* Hosted managers (`osano()`, `ethyca()`) have none: their `<head>` tags load
|
|
8
|
+
* them and report their answers (see `head.ts`). A manager that ships as an
|
|
9
|
+
* npm package adds its module under `components/layout/consent/` instead: a
|
|
10
|
+
* `start` (`ConsentClientStart` in its `types.ts`) that reports the reader's answer with
|
|
11
|
+
* `consent.set({ analytics })` and sets `consent.open`, with the packages it
|
|
12
|
+
* imports listed in its factory's `runtimeDeps`, so only the sites that pick
|
|
13
|
+
* it install them.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Each adapter's browser module, as the generated project imports it. */
|
|
17
|
+
export const CONSENT_CLIENT_MODULES = new Map([
|
|
18
|
+
["native", "blume/components/layout/consent/native.ts"],
|
|
19
|
+
]);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import type { HeadScript } from "../analytics/head.ts";
|
|
4
|
+
import type { AdapterDescriptor } from "../core/adapter.ts";
|
|
5
|
+
import { adapterDescriptorSchema } from "../core/adapter.ts";
|
|
6
|
+
|
|
7
|
+
/** Options for {@link ethyca}. */
|
|
8
|
+
export interface EthycaOptions {
|
|
9
|
+
/**
|
|
10
|
+
* The key of the privacy notice that covers analytics, as you named it in
|
|
11
|
+
* Fides. Defaults to `analytics`.
|
|
12
|
+
*/
|
|
13
|
+
notice?: string;
|
|
14
|
+
/** Your Fides privacy center's origin, which serves `fides.js`. */
|
|
15
|
+
privacyCenter: string;
|
|
16
|
+
/** The Fides property to load, when you have more than one. */
|
|
17
|
+
propertyId?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const ethycaOptionsSchema = z.strictObject({
|
|
21
|
+
notice: z.string().min(1).optional(),
|
|
22
|
+
privacyCenter: z.url({ protocol: /^https?$/u }),
|
|
23
|
+
propertyId: z.string().min(1).optional(),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export type EthycaAdapter = AdapterDescriptor<"ethyca", EthycaOptions>;
|
|
27
|
+
|
|
28
|
+
export const ethycaAdapterSchema = adapterDescriptorSchema(
|
|
29
|
+
"ethyca",
|
|
30
|
+
ethycaOptionsSchema
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Ethyca's Fides consent manager, loaded from your privacy center. Fides
|
|
35
|
+
* shows its own banner and modal, set up in Fides, and Blume runs the
|
|
36
|
+
* analytics once the reader's analytics notice is on. Nothing here is
|
|
37
|
+
* secret.
|
|
38
|
+
*/
|
|
39
|
+
export const ethyca = (options: EthycaOptions): EthycaAdapter => ({
|
|
40
|
+
kind: "ethyca",
|
|
41
|
+
options,
|
|
42
|
+
requiredSecrets: [],
|
|
43
|
+
runtimeDeps: [],
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Reports the analytics notice to `window.blumeConsent` when Fides is ready
|
|
48
|
+
* and whenever the reader saves a change, and reopens Fides' modal from the
|
|
49
|
+
* Cookie settings link. The notice key rides in as `data-notice`. It counts
|
|
50
|
+
* as allowed when on (`true`), opted in, or a notice that only asks for
|
|
51
|
+
* acknowledgment.
|
|
52
|
+
*/
|
|
53
|
+
export const ETHYCA_BRIDGE = `(()=>{const c=window.blumeConsent;if(!c){return;}const k=document.currentScript?.dataset.notice??"analytics";const sync=(e)=>{const v=(e?.detail?.consent??window.Fides?.consent??{})[k];c.set({analytics:v===true||v==="opt_in"||v==="acknowledge"});};c.open=()=>window.Fides?.showModal();addEventListener("FidesReady",sync);addEventListener("FidesUpdated",sync);if(window.Fides?.initialized){sync();}})();`;
|
|
54
|
+
|
|
55
|
+
/** Fides' script from the privacy center, then the bridge. */
|
|
56
|
+
export const ethycaHead = (options: EthycaOptions): HeadScript[] => {
|
|
57
|
+
const src = new URL(
|
|
58
|
+
"fides.js",
|
|
59
|
+
`${options.privacyCenter.replace(/\/+$/u, "")}/`
|
|
60
|
+
);
|
|
61
|
+
if (options.propertyId) {
|
|
62
|
+
src.searchParams.set("property_id", options.propertyId);
|
|
63
|
+
}
|
|
64
|
+
return [
|
|
65
|
+
{ attributes: { src: src.href }, content: null },
|
|
66
|
+
{
|
|
67
|
+
attributes: { "data-notice": options.notice ?? "analytics" },
|
|
68
|
+
content: ETHYCA_BRIDGE,
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { HeadScript } from "../analytics/head.ts";
|
|
2
|
+
import { ethycaHead } from "./ethyca.ts";
|
|
3
|
+
import { osanoHead } from "./osano.ts";
|
|
4
|
+
import type { ConsentAdapter } from "./schema.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The tags one consent adapter emits into `<head>`, after the init script and
|
|
8
|
+
* ahead of the held analytics: a hosted manager's loader and the bridge that
|
|
9
|
+
* reports its answers to `window.blumeConsent`. `native()` has none; its
|
|
10
|
+
* banner is markup (`ConsentBanner.astro`) and its logic is the runtime's.
|
|
11
|
+
*/
|
|
12
|
+
export const consentHead = (adapter: ConsentAdapter): HeadScript[] => {
|
|
13
|
+
switch (adapter.kind) {
|
|
14
|
+
case "ethyca": {
|
|
15
|
+
return ethycaHead(adapter.options);
|
|
16
|
+
}
|
|
17
|
+
case "osano": {
|
|
18
|
+
return osanoHead(adapter.options);
|
|
19
|
+
}
|
|
20
|
+
default: {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consent adapters for `blume.config.ts`:
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* import { defineConfig } from "blume";
|
|
6
|
+
* import { googleAnalytics } from "blume/analytics";
|
|
7
|
+
* import { native } from "blume/consent";
|
|
8
|
+
*
|
|
9
|
+
* export default defineConfig({
|
|
10
|
+
* analytics: [googleAnalytics({ id: "G-XXXXXXXXXX" })],
|
|
11
|
+
* consent: native({ policy: "/privacy" }),
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* With `consent` set, analytics waits for the reader: every adapter's tags are
|
|
16
|
+
* held until the consent adapter reports that analytics is allowed. Each
|
|
17
|
+
* factory returns a plain descriptor (see `core/adapter.ts`).
|
|
18
|
+
*
|
|
19
|
+
* Adding a consent manager: a factory and option schema in its own module,
|
|
20
|
+
* and a member of `consentAdapterSchema` (`schema.ts`). Then connect it to
|
|
21
|
+
* `window.blumeConsent` (see `init.ts` for the contract): report the reader's
|
|
22
|
+
* choice with `set({ analytics })` on load and on every change, and set
|
|
23
|
+
* `open` to reopen the manager's preferences. A hosted manager does that
|
|
24
|
+
* with tags in `consentHead` (`head.ts`): its loader, then a constant bridge
|
|
25
|
+
* script (`osano.ts` is an example). A manager that ships as an npm package
|
|
26
|
+
* does it in a browser module instead, registered in `clients.ts`, with its
|
|
27
|
+
* packages in the factory's `runtimeDeps` (`native()`'s banner is the
|
|
28
|
+
* example).
|
|
29
|
+
*/
|
|
30
|
+
export type { AdapterDescriptor, JsonValue } from "../core/adapter.ts";
|
|
31
|
+
export { ethyca } from "./ethyca.ts";
|
|
32
|
+
export type { EthycaAdapter, EthycaOptions } from "./ethyca.ts";
|
|
33
|
+
export { native } from "./native.ts";
|
|
34
|
+
export type { NativeAdapter, NativeOptions } from "./native.ts";
|
|
35
|
+
export { osano } from "./osano.ts";
|
|
36
|
+
export type { OsanoAdapter, OsanoOptions } from "./osano.ts";
|
|
37
|
+
export type { ConsentAdapter } from "./schema.ts";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The consent layer's first script, inlined at the top of `<head>` on every
|
|
3
|
+
* page when `consent` is configured, ahead of any adapter's script and the
|
|
4
|
+
* held analytics. It creates `window.blumeConsent`, the one contract every
|
|
5
|
+
* consent adapter talks to:
|
|
6
|
+
*
|
|
7
|
+
* - `analytics`: `null` until an adapter reports, then the reader's choice.
|
|
8
|
+
* - `set({ analytics })`: what an adapter calls with the reader's choice, on
|
|
9
|
+
* load for a returning reader and again whenever it changes. A change fires
|
|
10
|
+
* a `blume:consent` event on `window` (`detail: { analytics }`), which the
|
|
11
|
+
* runtime (`client.ts`) answers by running the held analytics, and which a
|
|
12
|
+
* site can listen to for its own scripts.
|
|
13
|
+
* - `open()`: set by an adapter to reopen its preferences; the footer's
|
|
14
|
+
* Cookie settings link calls it.
|
|
15
|
+
* - `kind`: the configured adapter (`native`, `osano`, …), from the tag's
|
|
16
|
+
* `data-kind`.
|
|
17
|
+
*
|
|
18
|
+
* It also sets `window.webAnalyticsBeforeSend`, which Vercel Web Analytics
|
|
19
|
+
* reads when it starts, so `vercel()` sends nothing until analytics is
|
|
20
|
+
* allowed; its script is a component rather than a tag, so it can't be held
|
|
21
|
+
* like the others.
|
|
22
|
+
*
|
|
23
|
+
* A constant, like the layouts' other inline scripts (see
|
|
24
|
+
* `components/layout/head-scripts.ts`): the kind rides in as an attribute,
|
|
25
|
+
* never as interpolated source. It runs once per real page load; the client
|
|
26
|
+
* router never runs an inline script twice, and the state it creates lives
|
|
27
|
+
* on across navigations.
|
|
28
|
+
*/
|
|
29
|
+
export const CONSENT_INIT_SCRIPT = `(()=>{if(window.blumeConsent){return;}const c={analytics:null,kind:document.currentScript?.dataset.kind??"",set(s){const a=s?.analytics===true;if(c.analytics===a){return;}c.analytics=a;dispatchEvent(new CustomEvent("blume:consent",{detail:{analytics:a}}));}};window.blumeConsent=c;window.webAnalyticsBeforeSend=(e)=>c.analytics===true?e:null;})();`;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import type { AdapterDescriptor } from "../core/adapter.ts";
|
|
4
|
+
import { adapterDescriptorSchema } from "../core/adapter.ts";
|
|
5
|
+
|
|
6
|
+
/** Options for {@link native}. */
|
|
7
|
+
export interface NativeOptions {
|
|
8
|
+
/** Where the banner's privacy policy link goes: a page route or a URL. */
|
|
9
|
+
policy?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const nativeOptionsSchema = z.strictObject({
|
|
13
|
+
policy: z.string().min(1).optional(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export type NativeAdapter = AdapterDescriptor<"native", NativeOptions>;
|
|
17
|
+
|
|
18
|
+
export const nativeAdapterSchema = adapterDescriptorSchema(
|
|
19
|
+
"native",
|
|
20
|
+
nativeOptionsSchema
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Blume's own consent banner: a card at the foot of the page asking to use
|
|
25
|
+
* analytics cookies, with Accept and Decline side by side and an optional
|
|
26
|
+
* link to your privacy policy. The answer stays in the reader's browser, and
|
|
27
|
+
* the footer's Cookie settings link brings the banner back to change it. Its
|
|
28
|
+
* text comes from the `consent` UI strings, translated in every built-in
|
|
29
|
+
* language.
|
|
30
|
+
*/
|
|
31
|
+
export const native = (options: NativeOptions = {}): NativeAdapter => ({
|
|
32
|
+
kind: "native",
|
|
33
|
+
options,
|
|
34
|
+
requiredSecrets: [],
|
|
35
|
+
runtimeDeps: [],
|
|
36
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import type { HeadScript } from "../analytics/head.ts";
|
|
4
|
+
import type { AdapterDescriptor } from "../core/adapter.ts";
|
|
5
|
+
import { adapterDescriptorSchema } from "../core/adapter.ts";
|
|
6
|
+
|
|
7
|
+
/** Options for {@link osano}. */
|
|
8
|
+
export interface OsanoOptions {
|
|
9
|
+
/** The configuration ID from the script tag Osano gives you. */
|
|
10
|
+
configId: string;
|
|
11
|
+
/** The customer ID from the script tag Osano gives you. */
|
|
12
|
+
customerId: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const osanoOptionsSchema = z.strictObject({
|
|
16
|
+
configId: z.string().min(1),
|
|
17
|
+
customerId: z.string().min(1),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export type OsanoAdapter = AdapterDescriptor<"osano", OsanoOptions>;
|
|
21
|
+
|
|
22
|
+
export const osanoAdapterSchema = adapterDescriptorSchema(
|
|
23
|
+
"osano",
|
|
24
|
+
osanoOptionsSchema
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Osano Cookie Consent. Osano shows its own banner and drawer, set up in the
|
|
29
|
+
* Osano dashboard, and Blume runs the analytics once Osano reports the
|
|
30
|
+
* reader's `ANALYTICS` consent. Both IDs come from the script tag Osano
|
|
31
|
+
* gives you, and neither is secret.
|
|
32
|
+
*/
|
|
33
|
+
export const osano = (options: OsanoOptions): OsanoAdapter => ({
|
|
34
|
+
kind: "osano",
|
|
35
|
+
options,
|
|
36
|
+
requiredSecrets: [],
|
|
37
|
+
runtimeDeps: [],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Reports Osano's analytics consent to `window.blumeConsent` now (`Osano.cm`
|
|
42
|
+
* is ready as soon as its script ran) and on every Osano consent event, and
|
|
43
|
+
* reopens Osano's drawer from the Cookie settings link.
|
|
44
|
+
*/
|
|
45
|
+
export const OSANO_BRIDGE = `(()=>{const o=window.Osano?.cm;const c=window.blumeConsent;if(!o||!c){return;}const sync=()=>c.set({analytics:o.analytics===true});c.open=()=>o.showDrawer();for(const e of ["osano-cm-initialized","osano-cm-consent-saved","osano-cm-consent-changed"]){o.addEventListener(e,sync);}sync();})();`;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Osano's loader, synchronous as its install guide requires, then the
|
|
49
|
+
* bridge. The IDs are path segments, so each is encoded.
|
|
50
|
+
*/
|
|
51
|
+
export const osanoHead = (options: OsanoOptions): HeadScript[] => [
|
|
52
|
+
{
|
|
53
|
+
attributes: {
|
|
54
|
+
src: `https://cmp.osano.com/${encodeURIComponent(options.customerId)}/${encodeURIComponent(options.configId)}/osano.js`,
|
|
55
|
+
},
|
|
56
|
+
content: null,
|
|
57
|
+
},
|
|
58
|
+
{ attributes: {}, content: OSANO_BRIDGE },
|
|
59
|
+
];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { ethycaAdapterSchema } from "./ethyca.ts";
|
|
4
|
+
import { nativeAdapterSchema } from "./native.ts";
|
|
5
|
+
import { osanoAdapterSchema } from "./osano.ts";
|
|
6
|
+
|
|
7
|
+
const ADAPTER_HINT =
|
|
8
|
+
'consent takes one adapter — e.g. `consent: native()` or `consent: osano({ customerId, configId })`, imported from "blume/consent".';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The configured consent adapter, as its factory returned it. Anything that
|
|
12
|
+
* isn't one (`true`, a list, an unknown `kind`) fails with the adapter hint;
|
|
13
|
+
* an adapter's own option errors keep their messages.
|
|
14
|
+
*/
|
|
15
|
+
export const consentAdapterSchema = z.discriminatedUnion(
|
|
16
|
+
"kind",
|
|
17
|
+
[ethycaAdapterSchema, nativeAdapterSchema, osanoAdapterSchema],
|
|
18
|
+
{ error: ADAPTER_HINT }
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export type ConsentAdapter = z.output<typeof consentAdapterSchema>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* `blume.config.consent`: the adapter that asks readers before analytics
|
|
25
|
+
* runs. Unset (`null` once resolved) means no consent layer, and analytics
|
|
26
|
+
* runs as it loads.
|
|
27
|
+
*/
|
|
28
|
+
export const consentConfigSchema = consentAdapterSchema
|
|
29
|
+
.optional()
|
|
30
|
+
.transform((adapter) => adapter ?? null);
|
package/src/core/builtin-tags.ts
CHANGED
|
@@ -31,7 +31,11 @@ export const BUILTIN_MDX_TAGS = new Set<string>([
|
|
|
31
31
|
"Math",
|
|
32
32
|
"Operation",
|
|
33
33
|
"Panel",
|
|
34
|
+
"ParamField",
|
|
34
35
|
"Prompt",
|
|
36
|
+
"RequestExample",
|
|
37
|
+
"ResponseExample",
|
|
38
|
+
"ResponseField",
|
|
35
39
|
"Step",
|
|
36
40
|
"Steps",
|
|
37
41
|
"Tab",
|
|
@@ -40,6 +44,7 @@ export const BUILTIN_MDX_TAGS = new Set<string>([
|
|
|
40
44
|
"Tooltip",
|
|
41
45
|
"Tree",
|
|
42
46
|
"TypeTable",
|
|
47
|
+
"View",
|
|
43
48
|
"Visibility",
|
|
44
49
|
"YouTube",
|
|
45
50
|
]);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UIStrings } from "./i18n-ui.ts";
|
|
2
|
+
import { resolveLocalizable } from "./localizable.ts";
|
|
3
|
+
import type { LocalizableLabel, ResolvedConfig } from "./schema.ts";
|
|
2
4
|
import { sourcesOfKind } from "./sources/collection.ts";
|
|
3
5
|
import type { PageRecord } from "./types.ts";
|
|
4
6
|
|
|
@@ -22,3 +24,31 @@ export const hasChangelogIndex = (
|
|
|
22
24
|
page.contentType === "changelog" &&
|
|
23
25
|
!(page.meta.draft || page.meta.sidebar.hidden)
|
|
24
26
|
) || sourcesOfKind(config, "github-releases").length > 0;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A locale's UI strings with the index's title and description taken from
|
|
30
|
+
* the `changelog` config where it sets them (a string, or a per-locale map
|
|
31
|
+
* resolved like a header label), so every surface that reads the
|
|
32
|
+
* `changelog` strings (the page, its OG card, its Markdown mirror) agrees.
|
|
33
|
+
*/
|
|
34
|
+
export const withChangelogIndexText = (
|
|
35
|
+
config: ResolvedConfig,
|
|
36
|
+
ui: UIStrings,
|
|
37
|
+
locale?: string
|
|
38
|
+
): UIStrings => {
|
|
39
|
+
const text = (label: LocalizableLabel | undefined, fallback: string) =>
|
|
40
|
+
label === undefined
|
|
41
|
+
? fallback
|
|
42
|
+
: resolveLocalizable(label, locale, config.i18n?.defaultLocale);
|
|
43
|
+
return {
|
|
44
|
+
...ui,
|
|
45
|
+
changelog: {
|
|
46
|
+
...ui.changelog,
|
|
47
|
+
description: text(
|
|
48
|
+
config.changelog?.description,
|
|
49
|
+
ui.changelog.description
|
|
50
|
+
),
|
|
51
|
+
title: text(config.changelog?.title, ui.changelog.title),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** The slice of Astro's `APIContext` a server route reads the reader from. */
|
|
2
|
+
export interface ClientContext {
|
|
3
|
+
/** The reader's address; Astro's getter throws where the host can't tell. */
|
|
4
|
+
readonly clientAddress?: string;
|
|
5
|
+
readonly request: Request;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The reader's IP address as the host reports it (Astro resolves the
|
|
10
|
+
* platform's trusted header, or the socket on a Node server), or `undefined`
|
|
11
|
+
* where the host can't tell.
|
|
12
|
+
*/
|
|
13
|
+
export const clientAddressOf = (context: ClientContext): string | undefined => {
|
|
14
|
+
try {
|
|
15
|
+
return context.clientAddress || undefined;
|
|
16
|
+
} catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { relative } from "pathe";
|
|
2
|
+
|
|
1
3
|
import { BUILTIN_MDX_TAGS } from "./builtin-tags.ts";
|
|
2
4
|
import type { Diagnostic, PageRecord } from "./types.ts";
|
|
3
5
|
|
|
@@ -42,3 +44,54 @@ export const validateUsedComponents = (
|
|
|
42
44
|
}
|
|
43
45
|
return diagnostics;
|
|
44
46
|
};
|
|
47
|
+
|
|
48
|
+
/** What example discovery found: where it looked, and each example's key. */
|
|
49
|
+
export interface ExampleKeys {
|
|
50
|
+
/** Absolute directory the examples were discovered under. */
|
|
51
|
+
dir: string;
|
|
52
|
+
examples: readonly { path: string }[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Warn about each `<Component path>` in an `.mdx` page that names no
|
|
57
|
+
* discovered example. The page still renders, with a "No example found" box
|
|
58
|
+
* where the preview should be, so without this a typo or a moved example
|
|
59
|
+
* ships silently. Reported at the `path` value, in the partial that holds it
|
|
60
|
+
* when an `<include>` brought it in; a file shared by several locales is
|
|
61
|
+
* reported once. `extraTags` are the project's own components (islands +
|
|
62
|
+
* overrides), as for {@link validateUsedComponents}: one named `Component`
|
|
63
|
+
* replaces the built-in and resolves `path` its own way, so none is checked.
|
|
64
|
+
*/
|
|
65
|
+
export const missingExampleDiagnostics = (
|
|
66
|
+
pages: readonly PageRecord[],
|
|
67
|
+
discovery: ExampleKeys,
|
|
68
|
+
root: string,
|
|
69
|
+
extraTags: ReadonlySet<string>
|
|
70
|
+
): Diagnostic[] => {
|
|
71
|
+
if (extraTags.has("Component")) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const known = new Set(discovery.examples.map((example) => example.path));
|
|
75
|
+
const dir = relative(root, discovery.dir) || ".";
|
|
76
|
+
const diagnostics: Diagnostic[] = [];
|
|
77
|
+
const seen = new Set<string>();
|
|
78
|
+
for (const page of pages) {
|
|
79
|
+
for (const use of page.examplesUsed ?? []) {
|
|
80
|
+
const file = use.file ?? page.sourcePath ?? page.id;
|
|
81
|
+
const key = `${file}:${use.line}:${use.column}`;
|
|
82
|
+
if (!(known.has(use.path) || seen.has(key))) {
|
|
83
|
+
seen.add(key);
|
|
84
|
+
diagnostics.push({
|
|
85
|
+
code: "BLUME_EXAMPLE_NOT_FOUND",
|
|
86
|
+
column: use.column,
|
|
87
|
+
file,
|
|
88
|
+
line: use.line,
|
|
89
|
+
message: `<Component path="${use.path}"> in ${page.route} names no example, so the page shows "No example found" in its place.`,
|
|
90
|
+
severity: "warning",
|
|
91
|
+
suggestion: `Fix the path, or add the example under ${dir}/: \`path\` is its location there, without the extension.`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return diagnostics;
|
|
97
|
+
};
|
|
@@ -69,6 +69,29 @@ type Group = (typeof GROUPS)[number];
|
|
|
69
69
|
|
|
70
70
|
const isGroup = (name: string): name is Group => GROUP_SET.has(name);
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* The `layout` keys the built-in chrome reads (`RootLayout.astro` and
|
|
74
|
+
* `Header.astro`). Any other key is never rendered, so it's warned about
|
|
75
|
+
* rather than silently dropped; a typo or wrong case would otherwise leave
|
|
76
|
+
* the built-in in place with no sign why.
|
|
77
|
+
*/
|
|
78
|
+
const LAYOUT_SLOTS = [
|
|
79
|
+
"Layout",
|
|
80
|
+
"Header",
|
|
81
|
+
"Logo",
|
|
82
|
+
"Search",
|
|
83
|
+
"Sidebar",
|
|
84
|
+
"MobileNav",
|
|
85
|
+
"Breadcrumbs",
|
|
86
|
+
"TableOfContents",
|
|
87
|
+
"Pagination",
|
|
88
|
+
"Feedback",
|
|
89
|
+
"PageHeader",
|
|
90
|
+
"PageFooter",
|
|
91
|
+
"Footer",
|
|
92
|
+
];
|
|
93
|
+
const LAYOUT_SLOT_SET: ReadonlySet<string> = new Set(LAYOUT_SLOTS);
|
|
94
|
+
|
|
72
95
|
/** The authoring forms an override accepts; the fix every rejection points at. */
|
|
73
96
|
export const ACCEPTED_OVERRIDE_FORMS =
|
|
74
97
|
"Each override must be an imported identifier, a path string, or a `{ component, client, media }` object literal whose `component` is an imported identifier or a path string.";
|
|
@@ -628,6 +651,15 @@ const collectGroupOverrides = (
|
|
|
628
651
|
if (normalized) {
|
|
629
652
|
result[name].push(normalized);
|
|
630
653
|
}
|
|
654
|
+
if (
|
|
655
|
+
name === "layout" &&
|
|
656
|
+
normalized &&
|
|
657
|
+
!LAYOUT_SLOT_SET.has(normalized.key)
|
|
658
|
+
) {
|
|
659
|
+
context.warnings.push(
|
|
660
|
+
`Layout override "${normalized.key}" isn't a layout slot, so nothing renders it. Use one of: ${LAYOUT_SLOTS.join(", ")}.`
|
|
661
|
+
);
|
|
662
|
+
}
|
|
631
663
|
}
|
|
632
664
|
};
|
|
633
665
|
|