blume 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +48 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-1d7ve1dm.js → chunk-0gz36akr.js} +18 -2
- package/dist/cli/{chunk-1d7ve1dm.js.map → chunk-0gz36akr.js.map} +3 -3
- package/dist/cli/{chunk-2eytanqx.js → chunk-1n228xqb.js} +2 -2
- package/dist/cli/{chunk-yfyb25rh.js → chunk-2f3ndkpw.js} +24 -8
- package/dist/cli/chunk-2f3ndkpw.js.map +14 -0
- package/dist/cli/{chunk-r20tn01b.js → chunk-2f7n4qzt.js} +8 -2
- package/dist/cli/{chunk-r20tn01b.js.map → chunk-2f7n4qzt.js.map} +3 -3
- package/dist/cli/{chunk-35d4wj9f.js → chunk-2n4ps1b3.js} +7 -7
- package/dist/cli/{chunk-j85vccga.js → chunk-43zcf4gz.js} +97 -57
- package/dist/cli/{chunk-j85vccga.js.map → chunk-43zcf4gz.js.map} +6 -6
- package/dist/cli/{chunk-e04dxsz1.js → chunk-4ejxbzee.js} +1 -1
- package/dist/cli/{chunk-5m5nmvyq.js → chunk-4h8z9vv5.js} +233 -39
- package/dist/cli/chunk-4h8z9vv5.js.map +16 -0
- package/dist/cli/{chunk-5f86nr5m.js → chunk-5cg2rzgf.js} +18 -16
- package/dist/cli/{chunk-5f86nr5m.js.map → chunk-5cg2rzgf.js.map} +2 -2
- package/dist/cli/{chunk-tzmab476.js → chunk-5ffywsmb.js} +4 -4
- package/dist/cli/{chunk-2z928egk.js → chunk-5wj2qwn2.js} +5 -5
- package/dist/cli/chunk-6bm0xpgd.js +18 -0
- package/dist/cli/chunk-6bm0xpgd.js.map +10 -0
- package/dist/cli/{chunk-vg9r4eb9.js → chunk-713mngdq.js} +12 -5
- package/dist/cli/{chunk-vg9r4eb9.js.map → chunk-713mngdq.js.map} +3 -3
- package/dist/cli/{chunk-5xvm6tfj.js → chunk-9geymqns.js} +17 -15
- package/dist/cli/{chunk-5xvm6tfj.js.map → chunk-9geymqns.js.map} +2 -2
- package/dist/cli/{chunk-q58y5e6a.js → chunk-9xr4dgee.js} +26 -17
- package/dist/cli/chunk-9xr4dgee.js.map +10 -0
- package/dist/cli/{chunk-b07cmahc.js → chunk-amrb6hgh.js} +2 -2
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-akbpwfxc.js → chunk-cmtcnh9f.js} +2 -2
- package/dist/cli/chunk-cy5bm0j0.js +104 -0
- package/dist/cli/chunk-cy5bm0j0.js.map +11 -0
- package/dist/cli/{chunk-crgn1q09.js → chunk-e7vvk5ya.js} +4 -4
- package/dist/cli/{chunk-pehfxfta.js → chunk-g2z9x01v.js} +6 -98
- package/dist/cli/chunk-g2z9x01v.js.map +10 -0
- package/dist/cli/{chunk-tkacnehg.js → chunk-gp84za0h.js} +2 -2
- package/dist/cli/{chunk-wrr3j9w9.js → chunk-h2a48yhd.js} +186 -63
- package/dist/cli/chunk-h2a48yhd.js.map +36 -0
- package/dist/cli/{chunk-hm3vjy5s.js → chunk-jnwj5kjj.js} +14 -9
- package/dist/cli/{chunk-hm3vjy5s.js.map → chunk-jnwj5kjj.js.map} +4 -4
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-2hsdwb9n.js → chunk-nd1821sk.js} +18 -16
- package/dist/cli/{chunk-2hsdwb9n.js.map → chunk-nd1821sk.js.map} +2 -2
- package/dist/cli/{chunk-6dsbexzp.js → chunk-ntv4qrt7.js} +17 -15
- package/dist/cli/{chunk-6dsbexzp.js.map → chunk-ntv4qrt7.js.map} +2 -2
- package/dist/cli/{chunk-r9rcc4w7.js → chunk-p804f3pe.js} +7 -7
- package/dist/cli/{chunk-ey84smr6.js → chunk-py62fewh.js} +6 -6
- package/dist/cli/{chunk-ey84smr6.js.map → chunk-py62fewh.js.map} +1 -1
- package/dist/cli/chunk-q3wxxq39.js +126 -0
- package/dist/cli/chunk-q3wxxq39.js.map +11 -0
- package/dist/cli/{chunk-9t7a85s3.js → chunk-rekqz4qg.js} +23 -13
- package/dist/cli/chunk-rekqz4qg.js.map +10 -0
- package/dist/cli/{chunk-8ktnccpt.js → chunk-ta27feev.js} +1 -1
- package/dist/cli/{chunk-pv29h0wf.js → chunk-xkz5xbtv.js} +3476 -822
- package/dist/cli/chunk-xkz5xbtv.js.map +213 -0
- package/dist/cli/{chunk-a58773jm.js → chunk-y4ykbark.js} +2 -2
- package/dist/cli/{chunk-p3v96n38.js → chunk-y5h4r2y0.js} +4 -4
- package/dist/cli/{chunk-acanzt5p.js → chunk-yj17vs39.js} +6 -6
- package/dist/cli/{chunk-p73c0m7w.js → chunk-yxmk4pec.js} +16 -14
- package/dist/cli/{chunk-p73c0m7w.js.map → chunk-yxmk4pec.js.map} +2 -2
- package/dist/cli/{chunk-3em5wd2y.js → chunk-zccbjcj0.js} +4 -3
- package/dist/cli/{chunk-3em5wd2y.js.map → chunk-zccbjcj0.js.map} +2 -2
- package/dist/cli/{chunk-c8chx29p.js → chunk-zf748avv.js} +384 -207
- package/dist/cli/chunk-zf748avv.js.map +37 -0
- package/dist/cli/{chunk-g4hq16wv.js → chunk-zhvd6adm.js} +16 -14
- package/dist/cli/{chunk-g4hq16wv.js.map → chunk-zhvd6adm.js.map} +2 -2
- package/dist/cli/index.js +26 -20
- package/dist/cli/index.js.map +5 -5
- package/dist/types/ai/agent-surface.d.ts +8 -7
- package/dist/types/ai/ai-catalog.d.ts +7 -0
- package/dist/types/ai/ask-context.d.ts +22 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +16 -0
- package/dist/types/astro/integration.d.ts +8 -0
- package/dist/types/captcha/hcaptcha.d.ts +27 -0
- package/dist/types/captcha/index.d.ts +28 -0
- package/dist/types/captcha/schema.d.ts +29 -0
- package/dist/types/captcha/turnstile.d.ts +28 -0
- package/dist/types/components/content/api-field.d.ts +59 -0
- package/dist/types/components/content/api-page.d.ts +95 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/helpers.d.ts +137 -0
- package/dist/types/components/openapi/security.d.ts +85 -0
- package/dist/types/consent/ethyca.d.ts +48 -0
- package/dist/types/consent/index.d.ts +37 -0
- package/dist/types/consent/native.d.ts +28 -0
- package/dist/types/consent/osano.d.ts +42 -0
- package/dist/types/consent/schema.d.ts +110 -0
- package/dist/types/core/config-input.d.ts +187 -20
- package/dist/types/core/data.d.ts +49 -4
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/i18n-ui.d.ts +86 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/redirect-patterns.d.ts +144 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +551 -56
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/types.d.ts +1 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +5 -0
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/vercel.d.ts +6 -0
- package/dist/types/deploy/redirects.d.ts +39 -11
- package/dist/types/deploy/vercel-negotiation.d.ts +9 -0
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/features.d.ts +3 -2
- package/dist/types/narration/build.d.ts +70 -0
- package/dist/types/narration/provider.d.ts +26 -0
- package/dist/types/narration/script.d.ts +154 -0
- package/dist/types/openapi/model.d.ts +12 -6
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +13 -0
- package/dist/types/openapi/references.d.ts +14 -4
- package/dist/types/ratelimit/cloudflare.d.ts +39 -0
- package/dist/types/ratelimit/index.d.ts +27 -0
- package/dist/types/ratelimit/memory.d.ts +36 -0
- package/dist/types/ratelimit/schema.d.ts +111 -0
- package/dist/types/ratelimit/upstash.d.ts +21 -0
- package/dist/types/ratelimit/wrangler.d.ts +23 -0
- package/dist/types/reference/asyncapi.d.ts +10 -10
- package/dist/types/reference/graphql.d.ts +13 -10
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +45 -5
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +60 -36
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +4 -0
- package/dist/types/seo/metatags.d.ts +20 -0
- package/docs/02-deployment.mdx +41 -5
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/advanced/changelog.mdx +2 -2
- package/docs/advanced/skills.mdx +14 -0
- package/docs/cli/audit.mdx +21 -1
- package/docs/cli/index.mdx +1 -0
- package/docs/configuration/analytics.mdx +3 -1
- package/docs/configuration/assistant.mdx +188 -36
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +4 -4
- package/docs/configuration/index.mdx +63 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +69 -0
- package/docs/configuration/search.mdx +29 -1
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +106 -0
- package/docs/content/frontmatter.mdx +76 -0
- package/docs/content/i18n.mdx +38 -3
- package/docs/content/includes.mdx +16 -0
- package/docs/content/meta.mdx +1 -0
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +28 -6
- package/docs/content/sources/contentful.mdx +32 -0
- package/docs/content/sources/custom.mdx +39 -0
- package/docs/content/sources/github-releases.mdx +31 -0
- package/docs/content/sources/index.mdx +91 -0
- package/docs/content/sources/meta.ts +16 -0
- package/docs/content/sources/notion.mdx +32 -0
- package/docs/content/sources/obsidian.mdx +37 -0
- package/docs/content/sources/payload.mdx +30 -0
- package/docs/content/sources/remote-mdx.mdx +40 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +31 -0
- package/docs/content/syntax.mdx +67 -2
- package/docs/content/variables.mdx +41 -0
- package/docs/discoverability/agent-discovery.mdx +29 -2
- package/docs/discoverability/index.mdx +1 -1
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +1 -1
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +102 -3
- package/docs/references/scalar.mdx +3 -1
- package/package.json +36 -1
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +5 -5
- package/skills/blume-migrate/references/docusaurus.md +3 -3
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +2 -2
- package/skills/blume-migrate/references/starlight.md +2 -1
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +60 -14
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +2 -1
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +6 -3
- package/src/ai/ask-context.ts +73 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/component-markdown.ts +75 -0
- package/src/ai/cors.ts +2 -0
- package/src/ai/index.ts +12 -0
- package/src/ai/llms.ts +6 -2
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/openapi-components.ts +9 -3
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +35 -2
- package/src/ai/write-skill.ts +97 -0
- package/src/astro/generate.ts +132 -18
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +35 -0
- package/src/astro/module-types.ts +6 -0
- package/src/astro/templates.ts +283 -30
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +19 -0
- package/src/audit/checks/contrast.ts +183 -0
- package/src/audit/checks/i18n.ts +2 -3
- package/src/audit/checks/indexability.ts +2 -3
- package/src/audit/checks/links.ts +5 -12
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +2 -0
- package/src/audit/types.ts +2 -1
- package/src/blume-modules.d.ts +7 -0
- package/src/captcha/client.ts +152 -0
- package/src/captcha/hcaptcha.ts +36 -0
- package/src/captcha/index.ts +28 -0
- package/src/captcha/schema.ts +32 -0
- package/src/captcha/turnstile.ts +38 -0
- package/src/captcha/verify.ts +71 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/doctor.ts +22 -16
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/index.ts +5 -0
- package/src/cli/required-secrets.ts +71 -29
- package/src/components/BlumePage.astro +2 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +62 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Color.astro +1 -0
- package/src/components/content/FileTree.astro +1 -0
- package/src/components/content/GithubInfo.astro +1 -0
- package/src/components/content/Panel.astro +1 -0
- package/src/components/content/ParamField.astro +25 -0
- package/src/components/content/RequestExample.astro +17 -0
- package/src/components/content/ResponseExample.astro +17 -0
- package/src/components/content/ResponseField.astro +32 -0
- package/src/components/content/Step.astro +1 -0
- package/src/components/content/Tile.astro +1 -0
- package/src/components/content/Tooltip.astro +1 -0
- package/src/components/content/Tree.astro +1 -0
- package/src/components/content/TypeTable.astro +4 -1
- package/src/components/content/View.astro +21 -0
- package/src/components/content/ViewSwitcher.astro +168 -0
- package/src/components/content/api-field.ts +100 -0
- package/src/components/content/api-page.ts +224 -0
- package/src/components/content/view-switcher.ts +71 -0
- package/src/components/index.ts +2 -0
- package/src/components/islands/Assistant.astro +10 -1
- package/src/components/islands/assistant.tsx +104 -14
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +110 -21
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +6 -2
- package/src/components/layout/ConsentBanner.astro +62 -0
- package/src/components/layout/ConsentHead.astro +38 -0
- package/src/components/layout/Directory.astro +94 -0
- package/src/components/layout/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +122 -80
- package/src/components/layout/LanguageSwitcher.astro +48 -15
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +33 -7
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +71 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +308 -45
- package/src/components/layout/Search.astro +31 -17
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/consent/native.ts +79 -0
- package/src/components/layout/consent/types.ts +37 -0
- package/src/components/layout/footer-links.ts +53 -0
- package/src/components/layout/footer-socials.ts +87 -0
- package/src/components/layout/locale-redirect.ts +107 -0
- package/src/components/layout/nav-utils.ts +83 -0
- package/src/components/layout/page-feedback.ts +96 -0
- package/src/components/layout/search/analytics.ts +98 -0
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/types.ts +20 -0
- package/src/components/layout/search/typesense.ts +5 -1
- package/src/components/openapi/Operation.astro +161 -13
- package/src/components/openapi/RequestBody.astro +6 -4
- package/src/components/openapi/RequestPanel.astro +59 -7
- package/src/components/openapi/Responses.astro +6 -4
- package/src/components/openapi/async-snippets.ts +4 -4
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/security.ts +6 -3
- package/src/components/openapi/snippets.ts +869 -8
- package/src/components/props.ts +6 -0
- package/src/consent/client.ts +95 -0
- package/src/consent/clients.ts +19 -0
- package/src/consent/ethyca.ts +71 -0
- package/src/consent/head.ts +24 -0
- package/src/consent/index.ts +37 -0
- package/src/consent/init.ts +29 -0
- package/src/consent/native.ts +36 -0
- package/src/consent/osano.ts +59 -0
- package/src/consent/schema.ts +30 -0
- package/src/core/builtin-tags.ts +5 -0
- package/src/core/client-address.ts +19 -0
- package/src/core/config-input.ts +194 -20
- package/src/core/data.ts +44 -4
- package/src/core/diagnostics.ts +3 -2
- package/src/core/footer.ts +26 -0
- package/src/core/graph.ts +39 -36
- package/src/core/i18n-ui.ts +82 -2
- package/src/core/includes.ts +20 -3
- package/src/core/links.ts +16 -2
- package/src/core/localizable.ts +26 -0
- package/src/core/navigation.ts +43 -12
- package/src/core/page-modes.ts +56 -0
- package/src/core/project-graph.ts +111 -5
- package/src/core/redirect-patterns.ts +491 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +318 -64
- package/src/core/sources/normalize.ts +2 -1
- package/src/core/sources/read.ts +8 -3
- package/src/core/types.ts +1 -1
- package/src/core/ui-packs/ar.ts +43 -0
- package/src/core/ui-packs/bg.ts +45 -0
- package/src/core/ui-packs/bn.ts +43 -0
- package/src/core/ui-packs/ca.ts +46 -0
- package/src/core/ui-packs/cs.ts +44 -0
- package/src/core/ui-packs/da.ts +45 -0
- package/src/core/ui-packs/de.ts +46 -0
- package/src/core/ui-packs/el.ts +45 -0
- package/src/core/ui-packs/es.ts +46 -0
- package/src/core/ui-packs/fa.ts +45 -0
- package/src/core/ui-packs/fi.ts +45 -0
- package/src/core/ui-packs/fr.ts +46 -0
- package/src/core/ui-packs/he.ts +43 -0
- package/src/core/ui-packs/hi.ts +44 -0
- package/src/core/ui-packs/hr.ts +45 -0
- package/src/core/ui-packs/hu.ts +44 -0
- package/src/core/ui-packs/id.ts +45 -0
- package/src/core/ui-packs/it.ts +45 -0
- package/src/core/ui-packs/ja.ts +45 -0
- package/src/core/ui-packs/ko.ts +44 -0
- package/src/core/ui-packs/nl.ts +46 -0
- package/src/core/ui-packs/no.ts +44 -0
- package/src/core/ui-packs/pl.ts +45 -0
- package/src/core/ui-packs/pt-br.ts +46 -0
- package/src/core/ui-packs/pt.ts +45 -0
- package/src/core/ui-packs/ro.ts +45 -0
- package/src/core/ui-packs/ru.ts +45 -0
- package/src/core/ui-packs/sk.ts +44 -0
- package/src/core/ui-packs/sr.ts +45 -0
- package/src/core/ui-packs/sv.ts +44 -0
- package/src/core/ui-packs/th.ts +43 -0
- package/src/core/ui-packs/tr.ts +45 -0
- package/src/core/ui-packs/uk.ts +45 -0
- package/src/core/ui-packs/vi.ts +45 -0
- package/src/core/ui-packs/zh-tw.ts +43 -0
- package/src/core/ui-packs/zh.ts +43 -0
- package/src/core/variables.ts +103 -0
- package/src/deploy/artifacts.ts +77 -8
- package/src/deploy/cloudflare-negotiation.ts +35 -5
- package/src/deploy/headers.ts +2 -1
- package/src/deploy/node-headers.ts +63 -9
- package/src/deploy/platforms/cloudflare.ts +32 -0
- package/src/deploy/platforms/netlify.ts +33 -1
- package/src/deploy/platforms/vercel.ts +37 -2
- package/src/deploy/redirects.ts +91 -24
- package/src/deploy/vercel-negotiation.ts +36 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/features.ts +3 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +28 -5
- package/src/markdown/math.ts +4 -4
- package/src/markdown/variables.ts +56 -0
- package/src/markdown/views.ts +82 -0
- package/src/narration/build.ts +412 -0
- package/src/narration/player.ts +249 -0
- package/src/narration/provider.ts +29 -0
- package/src/narration/script.ts +592 -0
- package/src/og/card.ts +7 -6
- package/src/openapi/model.ts +57 -24
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +55 -2
- package/src/openapi/references.ts +21 -5
- package/src/openapi/render-mdx.ts +5 -1
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +1 -1
- package/src/ratelimit/cloudflare.ts +54 -0
- package/src/ratelimit/index.ts +30 -0
- package/src/ratelimit/memory.ts +45 -0
- package/src/ratelimit/runtime.ts +229 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +30 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +5 -2
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +51 -7
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +20 -4
- package/src/registry/registry.ts +7 -0
- package/src/search/documents.ts +26 -2
- package/src/search/orama-index.ts +28 -3
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/sync/algolia.ts +15 -4
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +5 -0
- package/src/seo/metatags.ts +67 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +56 -3
- package/src/theme/palette.ts +121 -45
- package/src/translate/prompts.ts +1 -0
- package/src/translate/validate.ts +8 -2
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-364znk6q.js +0 -75
- package/dist/cli/chunk-364znk6q.js.map +0 -11
- package/dist/cli/chunk-5m5nmvyq.js.map +0 -13
- package/dist/cli/chunk-9t7a85s3.js.map +0 -10
- package/dist/cli/chunk-c8chx29p.js.map +0 -36
- package/dist/cli/chunk-pehfxfta.js.map +0 -10
- package/dist/cli/chunk-pv29h0wf.js.map +0 -190
- package/dist/cli/chunk-q58y5e6a.js.map +0 -10
- package/dist/cli/chunk-wrr3j9w9.js.map +0 -35
- package/dist/cli/chunk-yfyb25rh.js.map +0 -14
- package/docs/content/sources.mdx +0 -334
- /package/dist/cli/{chunk-2eytanqx.js.map → chunk-1n228xqb.js.map} +0 -0
- /package/dist/cli/{chunk-35d4wj9f.js.map → chunk-2n4ps1b3.js.map} +0 -0
- /package/dist/cli/{chunk-e04dxsz1.js.map → chunk-4ejxbzee.js.map} +0 -0
- /package/dist/cli/{chunk-tzmab476.js.map → chunk-5ffywsmb.js.map} +0 -0
- /package/dist/cli/{chunk-2z928egk.js.map → chunk-5wj2qwn2.js.map} +0 -0
- /package/dist/cli/{chunk-b07cmahc.js.map → chunk-amrb6hgh.js.map} +0 -0
- /package/dist/cli/{chunk-akbpwfxc.js.map → chunk-cmtcnh9f.js.map} +0 -0
- /package/dist/cli/{chunk-crgn1q09.js.map → chunk-e7vvk5ya.js.map} +0 -0
- /package/dist/cli/{chunk-tkacnehg.js.map → chunk-gp84za0h.js.map} +0 -0
- /package/dist/cli/{chunk-r9rcc4w7.js.map → chunk-p804f3pe.js.map} +0 -0
- /package/dist/cli/{chunk-8ktnccpt.js.map → chunk-ta27feev.js.map} +0 -0
- /package/dist/cli/{chunk-a58773jm.js.map → chunk-y4ykbark.js.map} +0 -0
- /package/dist/cli/{chunk-p3v96n38.js.map → chunk-y5h4r2y0.js.map} +0 -0
- /package/dist/cli/{chunk-acanzt5p.js.map → chunk-yj17vs39.js.map} +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
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 turnstile}. */
|
|
7
|
+
export interface TurnstileOptions {
|
|
8
|
+
/** The widget's site key, from the Cloudflare dashboard. */
|
|
9
|
+
siteKey: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const turnstileOptionsSchema = z.strictObject({
|
|
13
|
+
siteKey: z.string().min(1),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export type TurnstileAdapter = AdapterDescriptor<"turnstile", TurnstileOptions>;
|
|
17
|
+
|
|
18
|
+
export const turnstileAdapterSchema = adapterDescriptorSchema(
|
|
19
|
+
"turnstile",
|
|
20
|
+
turnstileOptionsSchema
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
/** Where the assistant's route checks a Turnstile token. */
|
|
24
|
+
export const TURNSTILE_VERIFY_URL =
|
|
25
|
+
"https://challenges.cloudflare.com/turnstile/v0/siteverify";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Cloudflare Turnstile. The site key is public and goes to the browser; the
|
|
29
|
+
* secret key the route checks tokens with comes from `TURNSTILE_SECRET_KEY`.
|
|
30
|
+
* Set the widget to Invisible or Managed in the Cloudflare dashboard: most
|
|
31
|
+
* readers never see a challenge.
|
|
32
|
+
*/
|
|
33
|
+
export const turnstile = (options: TurnstileOptions): TurnstileAdapter => ({
|
|
34
|
+
kind: "turnstile",
|
|
35
|
+
options,
|
|
36
|
+
requiredSecrets: ["TURNSTILE_SECRET_KEY"],
|
|
37
|
+
runtimeDeps: [],
|
|
38
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server half of the bot check: the generated assistant route verifies
|
|
3
|
+
* the token the browser sent with the question against the provider before
|
|
4
|
+
* it calls the model. A failed or unreachable check refuses the question
|
|
5
|
+
* (and logs why), so a server that can't reach the provider shows up as a
|
|
6
|
+
* refused question rather than a silently unprotected route.
|
|
7
|
+
*/
|
|
8
|
+
import { clientAddressOf } from "../core/client-address.ts";
|
|
9
|
+
import type { ClientContext } from "../core/client-address.ts";
|
|
10
|
+
import { HCAPTCHA_VERIFY_URL } from "./hcaptcha.ts";
|
|
11
|
+
import type { CaptchaAdapter } from "./schema.ts";
|
|
12
|
+
import { TURNSTILE_VERIFY_URL } from "./turnstile.ts";
|
|
13
|
+
|
|
14
|
+
/** The longest token either provider issues, with room to spare. */
|
|
15
|
+
const MAX_TOKEN_LENGTH = 4096;
|
|
16
|
+
|
|
17
|
+
/** What the provider answers about a token. */
|
|
18
|
+
interface VerifyReply {
|
|
19
|
+
"error-codes"?: string[];
|
|
20
|
+
success?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** What the route hands the check from its runtime. */
|
|
24
|
+
export interface VerifyOptions {
|
|
25
|
+
/** For tests; defaults to the global `fetch`. */
|
|
26
|
+
fetch?: typeof fetch;
|
|
27
|
+
/** The provider's secret key. */
|
|
28
|
+
secret: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether the provider confirms `token` came from a person on this site. The
|
|
33
|
+
* route passes the request body's `captcha` when it's a string.
|
|
34
|
+
*/
|
|
35
|
+
export const verifyCaptcha = async (
|
|
36
|
+
adapter: CaptchaAdapter,
|
|
37
|
+
token: string | undefined,
|
|
38
|
+
context: ClientContext,
|
|
39
|
+
options: VerifyOptions
|
|
40
|
+
): Promise<boolean> => {
|
|
41
|
+
if (!token || token.length > MAX_TOKEN_LENGTH) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const form = new URLSearchParams({ response: token, secret: options.secret });
|
|
45
|
+
const address = clientAddressOf(context);
|
|
46
|
+
if (address) {
|
|
47
|
+
form.set("remoteip", address);
|
|
48
|
+
}
|
|
49
|
+
if (adapter.kind === "hcaptcha") {
|
|
50
|
+
form.set("sitekey", adapter.options.siteKey);
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const response = await (options.fetch ?? fetch)(
|
|
54
|
+
adapter.kind === "hcaptcha" ? HCAPTCHA_VERIFY_URL : TURNSTILE_VERIFY_URL,
|
|
55
|
+
{ body: form, method: "POST" }
|
|
56
|
+
);
|
|
57
|
+
// SAFETY: both providers answer JSON with a `success` flag; anything
|
|
58
|
+
// else reads as a failure below.
|
|
59
|
+
const reply = (await response.json()) as VerifyReply;
|
|
60
|
+
if (reply.success === true) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
console.warn(
|
|
64
|
+
`The ${adapter.kind} check refused a question:`,
|
|
65
|
+
reply["error-codes"] ?? response.status
|
|
66
|
+
);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error(`The ${adapter.kind} check could not be reached:`, error);
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
};
|
package/src/cli/command-meta.ts
CHANGED
|
@@ -62,6 +62,11 @@ export const commandMeta = {
|
|
|
62
62
|
description: "Preview the last production build.",
|
|
63
63
|
name: "preview",
|
|
64
64
|
},
|
|
65
|
+
skill: {
|
|
66
|
+
description:
|
|
67
|
+
"Write the docs site's agent skill with a coding agent, in place of the generated one.",
|
|
68
|
+
name: "skill",
|
|
69
|
+
},
|
|
65
70
|
sync: {
|
|
66
71
|
description: "Re-fetch remote content sources and regenerate the runtime.",
|
|
67
72
|
name: "sync",
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
import { BlumeError } from "../../core/diagnostics.ts";
|
|
15
15
|
import { packageRoot } from "../../core/package-root.ts";
|
|
16
16
|
import { scanProject } from "../../core/project-graph.ts";
|
|
17
|
+
import type { ResolvedConfig } from "../../core/schema.ts";
|
|
17
18
|
import { serverFeatures } from "../../core/server-features.ts";
|
|
18
19
|
import type { Diagnostic } from "../../core/types.ts";
|
|
19
20
|
import { unregisteredSnapshotDiagnostics } from "../../core/version-cut.ts";
|
|
@@ -71,6 +72,25 @@ const supportedNodeRange = (): string => {
|
|
|
71
72
|
}
|
|
72
73
|
};
|
|
73
74
|
|
|
75
|
+
/** The adapters a project runs, one line per kind, for the doctor summary. */
|
|
76
|
+
const integrationSummary = (config: ResolvedConfig): string[] => {
|
|
77
|
+
const { assistant } = config.ai;
|
|
78
|
+
let assistantSummary = "off";
|
|
79
|
+
if (assistant?.enabled) {
|
|
80
|
+
assistantSummary = assistant.endpoint
|
|
81
|
+
? "external endpoint"
|
|
82
|
+
: assistant.provider.kind;
|
|
83
|
+
}
|
|
84
|
+
return [
|
|
85
|
+
`References: ${config.reference.map((adapter) => adapter.kind).join(", ") || "none"}`,
|
|
86
|
+
`Analytics: ${config.analytics.map((adapter) => adapter.kind).join(", ") || "none"}`,
|
|
87
|
+
`Consent: ${config.consent?.kind ?? "none"}`,
|
|
88
|
+
`Rate limiting: ${config.rateLimit?.kind ?? "off"}`,
|
|
89
|
+
`Sources: ${config.content.sources.map((source) => source.kind).join(", ")}`,
|
|
90
|
+
`Assistant: ${assistantSummary}`,
|
|
91
|
+
];
|
|
92
|
+
};
|
|
93
|
+
|
|
74
94
|
export const doctorCommand = defineCommand({
|
|
75
95
|
args: {
|
|
76
96
|
json: {
|
|
@@ -144,23 +164,9 @@ export const doctorCommand = defineCommand({
|
|
|
144
164
|
logger.info(`Output: ${config.deployment.options.output}`);
|
|
145
165
|
logger.info(`Adapter: ${config.deployment.kind}`);
|
|
146
166
|
logger.info(`Search: ${config.search.provider.kind}`);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
);
|
|
150
|
-
logger.info(
|
|
151
|
-
`Analytics: ${config.analytics.map((adapter) => adapter.kind).join(", ") || "none"}`
|
|
152
|
-
);
|
|
153
|
-
logger.info(
|
|
154
|
-
`Sources: ${config.content.sources.map((source) => source.kind).join(", ")}`
|
|
155
|
-
);
|
|
156
|
-
const { assistant } = config.ai;
|
|
157
|
-
let assistantSummary = "off";
|
|
158
|
-
if (assistant?.enabled) {
|
|
159
|
-
assistantSummary = assistant.endpoint
|
|
160
|
-
? "external endpoint"
|
|
161
|
-
: assistant.provider.kind;
|
|
167
|
+
for (const line of integrationSummary(config)) {
|
|
168
|
+
logger.info(line);
|
|
162
169
|
}
|
|
163
|
-
logger.info(`Assistant: ${assistantSummary}`);
|
|
164
170
|
}
|
|
165
171
|
} catch (error) {
|
|
166
172
|
if (error instanceof BlumeError) {
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { defineCommand } from "citty";
|
|
2
|
+
import { join } from "pathe";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
planSkill,
|
|
6
|
+
WRITE_SKILL_DIR,
|
|
7
|
+
writeSkillPrompt,
|
|
8
|
+
} from "../../ai/write-skill.ts";
|
|
9
|
+
import { AGENTS, launchInstalledAgent } from "../../audit/agent.ts";
|
|
10
|
+
import type { AgentKind } from "../../audit/agent.ts";
|
|
11
|
+
import { BlumeError } from "../../core/diagnostics.ts";
|
|
12
|
+
import { packageRoot } from "../../core/package-root.ts";
|
|
13
|
+
import { scanProject } from "../../core/project-graph.ts";
|
|
14
|
+
import { getBlumeVersion } from "../../core/version.ts";
|
|
15
|
+
import { commandMeta } from "../command-meta.ts";
|
|
16
|
+
import { reportInternalError } from "../internal-error.ts";
|
|
17
|
+
import { logger, reportDiagnostics } from "../log.ts";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* `blume skill` — write the docs site's agent skill with a coding agent. Every
|
|
21
|
+
* build publishes a generated skill at `/skill.md` (a map of the docs); this
|
|
22
|
+
* opens Claude Code or Codex on the `blume-write-skill` skill bundled in this
|
|
23
|
+
* package to write the richer one, grounded in the docs, under the same name
|
|
24
|
+
* so it takes the generated one's place. The judgment stays in the skill; the
|
|
25
|
+
* command is the front door, like `blume migrate`. Status lines go straight to
|
|
26
|
+
* stderr: consola drops info-level lines in test and CI environments.
|
|
27
|
+
*/
|
|
28
|
+
export const skillCommand = defineCommand({
|
|
29
|
+
args: {
|
|
30
|
+
claude: {
|
|
31
|
+
description: "Write the skill with Claude Code.",
|
|
32
|
+
type: "boolean",
|
|
33
|
+
},
|
|
34
|
+
codex: {
|
|
35
|
+
description: "Write the skill with Codex.",
|
|
36
|
+
type: "boolean",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
meta: commandMeta.skill,
|
|
40
|
+
async run({ args }) {
|
|
41
|
+
const root = process.cwd();
|
|
42
|
+
// SAFETY: AGENTS is a closed record keyed by AgentKind, so its keys are
|
|
43
|
+
// exactly the agent kinds.
|
|
44
|
+
const agents = (Object.keys(AGENTS) as AgentKind[]).filter(
|
|
45
|
+
(kind) => args[kind]
|
|
46
|
+
);
|
|
47
|
+
if (agents.length > 1) {
|
|
48
|
+
logger.error("Pass at most one of --codex or --claude.");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
const [agent] = agents;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// A scan, not `prepareProject`: the agent reads the content tree and
|
|
55
|
+
// the runtime isn't touched, so a running dev server is left alone.
|
|
56
|
+
const plan = planSkill(await scanProject(root, { mode: "build" }));
|
|
57
|
+
const skillDir = join(packageRoot(), WRITE_SKILL_DIR);
|
|
58
|
+
process.stderr.write(
|
|
59
|
+
` ${plan.exists ? "Updating" : "Writing"} the "${plan.name}" skill at ${plan.file}.\n`
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// Without an agent flag the command is the pointer for any other agent:
|
|
63
|
+
// the bundled skill's path, and the install line that puts the skill
|
|
64
|
+
// where agents look for it.
|
|
65
|
+
if (!agent) {
|
|
66
|
+
process.stderr.write(
|
|
67
|
+
` blume skill writes it with a coding agent: rerun with --codex or --claude.\n Using another agent? Point it at ${join(skillDir, "SKILL.md")},\n or install the skill where your agent looks for skills: npx skills add haydenbleasel/blume --skill blume-write-skill\n`
|
|
68
|
+
);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const cli = AGENTS[agent];
|
|
73
|
+
process.stderr.write(` Handing it to ${cli.name}…\n\n`);
|
|
74
|
+
const code = await launchInstalledAgent(
|
|
75
|
+
cli.bin,
|
|
76
|
+
writeSkillPrompt(plan, { skillDir, version: getBlumeVersion() })
|
|
77
|
+
);
|
|
78
|
+
if (code === null) {
|
|
79
|
+
logger.error(
|
|
80
|
+
`${cli.name} (\`${cli.bin}\`) was not found on PATH. Install it with \`${cli.install}\`.`
|
|
81
|
+
);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
if (code !== 0) {
|
|
85
|
+
process.exit(code);
|
|
86
|
+
}
|
|
87
|
+
} catch (error) {
|
|
88
|
+
if (error instanceof BlumeError) {
|
|
89
|
+
reportDiagnostics([error.diagnostic], root);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
reportInternalError(error);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
});
|
package/src/cli/index.ts
CHANGED
|
@@ -81,6 +81,11 @@ const main = defineCommand({
|
|
|
81
81
|
() => import("./commands/preview.ts"),
|
|
82
82
|
"previewCommand"
|
|
83
83
|
),
|
|
84
|
+
skill: lazyCommand(
|
|
85
|
+
commandMeta.skill,
|
|
86
|
+
() => import("./commands/skill.ts"),
|
|
87
|
+
"skillCommand"
|
|
88
|
+
),
|
|
84
89
|
sync: lazyCommand(
|
|
85
90
|
commandMeta.sync,
|
|
86
91
|
() => import("./commands/sync.ts"),
|
|
@@ -2,6 +2,60 @@ import { resolveAskBackend } from "../ai/ask.ts";
|
|
|
2
2
|
import type { ResolvedConfig } from "../core/schema.ts";
|
|
3
3
|
import type { Diagnostic } from "../core/types.ts";
|
|
4
4
|
|
|
5
|
+
/** A feature, and the secrets the adapter behind it reads. */
|
|
6
|
+
interface SecretOwner {
|
|
7
|
+
feature: string;
|
|
8
|
+
note?: string;
|
|
9
|
+
secrets: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The adapters that name their own secrets. The built-ins mostly declare
|
|
14
|
+
* none: analytics ships public tokens in the page, consent managers load
|
|
15
|
+
* public scripts, reference adapters read public specs, and host adapters
|
|
16
|
+
* read platform-injected env.
|
|
17
|
+
*/
|
|
18
|
+
const adapterSecretOwners = (config: ResolvedConfig): SecretOwner[] => {
|
|
19
|
+
const { consent, deployment, rateLimit } = config;
|
|
20
|
+
const { provider } = config.search;
|
|
21
|
+
const owners: SecretOwner[] = [
|
|
22
|
+
// Each search adapter declares the secrets its generated runtime reads.
|
|
23
|
+
{ feature: `Search (${provider.kind})`, secrets: provider.requiredSecrets },
|
|
24
|
+
...config.analytics.map((adapter) => ({
|
|
25
|
+
feature: `Analytics (${adapter.kind})`,
|
|
26
|
+
secrets: adapter.requiredSecrets,
|
|
27
|
+
})),
|
|
28
|
+
// Each content source adapter declares the env vars its fetch reads.
|
|
29
|
+
...config.content.sources.map((source) => ({
|
|
30
|
+
feature: `Content source (${source.kind})`,
|
|
31
|
+
secrets: source.requiredSecrets,
|
|
32
|
+
})),
|
|
33
|
+
...config.reference.map((adapter) => ({
|
|
34
|
+
feature: `API reference (${adapter.kind})`,
|
|
35
|
+
secrets: adapter.requiredSecrets,
|
|
36
|
+
})),
|
|
37
|
+
{
|
|
38
|
+
feature: `Deployment (${deployment.kind})`,
|
|
39
|
+
secrets: deployment.requiredSecrets,
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
if (consent) {
|
|
43
|
+
owners.push({
|
|
44
|
+
feature: `Consent (${consent.kind})`,
|
|
45
|
+
secrets: consent.requiredSecrets,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// Upstash's endpoint and token.
|
|
49
|
+
if (rateLimit) {
|
|
50
|
+
owners.push({
|
|
51
|
+
feature: `Rate limiting (${rateLimit.kind})`,
|
|
52
|
+
note: "read at request time; without it the routes count in memory",
|
|
53
|
+
secrets: rateLimit.requiredSecrets,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return owners;
|
|
57
|
+
};
|
|
58
|
+
|
|
5
59
|
/**
|
|
6
60
|
* Warn early when an enabled feature needs a secret env var that isn't set, so
|
|
7
61
|
* the failure surfaces at `blume dev`/`build` instead of at the first request in
|
|
@@ -26,47 +80,35 @@ export const checkRequiredSecrets = (config: ResolvedConfig): Diagnostic[] => {
|
|
|
26
80
|
|
|
27
81
|
if (config.ai.assistant?.enabled && !config.ai.assistant.endpoint) {
|
|
28
82
|
// The adapter descriptor names the env vars its route reads.
|
|
29
|
-
const { provider } = config.ai.assistant;
|
|
83
|
+
const { captcha, provider } = config.ai.assistant;
|
|
30
84
|
const backend = resolveAskBackend(provider);
|
|
31
85
|
for (const env of provider.requiredSecrets) {
|
|
32
86
|
requireSecret(`Assistant (${backend.label})`, env, backend.secretNote);
|
|
33
87
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const { provider } = config.search;
|
|
38
|
-
for (const env of provider.requiredSecrets) {
|
|
39
|
-
requireSecret(`Search (${provider.kind})`, env);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Adapters name their own secrets; the built-in analytics adapters ship
|
|
43
|
-
// public tokens in the page and declare none.
|
|
44
|
-
for (const adapter of config.analytics) {
|
|
45
|
-
for (const env of adapter.requiredSecrets) {
|
|
46
|
-
requireSecret(`Analytics (${adapter.kind})`, env);
|
|
88
|
+
// The bot check's secret key, which the route verifies tokens with.
|
|
89
|
+
for (const env of captcha?.requiredSecrets ?? []) {
|
|
90
|
+
requireSecret(`Assistant bot check (${captcha?.kind})`, env);
|
|
47
91
|
}
|
|
48
92
|
}
|
|
49
93
|
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
94
|
+
// Generated narration reads its key at build, not at runtime; without it the
|
|
95
|
+
// build skips the audio and pages read with browser voices.
|
|
96
|
+
const { narration } = config;
|
|
97
|
+
if (narration.enabled && narration.provider) {
|
|
98
|
+
for (const env of narration.provider.requiredSecrets) {
|
|
99
|
+
requireSecret(
|
|
100
|
+
"Narration audio",
|
|
101
|
+
env,
|
|
102
|
+
"read at build; without it pages use browser voices"
|
|
103
|
+
);
|
|
54
104
|
}
|
|
55
105
|
}
|
|
56
106
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
for (const env of adapter.requiredSecrets) {
|
|
61
|
-
requireSecret(`API reference (${adapter.kind})`, env);
|
|
107
|
+
for (const owner of adapterSecretOwners(config)) {
|
|
108
|
+
for (const env of owner.secrets) {
|
|
109
|
+
requireSecret(owner.feature, env, owner.note);
|
|
62
110
|
}
|
|
63
111
|
}
|
|
64
112
|
|
|
65
|
-
// The deployment adapter names its own secrets; the built-in host adapters
|
|
66
|
-
// read platform-injected env and declare none.
|
|
67
|
-
for (const env of config.deployment.requiredSecrets) {
|
|
68
|
-
requireSecret(`Deployment (${config.deployment.kind})`, env);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
113
|
return diagnostics;
|
|
72
114
|
};
|
|
@@ -49,6 +49,7 @@ import TreeRoot from "./content/Tree.astro";
|
|
|
49
49
|
import TreeFile from "./content/TreeFile.astro";
|
|
50
50
|
import TreeFolder from "./content/TreeFolder.astro";
|
|
51
51
|
import TypeTable from "./content/TypeTable.astro";
|
|
52
|
+
import View from "./content/View.astro";
|
|
52
53
|
import Visibility from "./content/Visibility.astro";
|
|
53
54
|
import YouTube from "./content/YouTube.astro";
|
|
54
55
|
|
|
@@ -96,6 +97,7 @@ const components = {
|
|
|
96
97
|
Tooltip,
|
|
97
98
|
Tree,
|
|
98
99
|
TypeTable,
|
|
100
|
+
View,
|
|
99
101
|
Visibility,
|
|
100
102
|
YouTube,
|
|
101
103
|
...extra,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
// The method and path at the top of a page with `api` frontmatter, as an
|
|
3
|
+
// OpenAPI operation page shows them. `markdown/api-rail.ts` places it.
|
|
4
|
+
import MethodBadge from "../openapi/MethodBadge.astro";
|
|
5
|
+
import { readEndpointSpec } from "./api-page.ts";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
/** The endpoint, as the page's plugin wrote it. */
|
|
9
|
+
spec: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { method, target } = readEndpointSpec(Astro.props.spec);
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<div class="not-prose mb-6 flex flex-wrap items-center gap-3">
|
|
16
|
+
<MethodBadge method={method} />
|
|
17
|
+
<code class="break-all font-mono text-foreground text-sm">{target}</code>
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
// The row behind `<ParamField>` and `<ResponseField>`: the name with its
|
|
3
|
+
// labels, location, type, and flags, the default, then the description from
|
|
4
|
+
// the slot, which may hold any MDX, nested fields in an `<Expandable>`
|
|
5
|
+
// included. Styled like the OpenAPI reference's rows, so a hand-written API
|
|
6
|
+
// page reads like a generated one. Narration skips it, as it does type tables.
|
|
7
|
+
import { defaultLabel, isOn } from "./api-field.ts";
|
|
8
|
+
import type { FieldValue, FlagProp } from "./api-field.ts";
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
default?: FieldValue;
|
|
12
|
+
deprecated?: FlagProp;
|
|
13
|
+
location?: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
post?: string[];
|
|
16
|
+
pre?: string[];
|
|
17
|
+
required?: FlagProp;
|
|
18
|
+
type?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
default: value,
|
|
23
|
+
deprecated,
|
|
24
|
+
location,
|
|
25
|
+
name,
|
|
26
|
+
post = [],
|
|
27
|
+
pre = [],
|
|
28
|
+
required,
|
|
29
|
+
type,
|
|
30
|
+
} = Astro.props;
|
|
31
|
+
const shownDefault = defaultLabel(value);
|
|
32
|
+
const labelClass =
|
|
33
|
+
"rounded bg-muted px-1.5 py-0.5 font-medium text-[0.625rem] text-muted-foreground uppercase tracking-wide";
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
<div
|
|
37
|
+
class="border-border border-b py-4"
|
|
38
|
+
data-blume-field
|
|
39
|
+
data-blume-narration="skip"
|
|
40
|
+
>
|
|
41
|
+
<div class="not-prose flex flex-wrap items-baseline gap-x-2 gap-y-1">
|
|
42
|
+
{pre.map((label) => <span class={labelClass}>{label}</span>)}
|
|
43
|
+
{name && <code class="font-mono text-foreground text-sm">{name}</code>}
|
|
44
|
+
{post.map((label) => <span class={labelClass}>{label}</span>)}
|
|
45
|
+
{location && <span class={labelClass}>{location}</span>}
|
|
46
|
+
{type && <span class="text-muted-foreground text-xs">{type}</span>}
|
|
47
|
+
{
|
|
48
|
+
isOn(required) && (
|
|
49
|
+
<span class="font-medium text-[0.625rem] text-red-600 uppercase tracking-wide dark:text-red-400">
|
|
50
|
+
required
|
|
51
|
+
</span>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
{
|
|
55
|
+
isOn(deprecated) && (
|
|
56
|
+
<span class="font-medium text-[0.625rem] text-muted-foreground uppercase tracking-wide line-through">
|
|
57
|
+
deprecated
|
|
58
|
+
</span>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
</div>
|
|
62
|
+
{
|
|
63
|
+
shownDefault !== null && (
|
|
64
|
+
<div class="not-prose mt-2 text-muted-foreground text-xs">
|
|
65
|
+
Default:{" "}
|
|
66
|
+
<code class="rounded bg-muted px-1 py-0.5 text-foreground">
|
|
67
|
+
{shownDefault}
|
|
68
|
+
</code>
|
|
69
|
+
</div>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
{
|
|
73
|
+
Astro.slots.has("default") && (
|
|
74
|
+
<div class="mt-2 text-muted-foreground text-sm [&>:first-child]:mt-0 [&>:last-child]:mb-0">
|
|
75
|
+
<slot />
|
|
76
|
+
</div>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
</div>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
// A hand-written endpoint's Try it panel and request samples, at the head of
|
|
3
|
+
// its rail: the page's `<ParamField>`s become the parameters and body of an
|
|
4
|
+
// operation model like a spec'd operation's (see `api-page.ts`), so the
|
|
5
|
+
// playground and the samples are the OpenAPI reference's own. A page's own
|
|
6
|
+
// `<RequestExample>` stands in for the generated samples, and its
|
|
7
|
+
// `playground` frontmatter can drop the Try it panel (`simple`).
|
|
8
|
+
import data from "blume:data";
|
|
9
|
+
|
|
10
|
+
import { operationModel } from "../openapi/operation-model.ts";
|
|
11
|
+
import Playground from "../openapi/Playground.astro";
|
|
12
|
+
import { buildRequest, defaultValues } from "../openapi/request.ts";
|
|
13
|
+
import RequestPanel from "../openapi/RequestPanel.astro";
|
|
14
|
+
import { sampleLanguages } from "../openapi/snippets.ts";
|
|
15
|
+
import {
|
|
16
|
+
endpointBody,
|
|
17
|
+
endpointParameters,
|
|
18
|
+
endpointSecurity,
|
|
19
|
+
endpointTarget,
|
|
20
|
+
readEndpointSpec,
|
|
21
|
+
} from "./api-page.ts";
|
|
22
|
+
|
|
23
|
+
interface Props {
|
|
24
|
+
/** The endpoint, as the page's plugin wrote it. */
|
|
25
|
+
spec: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const spec = readEndpointSpec(Astro.props.spec);
|
|
29
|
+
const { api } = data.config;
|
|
30
|
+
const { path, servers } = endpointTarget(spec.target, api.server);
|
|
31
|
+
const model = operationModel({
|
|
32
|
+
method: spec.method,
|
|
33
|
+
parameters: endpointParameters(spec.fields),
|
|
34
|
+
path,
|
|
35
|
+
requestBody: endpointBody(spec.fields),
|
|
36
|
+
schemas: {},
|
|
37
|
+
security: endpointSecurity(spec.authMethod, api.auth),
|
|
38
|
+
servers,
|
|
39
|
+
});
|
|
40
|
+
const tryIt = spec.playground !== "simple" && api.playground.enabled;
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
{
|
|
44
|
+
tryIt && (
|
|
45
|
+
<Playground
|
|
46
|
+
model={model}
|
|
47
|
+
operation={`${spec.method} ${spec.target}`}
|
|
48
|
+
proxy={api.playground.proxy}
|
|
49
|
+
slug="api-pages"
|
|
50
|
+
/>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
{
|
|
54
|
+
!spec.requestExample && (
|
|
55
|
+
<RequestPanel
|
|
56
|
+
languages={sampleLanguages([])}
|
|
57
|
+
responses={{}}
|
|
58
|
+
sample={buildRequest(model, defaultValues(model))}
|
|
59
|
+
schemas={{}}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
// The column `<RequestExample>` and `<ResponseExample>` pin to, which
|
|
3
|
+
// `markdown/api-rail.ts` gathers at the end of the page. At `xl` it sits
|
|
4
|
+
// beside the page's content, which the layout pads to make room, and sticks
|
|
5
|
+
// under the header like an OpenAPI operation's sample panel; below `xl` it
|
|
6
|
+
// follows the content.
|
|
7
|
+
import OperationPanel from "../openapi/OperationPanel.astro";
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<div
|
|
11
|
+
class="not-prose mt-10 xl:absolute xl:inset-y-0 xl:end-0 xl:mt-0 xl:w-[28rem]"
|
|
12
|
+
data-blume-api-rail
|
|
13
|
+
>
|
|
14
|
+
<OperationPanel>
|
|
15
|
+
<div class="flex flex-col gap-4 [&>*]:my-0">
|
|
16
|
+
<slot />
|
|
17
|
+
</div>
|
|
18
|
+
</OperationPanel>
|
|
19
|
+
</div>
|
|
@@ -73,6 +73,7 @@ const { content: strings } = contentStrings(data, Astro.currentLocale);
|
|
|
73
73
|
owner && repo && (
|
|
74
74
|
<a
|
|
75
75
|
class="not-prose my-6 flex flex-col gap-2 rounded-blume border border-border p-4 no-underline! transition-colors hover:border-foreground/30 hover:bg-muted/40"
|
|
76
|
+
data-blume-narration="skip"
|
|
76
77
|
href={`${host}/${owner}/${repo}`}
|
|
77
78
|
{...NEW_TAB_ATTRS}
|
|
78
79
|
>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
// `<ParamField query="limit" type="integer" required>`: a request parameter,
|
|
3
|
+
// named by the attribute that says where it goes (`path`, `query`, `header`,
|
|
4
|
+
// or `body`), with its description in the slot. On a page with `api`
|
|
5
|
+
// frontmatter the fields also build that page's playground.
|
|
6
|
+
import ApiField from "./ApiField.astro";
|
|
7
|
+
import { paramField } from "./api-field.ts";
|
|
8
|
+
import type { ParamFieldProps } from "./api-field.ts";
|
|
9
|
+
|
|
10
|
+
type Props = ParamFieldProps;
|
|
11
|
+
|
|
12
|
+
const { location, name } = paramField(Astro.props);
|
|
13
|
+
const { default: value, deprecated, required, type } = Astro.props;
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<ApiField
|
|
17
|
+
default={value}
|
|
18
|
+
deprecated={deprecated}
|
|
19
|
+
location={location}
|
|
20
|
+
name={name}
|
|
21
|
+
required={required}
|
|
22
|
+
type={type}
|
|
23
|
+
>
|
|
24
|
+
<slot />
|
|
25
|
+
</ApiField>
|