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
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { exec, query } from "jsonpath-rfc9535";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
import type { JsonValue } from "../core/adapter.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* OpenAPI Overlays: the OpenAPI Initiative's format for changing an API
|
|
8
|
+
* description without editing it — an ordered list of actions, each an RFC
|
|
9
|
+
* 9535 JSONPath `target` with an `update` to merge in, a `copy` of another
|
|
10
|
+
* node to merge in, or `remove`. A spec generated by another tool or owned by
|
|
11
|
+
* another team can then carry docs-only changes (better descriptions, hidden
|
|
12
|
+
* internal operations, a public server URL) in a file of its own.
|
|
13
|
+
*
|
|
14
|
+
* Implements Overlay Specification 1.0 and 1.1 over `jsonpath-rfc9535`, which
|
|
15
|
+
* passes the JSONPath compliance suite in full, as the spec requires. The
|
|
16
|
+
* documents here are already parsed; `parse.ts` reads the files.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** An overlay document or action that doesn't follow the spec. */
|
|
20
|
+
export class OverlayError extends Error {
|
|
21
|
+
constructor(message: string) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "OverlayError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** An object node, the only kind that holds named properties. */
|
|
28
|
+
interface JsonObject {
|
|
29
|
+
[key: string]: JsonValue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A node that holds other nodes: where a match's parent can be. */
|
|
33
|
+
type JsonContainer = JsonObject | JsonValue[];
|
|
34
|
+
|
|
35
|
+
const isObject = (value: JsonValue | undefined): value is JsonObject =>
|
|
36
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A parsed YAML or JSON mapping, as the document an overlay acts on: the
|
|
40
|
+
* parser's own types say nothing of JSON, but what it parses is JSON.
|
|
41
|
+
*/
|
|
42
|
+
export const isJsonObject = <Value>(
|
|
43
|
+
value: Value
|
|
44
|
+
): value is Value & JsonObject =>
|
|
45
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
46
|
+
|
|
47
|
+
const isContainer = (value: JsonValue | undefined): value is JsonContainer =>
|
|
48
|
+
typeof value === "object" && value !== null;
|
|
49
|
+
|
|
50
|
+
const isIndex = (key: string | number | undefined): key is number =>
|
|
51
|
+
typeof key === "number";
|
|
52
|
+
|
|
53
|
+
/** An object, an array, or anything else: what update merging keys on. */
|
|
54
|
+
type MergeKind = "array" | "object" | "primitive";
|
|
55
|
+
|
|
56
|
+
const mergeKindOf = (value: JsonValue): MergeKind => {
|
|
57
|
+
if (Array.isArray(value)) {
|
|
58
|
+
return "array";
|
|
59
|
+
}
|
|
60
|
+
return isObject(value) ? "object" : "primitive";
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** A merge kind in a sentence. */
|
|
64
|
+
const MERGE_KIND_PHRASE: Record<MergeKind, string> = {
|
|
65
|
+
array: "an array",
|
|
66
|
+
object: "an object",
|
|
67
|
+
primitive: "a primitive value",
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const actionSchema = z.looseObject({
|
|
71
|
+
/** A JSONPath expression selecting one node to merge into the targets (1.1). */
|
|
72
|
+
copy: z.string().optional(),
|
|
73
|
+
description: z.string().optional(),
|
|
74
|
+
/** Remove every target from the map or array it's in. */
|
|
75
|
+
remove: z.boolean().default(false),
|
|
76
|
+
/** An RFC 9535 JSONPath expression selecting the nodes to act on. */
|
|
77
|
+
target: z.string().min(1),
|
|
78
|
+
/** A value merged into every target. */
|
|
79
|
+
update: z.json().optional(),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
/** A validated overlay action. */
|
|
83
|
+
type OverlayAction = z.output<typeof actionSchema>;
|
|
84
|
+
|
|
85
|
+
const overlaySchema = z.looseObject({
|
|
86
|
+
actions: z.array(actionSchema).min(1),
|
|
87
|
+
extends: z.string().optional(),
|
|
88
|
+
info: z.looseObject({ title: z.string(), version: z.string() }),
|
|
89
|
+
overlay: z.string().regex(/^1\.[01]\.\d+$/u, {
|
|
90
|
+
message: "must be an Overlay Specification version, 1.0.x or 1.1.x",
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
/** A validated overlay document. */
|
|
95
|
+
export type OverlayDocument = z.output<typeof overlaySchema>;
|
|
96
|
+
|
|
97
|
+
/** Validate a parsed overlay document, naming the file in any error. */
|
|
98
|
+
export const overlayDocument = <Value>(
|
|
99
|
+
value: Value,
|
|
100
|
+
name: string
|
|
101
|
+
): OverlayDocument => {
|
|
102
|
+
const parsed = overlaySchema.safeParse(value);
|
|
103
|
+
if (parsed.success) {
|
|
104
|
+
return parsed.data;
|
|
105
|
+
}
|
|
106
|
+
const [issue] = parsed.error.issues;
|
|
107
|
+
const at = issue?.path.length ? `\`${issue.path.join(".")}\` ` : "";
|
|
108
|
+
throw new OverlayError(
|
|
109
|
+
`${name} is not an overlay document: ${at}${issue?.message ?? "invalid"}.`
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/** A matched node, where it sits, and how to reach it. */
|
|
114
|
+
interface Match {
|
|
115
|
+
key?: string | number;
|
|
116
|
+
parent?: JsonContainer;
|
|
117
|
+
value: JsonValue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** The nodes `expression` selects, each with its parent (none for the root). */
|
|
121
|
+
const select = (document: JsonValue, expression: string): Match[] => {
|
|
122
|
+
const matches: Match[] = [];
|
|
123
|
+
exec(document, expression, (value, path) => {
|
|
124
|
+
let parent: JsonValue = document;
|
|
125
|
+
for (const key of path.slice(0, -1)) {
|
|
126
|
+
// SAFETY: the path is one the query walked, so every step is a key of
|
|
127
|
+
// the container before it.
|
|
128
|
+
parent = (parent as Record<string | number, JsonValue>)[key] ?? null;
|
|
129
|
+
}
|
|
130
|
+
const key = path.at(-1);
|
|
131
|
+
matches.push(
|
|
132
|
+
key === undefined || !isContainer(parent)
|
|
133
|
+
? { value }
|
|
134
|
+
: { key, parent, value }
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
return matches;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Merge `patch` into `target` as the spec says: objects recursively, arrays
|
|
142
|
+
* by concatenation, a primitive replaced by a primitive. Returns the merged
|
|
143
|
+
* value; any other pairing throws.
|
|
144
|
+
*/
|
|
145
|
+
const merge = (target: JsonValue, patch: JsonValue, at: string): JsonValue => {
|
|
146
|
+
if (isObject(target) && isObject(patch)) {
|
|
147
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
148
|
+
// Only recurse into the target's own keys, so a `__proto__` or
|
|
149
|
+
// `constructor` key can't reach a prototype.
|
|
150
|
+
target[key] = Object.hasOwn(target, key)
|
|
151
|
+
? merge(target[key] ?? null, value, `${at}.${key}`)
|
|
152
|
+
: structuredClone(value);
|
|
153
|
+
}
|
|
154
|
+
return target;
|
|
155
|
+
}
|
|
156
|
+
if (Array.isArray(target) && Array.isArray(patch)) {
|
|
157
|
+
target.push(...structuredClone(patch));
|
|
158
|
+
return target;
|
|
159
|
+
}
|
|
160
|
+
if (
|
|
161
|
+
mergeKindOf(target) === "primitive" &&
|
|
162
|
+
mergeKindOf(patch) === "primitive"
|
|
163
|
+
) {
|
|
164
|
+
return patch;
|
|
165
|
+
}
|
|
166
|
+
throw new OverlayError(
|
|
167
|
+
`can't merge ${MERGE_KIND_PHRASE[mergeKindOf(patch)]} into ${MERGE_KIND_PHRASE[mergeKindOf(target)]} at ${at}`
|
|
168
|
+
);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/** Remove each match from its container, later siblings first. */
|
|
172
|
+
const removeAll = (matches: Match[]): void => {
|
|
173
|
+
for (const { key, parent } of matches.toReversed()) {
|
|
174
|
+
if (Array.isArray(parent) && isIndex(key)) {
|
|
175
|
+
parent.splice(key, 1);
|
|
176
|
+
} else if (isObject(parent) && key !== undefined && !isIndex(key)) {
|
|
177
|
+
// oxlint-disable-next-line typescript/no-dynamic-delete -- an overlay target's key is only known at run time
|
|
178
|
+
delete parent[key];
|
|
179
|
+
} else {
|
|
180
|
+
throw new OverlayError("can't remove the document itself");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Merge `patch` into every match, which must all be objects, all arrays, or
|
|
187
|
+
* all primitives. A primitive match is replaced in its parent.
|
|
188
|
+
*/
|
|
189
|
+
const mergeAll = (matches: Match[], patch: JsonValue, target: string) => {
|
|
190
|
+
const kinds = new Set(matches.map((match) => mergeKindOf(match.value)));
|
|
191
|
+
if (kinds.size > 1) {
|
|
192
|
+
throw new OverlayError(
|
|
193
|
+
`its target selects a mix of ${[...kinds].toSorted().join(", ")} values, and an update needs all one kind`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
for (const { key, parent, value } of matches) {
|
|
197
|
+
const merged = merge(value, patch, target);
|
|
198
|
+
if (merged !== value && parent !== undefined && key !== undefined) {
|
|
199
|
+
// SAFETY: `key` came from walking `parent`, so it indexes it.
|
|
200
|
+
(parent as Record<string | number, JsonValue>)[key] = merged;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/** The single node a `copy` expression selects, cloned. */
|
|
206
|
+
const copied = (document: JsonValue, expression: string): JsonValue => {
|
|
207
|
+
const values = query(document, expression);
|
|
208
|
+
const [value] = values;
|
|
209
|
+
if (values.length !== 1 || value === undefined) {
|
|
210
|
+
throw new OverlayError(
|
|
211
|
+
`its copy expression "${expression}" selects ${values.length} nodes, and copy needs exactly one`
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return structuredClone(value);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const applyAction = (document: JsonValue, action: OverlayAction): void => {
|
|
218
|
+
const matches = select(document, action.target);
|
|
219
|
+
if (matches.length === 0) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (action.remove) {
|
|
223
|
+
removeAll(matches);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const patch =
|
|
227
|
+
action.update ??
|
|
228
|
+
(action.copy === undefined ? undefined : copied(document, action.copy));
|
|
229
|
+
if (patch !== undefined) {
|
|
230
|
+
mergeAll(matches, patch, action.target);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Apply an overlay to a parsed document, in place and in action order: each
|
|
236
|
+
* action sees the result of the one before. A target that matches nothing
|
|
237
|
+
* changes nothing. Throws an {@link OverlayError} naming the overlay file and
|
|
238
|
+
* the action that failed.
|
|
239
|
+
*/
|
|
240
|
+
export const applyOverlay = (
|
|
241
|
+
document: JsonValue,
|
|
242
|
+
overlay: OverlayDocument,
|
|
243
|
+
name: string
|
|
244
|
+
): void => {
|
|
245
|
+
for (const [index, action] of overlay.actions.entries()) {
|
|
246
|
+
try {
|
|
247
|
+
applyAction(document, action);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
// SAFETY: the JSONPath parser and this module throw Error instances.
|
|
250
|
+
const { message } = error as Error;
|
|
251
|
+
throw new OverlayError(
|
|
252
|
+
`${name} action ${index + 1} (${action.target}): ${message}`
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
};
|
package/src/openapi/parse.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { setTimeout as sleep } from "node:timers/promises";
|
|
|
4
4
|
import type * as ConverterModule from "@asyncapi/converter";
|
|
5
5
|
import { normalize, upgrade } from "@scalar/openapi-parser";
|
|
6
6
|
import pRetry, { AbortError } from "p-retry";
|
|
7
|
-
import { isAbsolute, join } from "pathe";
|
|
7
|
+
import { dirname, isAbsolute, join, resolve } from "pathe";
|
|
8
8
|
import type * as UndiciModule from "undici";
|
|
9
9
|
|
|
10
10
|
import {
|
|
@@ -15,15 +15,21 @@ import { nodeRequire } from "../core/node-require.ts";
|
|
|
15
15
|
import { hashText } from "../core/sources/cache.ts";
|
|
16
16
|
import type { AsyncApiDocument } from "./asyncapi.ts";
|
|
17
17
|
import { normalizeAsyncApiDocument } from "./asyncapi.ts";
|
|
18
|
+
import { operationLabel } from "./checks.ts";
|
|
19
|
+
import type { SpecIssue } from "./checks.ts";
|
|
18
20
|
import { buildGraphqlDocument } from "./graphql-build.ts";
|
|
19
21
|
import type { GraphqlDocument } from "./graphql.ts";
|
|
22
|
+
import { HTTP_METHODS } from "./model.ts";
|
|
20
23
|
import type { ApiDocument } from "./model.ts";
|
|
24
|
+
import { applyOverlay, isJsonObject, overlayDocument } from "./overlay.ts";
|
|
21
25
|
import { SpecDependencyError } from "./spec-dependency-error.ts";
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
28
|
* Spec loading and normalization. Blume reuses Scalar's parser
|
|
25
29
|
* (`@scalar/openapi-parser`) to read a spec (YAML or JSON), then upgrade Swagger
|
|
26
30
|
* 2.0 / OpenAPI 3.0 documents to 3.1 so the renderer only handles one shape.
|
|
31
|
+
* OpenAPI 3.2 is backward compatible with 3.1, so a 3.2 document is read as
|
|
32
|
+
* written.
|
|
27
33
|
* Internal `$ref`s are deliberately left in place (see `model.ts`).
|
|
28
34
|
*
|
|
29
35
|
* Remote (`http(s)`) specs are fetched defensively — bounded per attempt, retried
|
|
@@ -57,6 +63,8 @@ const PROXY_ENV_VARS = [
|
|
|
57
63
|
|
|
58
64
|
export interface ParsedSpec {
|
|
59
65
|
document: ApiDocument;
|
|
66
|
+
/** `x-codeSamples` entries whose `$ref` couldn't be inlined. */
|
|
67
|
+
issues: SpecIssue[];
|
|
60
68
|
warnings: string[];
|
|
61
69
|
}
|
|
62
70
|
|
|
@@ -75,6 +83,11 @@ export class InvalidSpecError extends Error {
|
|
|
75
83
|
|
|
76
84
|
/** Where and whether to cache a remote spec's text between runs. */
|
|
77
85
|
export interface SpecFetchOptions {
|
|
86
|
+
/**
|
|
87
|
+
* Overlay documents (local paths or `http(s)` URLs) applied in order to
|
|
88
|
+
* the parsed spec, before it's upgraded. See `overlay.ts`.
|
|
89
|
+
*/
|
|
90
|
+
overlays?: readonly string[];
|
|
78
91
|
/** Dir for a last-good on-disk copy of a remote spec (offline fallback). */
|
|
79
92
|
cacheDir?: string;
|
|
80
93
|
/**
|
|
@@ -310,13 +323,177 @@ const readSpecText = async (
|
|
|
310
323
|
const isApiDocument = <Value>(value: Value): value is Value & ApiDocument =>
|
|
311
324
|
typeof value === "object" && value !== null;
|
|
312
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Read a spec and apply its overlays, in order, to the parsed document as
|
|
328
|
+
* written (before any upgrade: an overlay targets its spec's own version).
|
|
329
|
+
* The overlays are read like the spec, local or remote, cached alike.
|
|
330
|
+
*/
|
|
331
|
+
const readOverlaid = async (
|
|
332
|
+
spec: string,
|
|
333
|
+
root: string,
|
|
334
|
+
options: SpecFetchOptions
|
|
335
|
+
): Promise<{ document: ReturnType<typeof normalize>; warnings: string[] }> => {
|
|
336
|
+
const [read, ...overlays] = await Promise.all(
|
|
337
|
+
[spec, ...(options.overlays ?? [])].map((path) =>
|
|
338
|
+
readSpecText(path, root, options)
|
|
339
|
+
)
|
|
340
|
+
);
|
|
341
|
+
const document = normalize(read?.text ?? "");
|
|
342
|
+
for (const [index, overlay] of overlays.entries()) {
|
|
343
|
+
const name = options.overlays?.[index] ?? "";
|
|
344
|
+
const parsed = overlayDocument(normalize(overlay.text), name);
|
|
345
|
+
// A spec that isn't a mapping has nothing to overlay; the caller
|
|
346
|
+
// rejects it as it would without overlays.
|
|
347
|
+
if (isJsonObject(document)) {
|
|
348
|
+
applyOverlay(document, parsed, name);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
document,
|
|
353
|
+
warnings: [read, ...overlays].flatMap((entry) => entry?.warnings ?? []),
|
|
354
|
+
};
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* A spec with its overlays applied, as JSON text: what the Scalar embed
|
|
359
|
+
* inlines, since it can't apply overlays itself.
|
|
360
|
+
*/
|
|
361
|
+
export const readOverlaidSpec = async (
|
|
362
|
+
spec: string,
|
|
363
|
+
root: string,
|
|
364
|
+
options: SpecFetchOptions
|
|
365
|
+
): Promise<{ text: string; warnings: string[] }> => {
|
|
366
|
+
const { document, warnings } = await readOverlaid(spec, root, options);
|
|
367
|
+
return { text: JSON.stringify(document), warnings };
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
/** A `$ref` in place of an `x-codeSamples` entry's `source`. */
|
|
371
|
+
interface SampleRef {
|
|
372
|
+
$ref: string;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/** An `x-codeSamples` entry whose `source` is a `$ref` rather than the code. */
|
|
376
|
+
const isRefSample = (value: unknown): value is { source: SampleRef } =>
|
|
377
|
+
isJsonObject(value) &&
|
|
378
|
+
isJsonObject(value.source) &&
|
|
379
|
+
typeof value.source.$ref === "string";
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Where a code sample's `$ref` points, in the form `readSpecText` reads: a
|
|
383
|
+
* URL, or a path resolved against the spec's own location. `undefined` for
|
|
384
|
+
* a JSON pointer (`#/…`, or a file with a fragment), which names a spot
|
|
385
|
+
* inside a document rather than a file of code.
|
|
386
|
+
*/
|
|
387
|
+
const sampleTarget = (
|
|
388
|
+
ref: string,
|
|
389
|
+
spec: string,
|
|
390
|
+
root: string
|
|
391
|
+
): string | undefined => {
|
|
392
|
+
if (ref.includes("#")) {
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
if (URL_SPEC.test(ref)) {
|
|
396
|
+
return ref;
|
|
397
|
+
}
|
|
398
|
+
if (URL_SPEC.test(spec)) {
|
|
399
|
+
return new URL(ref, spec).href;
|
|
400
|
+
}
|
|
401
|
+
return resolve(dirname(isAbsolute(spec) ? spec : join(root, spec)), ref);
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Inline each `x-codeSamples` entry whose `source` is a `$ref` to a file of
|
|
406
|
+
* its own, as Redocly's docs describe (`source: { $ref: ../code_samples/… }`):
|
|
407
|
+
* `redocly bundle` inlines those, and a spec read as written doesn't. Each
|
|
408
|
+
* file is read relative to the spec,
|
|
409
|
+
* the way the spec itself was (local, or fetched and cached), so the sample
|
|
410
|
+
* renders like a written-out one. An entry that can't be read is left out of
|
|
411
|
+
* the page, with a warning, rather than dropped without a sign.
|
|
412
|
+
*/
|
|
413
|
+
const inlineSampleRefs = async (
|
|
414
|
+
document: ApiDocument,
|
|
415
|
+
spec: string,
|
|
416
|
+
root: string,
|
|
417
|
+
options: SpecFetchOptions
|
|
418
|
+
): Promise<SpecIssue[]> => {
|
|
419
|
+
const reads: Promise<SpecIssue | undefined>[] = [];
|
|
420
|
+
const inline = async (
|
|
421
|
+
entry: { source: SampleRef | string },
|
|
422
|
+
ref: string,
|
|
423
|
+
label: string
|
|
424
|
+
): Promise<SpecIssue | undefined> => {
|
|
425
|
+
const target = sampleTarget(ref, spec, root);
|
|
426
|
+
if (target === undefined) {
|
|
427
|
+
return {
|
|
428
|
+
code: "BLUME_OPENAPI_CODE_SAMPLE_REF",
|
|
429
|
+
message: `${label} has an \`x-codeSamples\` entry whose \`source\` is a $ref to "${ref}", a spot inside a document, which Blume doesn't resolve, so the sample is left out.`,
|
|
430
|
+
suggestion:
|
|
431
|
+
"Point the `$ref` at a file that holds only the sample's code, or write the code out in `source`.",
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
try {
|
|
435
|
+
const { text } = await readSpecText(target, root, options);
|
|
436
|
+
entry.source = text;
|
|
437
|
+
return undefined;
|
|
438
|
+
} catch (error) {
|
|
439
|
+
// SAFETY: a failed read throws a Node error, and a failed fetch an
|
|
440
|
+
// Error (`attemptFetch` wraps anything else); only the message is shown.
|
|
441
|
+
const { message } = error as Error;
|
|
442
|
+
return {
|
|
443
|
+
code: "BLUME_OPENAPI_CODE_SAMPLE_REF",
|
|
444
|
+
message: `${label} has an \`x-codeSamples\` entry whose \`source\` is a $ref to "${ref}", which couldn't be read (${message}), so the sample is left out.`,
|
|
445
|
+
suggestion:
|
|
446
|
+
"Check the path, which is relative to the spec, or write the code out in `source`.",
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
const visit = (
|
|
451
|
+
name: string,
|
|
452
|
+
item: NonNullable<ApiDocument["paths"]>[string] | undefined,
|
|
453
|
+
webhook: boolean
|
|
454
|
+
): void => {
|
|
455
|
+
if (!isJsonObject(item) || "$ref" in item) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
for (const method of HTTP_METHODS) {
|
|
459
|
+
const operation = item[method];
|
|
460
|
+
// The spelling `customCodeSamples` renders: the current one wins.
|
|
461
|
+
const samples = isJsonObject(operation)
|
|
462
|
+
? (operation["x-codeSamples"] ?? operation["x-code-samples"])
|
|
463
|
+
: undefined;
|
|
464
|
+
for (const entry of Array.isArray(samples) ? samples : []) {
|
|
465
|
+
if (isRefSample(entry)) {
|
|
466
|
+
reads.push(
|
|
467
|
+
inline(
|
|
468
|
+
entry,
|
|
469
|
+
entry.source.$ref,
|
|
470
|
+
operationLabel(name, method, webhook)
|
|
471
|
+
)
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
for (const [path, item] of Object.entries(document.paths ?? {})) {
|
|
478
|
+
visit(path, item, false);
|
|
479
|
+
}
|
|
480
|
+
for (const [name, item] of Object.entries(document.webhooks ?? {})) {
|
|
481
|
+
visit(name, item, true);
|
|
482
|
+
}
|
|
483
|
+
const issues = await Promise.all(reads);
|
|
484
|
+
return issues.filter((issue) => issue !== undefined);
|
|
485
|
+
};
|
|
486
|
+
|
|
313
487
|
export const parseSpec = async (
|
|
314
488
|
spec: string,
|
|
315
489
|
root: string,
|
|
316
490
|
options: SpecFetchOptions = {}
|
|
317
491
|
): Promise<ParsedSpec> => {
|
|
318
|
-
const {
|
|
319
|
-
|
|
492
|
+
const { document: normalized, warnings } = await readOverlaid(
|
|
493
|
+
spec,
|
|
494
|
+
root,
|
|
495
|
+
options
|
|
496
|
+
);
|
|
320
497
|
const { specification } = upgrade(normalized);
|
|
321
498
|
// Reject a non-mapping here so the renderer never sees a non-document.
|
|
322
499
|
if (!isApiDocument(specification)) {
|
|
@@ -324,7 +501,8 @@ export const parseSpec = async (
|
|
|
324
501
|
`${spec} is not a valid OpenAPI document (expected a YAML or JSON object).`
|
|
325
502
|
);
|
|
326
503
|
}
|
|
327
|
-
|
|
504
|
+
const issues = await inlineSampleRefs(specification, spec, root, options);
|
|
505
|
+
return { document: specification, issues, warnings };
|
|
328
506
|
};
|
|
329
507
|
|
|
330
508
|
export interface ParsedAsyncApiSpec {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { isAbsolute, join } from "pathe";
|
|
2
|
+
|
|
1
3
|
import { normalizeRoute, withBasePath } from "../core/base-path.ts";
|
|
2
4
|
import type { ResolvedConfig } from "../core/schema.ts";
|
|
3
5
|
import { trimChar } from "../core/trim.ts";
|
|
6
|
+
import type { GraphqlAuthOptions } from "../reference/options.ts";
|
|
4
7
|
import type { ScalarOptions } from "../reference/scalar.ts";
|
|
5
8
|
import type { ResolvedReferenceAdapter } from "../reference/schema.ts";
|
|
6
9
|
|
|
@@ -28,8 +31,8 @@ export type BlumeReferenceKind = Exclude<ReferenceKind, "scalar">;
|
|
|
28
31
|
|
|
29
32
|
/** Per-adapter display options for the Blume renderer. */
|
|
30
33
|
export interface ReferenceDisplay {
|
|
31
|
-
/** Code-sample languages shown per operation. */
|
|
32
|
-
codeSamples: string[];
|
|
34
|
+
/** Code-sample languages shown per operation; `false` for none. */
|
|
35
|
+
codeSamples: string[] | false;
|
|
33
36
|
/** Whether nested schema rows start expanded. */
|
|
34
37
|
expandSchemas: boolean;
|
|
35
38
|
/**
|
|
@@ -54,6 +57,12 @@ export interface ReferenceSource {
|
|
|
54
57
|
*/
|
|
55
58
|
basePath: string;
|
|
56
59
|
label: string;
|
|
60
|
+
/**
|
|
61
|
+
* The source's own `label`, when it sets one: it names the sidebar group
|
|
62
|
+
* of the source's route. An unlabeled source's group keeps the name its
|
|
63
|
+
* route gives it.
|
|
64
|
+
*/
|
|
65
|
+
groupLabel?: string;
|
|
57
66
|
/** Whether generated pages are included in llms.txt/llms-full.txt. */
|
|
58
67
|
includeInLlms: boolean;
|
|
59
68
|
/** Whether generated pages are included in site search. */
|
|
@@ -67,11 +76,18 @@ export interface ReferenceSource {
|
|
|
67
76
|
seoDescriptionSuffix: boolean;
|
|
68
77
|
/** Local path or `http(s)` URL, verbatim from config. */
|
|
69
78
|
spec: string;
|
|
79
|
+
/**
|
|
80
|
+
* OpenAPI Overlay documents applied to `spec` in order (`openapi()` and
|
|
81
|
+
* `scalar()` only).
|
|
82
|
+
*/
|
|
83
|
+
overlays?: string[];
|
|
70
84
|
/**
|
|
71
85
|
* URL of the live GraphQL endpoint the playground and code samples target
|
|
72
86
|
* (GraphQL only — a schema, unlike an OpenAPI document, names no server).
|
|
73
87
|
*/
|
|
74
88
|
endpoint?: string;
|
|
89
|
+
/** How the GraphQL endpoint authenticates (GraphQL only). */
|
|
90
|
+
auth?: GraphqlAuthOptions;
|
|
75
91
|
/**
|
|
76
92
|
* The `scalar()` adapter's own options (`scalar` kind only): `theme` plus
|
|
77
93
|
* any Scalar config forwarded verbatim to `<ScalarComponent>`, which takes
|
|
@@ -176,6 +192,7 @@ const scalarOptionsOf = (
|
|
|
176
192
|
|
|
177
193
|
/** A source row with every kind's fields reconciled onto one shape. */
|
|
178
194
|
interface SourceRow {
|
|
195
|
+
auth?: GraphqlAuthOptions;
|
|
179
196
|
endpoint?: string;
|
|
180
197
|
includeInLlms: boolean;
|
|
181
198
|
includeInSearch: boolean;
|
|
@@ -184,13 +201,14 @@ interface SourceRow {
|
|
|
184
201
|
route?: string;
|
|
185
202
|
seoDescriptionSuffix: boolean;
|
|
186
203
|
spec: string;
|
|
204
|
+
overlays?: string[];
|
|
187
205
|
}
|
|
188
206
|
|
|
189
207
|
/**
|
|
190
208
|
* One row per source, with the kind-specific fields already reconciled: a
|
|
191
|
-
* GraphQL source's `endpoint`
|
|
192
|
-
* common single-schema case pairs
|
|
193
|
-
*
|
|
209
|
+
* GraphQL source's `endpoint` and `auth` fall back to the adapter-wide
|
|
210
|
+
* defaults (the common single-schema case pairs them with the `spec`
|
|
211
|
+
* shorthand); the other kinds have neither. A Scalar source carries only `noindex` of
|
|
194
212
|
* the per-source controls — the embed sits outside search and llms.txt, so
|
|
195
213
|
* the other two read as off.
|
|
196
214
|
*/
|
|
@@ -198,6 +216,7 @@ const sourceRowsOf = (adapter: ResolvedReferenceAdapter): SourceRow[] => {
|
|
|
198
216
|
if (adapter.kind === "graphql") {
|
|
199
217
|
return adapter.options.sources.map((source) => ({
|
|
200
218
|
...source,
|
|
219
|
+
auth: source.auth ?? adapter.options.auth,
|
|
201
220
|
endpoint: source.endpoint ?? adapter.options.endpoint,
|
|
202
221
|
}));
|
|
203
222
|
}
|
|
@@ -252,9 +271,18 @@ const referencesFor = (
|
|
|
252
271
|
if (adapter.kind === "scalar") {
|
|
253
272
|
reference.scalar = scalarOptionsOf(adapter.options);
|
|
254
273
|
}
|
|
274
|
+
if (source.label !== undefined) {
|
|
275
|
+
reference.groupLabel = source.label;
|
|
276
|
+
}
|
|
255
277
|
if (source.endpoint !== undefined) {
|
|
256
278
|
reference.endpoint = source.endpoint;
|
|
257
279
|
}
|
|
280
|
+
if (source.auth !== undefined) {
|
|
281
|
+
reference.auth = source.auth;
|
|
282
|
+
}
|
|
283
|
+
if (source.overlays !== undefined) {
|
|
284
|
+
reference.overlays = source.overlays;
|
|
285
|
+
}
|
|
258
286
|
return reference;
|
|
259
287
|
});
|
|
260
288
|
};
|
|
@@ -339,6 +367,27 @@ export const blumeReferences = (
|
|
|
339
367
|
return result;
|
|
340
368
|
};
|
|
341
369
|
|
|
370
|
+
/** A spec or overlay the parser fetches rather than reads from disk. */
|
|
371
|
+
const REMOTE_SPEC = /^https?:\/\//u;
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* The local files every reference reads, as absolute paths: each spec and
|
|
375
|
+
* overlay that isn't an `http(s)` URL, resolved from the project root the way
|
|
376
|
+
* the parser resolves them. `blume dev` watches these, so an edit to a spec
|
|
377
|
+
* regenerates its reference like an edit to a page does.
|
|
378
|
+
*/
|
|
379
|
+
export const referenceSpecFiles = (
|
|
380
|
+
config: ResolvedConfig,
|
|
381
|
+
root: string
|
|
382
|
+
): string[] => [
|
|
383
|
+
...new Set(
|
|
384
|
+
resolveReferences(config)
|
|
385
|
+
.flatMap((ref) => [ref.spec, ...(ref.overlays ?? [])])
|
|
386
|
+
.filter((path) => !REMOTE_SPEC.test(path))
|
|
387
|
+
.map((path) => (isAbsolute(path) ? path : join(root, path)))
|
|
388
|
+
),
|
|
389
|
+
];
|
|
390
|
+
|
|
342
391
|
/** Whether any reference is Scalar-rendered (gates the Scalar pages). */
|
|
343
392
|
export const hasScalarReferences = (config: ResolvedConfig): boolean =>
|
|
344
393
|
resolveReferences(config).some((ref) => ref.kind === "scalar");
|
|
@@ -363,11 +412,18 @@ export const builtinProxyReferences = (
|
|
|
363
412
|
ref.display.playground.proxy === true
|
|
364
413
|
);
|
|
365
414
|
|
|
415
|
+
/**
|
|
416
|
+
* Whether hand-written endpoint pages (`api` frontmatter) send their Try it
|
|
417
|
+
* requests through the built-in proxy: `api.playground.proxy: true`.
|
|
418
|
+
*/
|
|
419
|
+
export const apiPagesUseBuiltinProxy = (config: ResolvedConfig): boolean =>
|
|
420
|
+
config.api.playground.enabled && config.api.playground.proxy === true;
|
|
421
|
+
|
|
366
422
|
/**
|
|
367
423
|
* Whether the built-in playground CORS proxy endpoint (`/_api-proxy`) must be
|
|
368
424
|
* generated: some Blume-rendered reference's playground opted into it with
|
|
369
|
-
* `proxy: true
|
|
370
|
-
* two can never disagree.
|
|
425
|
+
* `proxy: true`, or the hand-written endpoint pages' did. Shared by the server
|
|
426
|
+
* feature gate and the generator so the two can never disagree.
|
|
371
427
|
*/
|
|
372
428
|
export const needsPlaygroundProxy = (config: ResolvedConfig): boolean =>
|
|
373
|
-
builtinProxyReferences(config).length > 0;
|
|
429
|
+
builtinProxyReferences(config).length > 0 || apiPagesUseBuiltinProxy(config);
|
|
@@ -270,7 +270,8 @@ const operationDescription = (
|
|
|
270
270
|
// method (see `extractGraphqlOperations`).
|
|
271
271
|
subject = `${operation.path} ${GRAPHQL_MEMBER_PHRASES[operation.method as GraphqlMember]}`;
|
|
272
272
|
} else {
|
|
273
|
-
|
|
273
|
+
// A webhook is a request the API sends, named rather than pathed.
|
|
274
|
+
subject = `${operation.method.toUpperCase()} ${operation.path} ${operation.webhook ? "webhook" : "endpoint"}`;
|
|
274
275
|
}
|
|
275
276
|
const suffix = `Reference for the ${subject} in the ${apiPhrase(spec)}.`;
|
|
276
277
|
// Room for the joining space and the period `asSentence` may add, so a
|
|
@@ -348,6 +349,9 @@ export const operationMdx = (
|
|
|
348
349
|
sidebar.badge = method;
|
|
349
350
|
}
|
|
350
351
|
const tags = graphql ? [operation.tag] : [operation.tag, method];
|
|
352
|
+
if (operation.webhook) {
|
|
353
|
+
tags.push("Webhook");
|
|
354
|
+
}
|
|
351
355
|
return {
|
|
352
356
|
body: withDescription(
|
|
353
357
|
description,
|