blume 2.1.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +110 -0
- 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-43zcf4gz.js → chunk-0pmb4tr4.js} +541 -368
- package/dist/cli/chunk-0pmb4tr4.js.map +35 -0
- package/dist/cli/{chunk-9geymqns.js → chunk-0w6hs479.js} +15 -15
- package/dist/cli/{chunk-xkz5xbtv.js → chunk-124fvmzq.js} +2802 -1422
- package/dist/cli/chunk-124fvmzq.js.map +220 -0
- package/dist/cli/chunk-150jk7km.js +52 -0
- package/dist/cli/chunk-150jk7km.js.map +10 -0
- package/dist/cli/{chunk-y4ykbark.js → chunk-1f882900.js} +2 -2
- package/dist/cli/{chunk-5ffywsmb.js → chunk-297ajdcv.js} +8 -6
- package/dist/cli/{chunk-5ffywsmb.js.map → chunk-297ajdcv.js.map} +3 -3
- package/dist/cli/{chunk-h2a48yhd.js → chunk-32khwcb6.js} +120 -16
- package/dist/cli/{chunk-h2a48yhd.js.map → chunk-32khwcb6.js.map} +10 -10
- package/dist/cli/{chunk-5cg2rzgf.js → chunk-36bxs9c7.js} +20 -49
- package/dist/cli/{chunk-5cg2rzgf.js.map → chunk-36bxs9c7.js.map} +4 -5
- package/dist/cli/{chunk-py62fewh.js → chunk-53jqw8z0.js} +3 -3
- package/dist/cli/{chunk-5wj2qwn2.js → chunk-58bt3hag.js} +4 -4
- package/dist/cli/{chunk-e7vvk5ya.js → chunk-5cmts6dv.js} +3 -3
- package/dist/cli/{chunk-y5h4r2y0.js → chunk-60hz265r.js} +15 -5
- package/dist/cli/chunk-60hz265r.js.map +10 -0
- package/dist/cli/chunk-74wfhv79.js +65 -0
- package/dist/cli/chunk-74wfhv79.js.map +10 -0
- package/dist/cli/{chunk-g2z9x01v.js → chunk-9qzgg6mj.js} +3 -3
- package/dist/cli/{chunk-q3wxxq39.js → chunk-a57yh0h9.js} +5 -5
- package/dist/cli/{chunk-713mngdq.js → chunk-ave1wcbr.js} +76 -10
- package/dist/cli/chunk-ave1wcbr.js.map +14 -0
- package/dist/cli/{chunk-2n4ps1b3.js → chunk-bqxaqn5p.js} +40 -22
- package/dist/cli/chunk-bqxaqn5p.js.map +15 -0
- package/dist/cli/{chunk-jnwj5kjj.js → chunk-bxwhtvw8.js} +20 -7
- package/dist/cli/{chunk-jnwj5kjj.js.map → chunk-bxwhtvw8.js.map} +3 -3
- package/dist/cli/chunk-ckrcm08h.js +324 -0
- package/dist/cli/chunk-ckrcm08h.js.map +14 -0
- package/dist/cli/{chunk-2f3ndkpw.js → chunk-desvm72z.js} +3 -3
- package/dist/cli/{chunk-gp84za0h.js → chunk-dhwtqnnd.js} +2 -2
- package/dist/cli/{chunk-4h8z9vv5.js → chunk-dpy8qdjf.js} +93 -47
- package/dist/cli/chunk-dpy8qdjf.js.map +17 -0
- package/dist/cli/{chunk-2f7n4qzt.js → chunk-dqhg54mr.js} +1 -1
- package/dist/cli/{chunk-0gz36akr.js → chunk-dv2z0rzf.js} +21 -5
- package/dist/cli/chunk-dv2z0rzf.js.map +12 -0
- package/dist/cli/{chunk-cm89scdv.js → chunk-es8h0v3j.js} +9 -11
- package/dist/cli/{chunk-cm89scdv.js.map → chunk-es8h0v3j.js.map} +3 -3
- package/dist/cli/{chunk-zhvd6adm.js → chunk-gfc5fqvf.js} +14 -14
- package/dist/cli/{chunk-nd1821sk.js → chunk-gxtg6ed2.js} +33 -19
- package/dist/cli/chunk-gxtg6ed2.js.map +10 -0
- package/dist/cli/{chunk-p804f3pe.js → chunk-hvcxng5f.js} +6 -6
- package/dist/cli/{chunk-ta27feev.js → chunk-j1x92mx9.js} +21 -2
- package/dist/cli/chunk-j1x92mx9.js.map +10 -0
- package/dist/cli/{chunk-rekqz4qg.js → chunk-k3gr1nm9.js} +19 -16
- package/dist/cli/chunk-k3gr1nm9.js.map +10 -0
- package/dist/cli/{chunk-1n228xqb.js → chunk-kdpzw38a.js} +2 -2
- package/dist/cli/{chunk-cy5bm0j0.js → chunk-ms9z66nz.js} +2 -2
- package/dist/cli/{chunk-cy5bm0j0.js.map → chunk-ms9z66nz.js.map} +2 -2
- package/dist/cli/{chunk-zf748avv.js → chunk-nbyvgnnm.js} +193 -286
- package/dist/cli/chunk-nbyvgnnm.js.map +36 -0
- package/dist/cli/{chunk-6bm0xpgd.js → chunk-s0bdnc7v.js} +2 -2
- package/dist/cli/{chunk-yxmk4pec.js → chunk-sc93apfs.js} +17 -16
- package/dist/cli/{chunk-yxmk4pec.js.map → chunk-sc93apfs.js.map} +3 -3
- package/dist/cli/{chunk-cmtcnh9f.js → chunk-tfycddbt.js} +2 -2
- package/dist/cli/{chunk-9xr4dgee.js → chunk-twy7psdz.js} +29 -16
- package/dist/cli/chunk-twy7psdz.js.map +10 -0
- package/dist/cli/{chunk-ntv4qrt7.js → chunk-y4msrwm9.js} +15 -15
- package/dist/cli/{chunk-yj17vs39.js → chunk-ydp3065p.js} +5 -5
- package/dist/cli/index.js +24 -19
- package/dist/cli/index.js.map +3 -3
- package/dist/types/ai/ask-context.d.ts +6 -2
- package/dist/types/ai/ask.d.ts +24 -5
- package/dist/types/ai/component-markdown.d.ts +2 -0
- package/dist/types/ai/openapi-components.d.ts +4 -1
- package/dist/types/analytics/clics.d.ts +37 -0
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/schema.d.ts +18 -0
- package/dist/types/astro/integration.d.ts +11 -4
- package/dist/types/astro/markdown-negotiation.d.ts +3 -0
- package/dist/types/astro/pages.d.ts +10 -0
- package/dist/types/cli/init/scaffold.d.ts +1 -1
- package/dist/types/components/content/api-field.d.ts +4 -1
- package/dist/types/components/content/api-page.d.ts +6 -1
- package/dist/types/components/openapi/code-samples.d.ts +29 -0
- package/dist/types/components/openapi/helpers.d.ts +22 -1
- package/dist/types/components/openapi/security.d.ts +10 -0
- package/dist/types/components/openapi/snippets.d.ts +60 -0
- package/dist/types/core/changelog-index.d.ts +8 -0
- package/dist/types/core/config-input.d.ts +37 -6
- package/dist/types/core/data.d.ts +4 -0
- package/dist/types/core/i18n-ui.d.ts +2 -0
- package/dist/types/core/links.d.ts +8 -0
- package/dist/types/core/powered-by.d.ts +12 -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 +11 -3
- package/dist/types/core/schema.d.ts +228 -3
- 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/lower.d.ts +10 -2
- package/dist/types/core/sources/normalize.d.ts +20 -1
- package/dist/types/core/sources/notion.d.ts +8 -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 +17 -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/cloudflare-negotiation.d.ts +5 -2
- package/dist/types/deploy/node-headers.d.ts +12 -4
- package/dist/types/deploy/platforms/cloudflare.d.ts +10 -7
- 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 +21 -2
- package/dist/types/deploy/redirects.d.ts +17 -1
- package/dist/types/deploy/sitemap.d.ts +2 -1
- package/dist/types/deploy/vercel-negotiation.d.ts +44 -21
- package/dist/types/narration/build.d.ts +34 -12
- package/dist/types/narration/provider.d.ts +96 -8
- 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 +15 -4
- package/dist/types/openapi/parse.d.ts +3 -0
- package/dist/types/openapi/references.d.ts +16 -0
- package/dist/types/openapi/sentence.d.ts +11 -1
- package/dist/types/ratelimit/index.d.ts +1 -1
- package/dist/types/ratelimit/schema.d.ts +8 -0
- package/dist/types/ratelimit/upstash.d.ts +39 -14
- package/dist/types/reference/graphql.d.ts +76 -1
- package/dist/types/reference/index.d.ts +1 -1
- package/dist/types/reference/openapi.d.ts +2 -2
- package/dist/types/reference/options.d.ts +37 -1
- package/dist/types/reference/schema.d.ts +84 -0
- 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/orama-index.d.ts +9 -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/jsonld.d.ts +11 -6
- package/dist/types/sources/contentful.d.ts +16 -0
- package/dist/types/sources/github-releases.d.ts +8 -1
- package/dist/types/sources/notion.d.ts +8 -0
- package/dist/types/sources/payload.d.ts +2 -0
- package/dist/types/sources/registry.d.ts +63 -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 +59 -13
- package/docs/03-upgrading.mdx +2 -1
- package/docs/04-migrating.mdx +9 -9
- package/docs/08-faq.mdx +12 -12
- package/docs/advanced/changelog.mdx +30 -2
- package/docs/advanced/custom-pages.mdx +1 -1
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +30 -7
- package/docs/cli/doctor.mdx +6 -2
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/translate.mdx +1 -0
- package/docs/cli/validate.mdx +4 -3
- package/docs/configuration/analytics.mdx +19 -1
- package/docs/configuration/assistant.mdx +6 -2
- package/docs/configuration/customization.mdx +4 -2
- package/docs/configuration/export.mdx +5 -3
- package/docs/configuration/index.mdx +4 -2
- package/docs/configuration/narration.mdx +43 -6
- package/docs/configuration/rate-limiting.mdx +23 -2
- package/docs/configuration/search.mdx +37 -14
- package/docs/content/components.mdx +2 -2
- package/docs/content/frontmatter.mdx +5 -3
- package/docs/content/i18n.mdx +2 -2
- package/docs/content/includes.mdx +1 -1
- package/docs/content/navigation.mdx +8 -6
- package/docs/content/sources/contentful.mdx +9 -4
- package/docs/content/sources/custom.mdx +7 -3
- package/docs/content/sources/github-releases.mdx +12 -2
- package/docs/content/sources/index.mdx +3 -3
- package/docs/content/sources/notion.mdx +17 -2
- package/docs/content/sources/obsidian.mdx +3 -1
- package/docs/content/sources/payload.mdx +5 -2
- package/docs/content/sources/remote-mdx.mdx +6 -0
- package/docs/content/sources/sanity.mdx +4 -2
- package/docs/content/sources/strapi.mdx +5 -2
- package/docs/content/syntax.mdx +2 -2
- package/docs/discoverability/agent-discovery.mdx +1 -1
- package/docs/discoverability/index.mdx +1 -1
- package/docs/discoverability/json-api.mdx +2 -0
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/markdown.mdx +3 -1
- package/docs/discoverability/mcp.mdx +6 -0
- package/docs/discoverability/sitemap-and-robots.mdx +1 -1
- package/docs/discoverability/structured-data.mdx +8 -6
- package/docs/references/api-pages.mdx +1 -1
- package/docs/references/asyncapi.mdx +5 -1
- package/docs/references/graphql.mdx +15 -1
- package/docs/references/openapi.mdx +64 -8
- package/package.json +9 -9
- package/skills/blume/SKILL.md +1 -1
- package/skills/blume-migrate/SKILL.md +2 -2
- package/skills/blume-migrate/assets/{oxfmt@0.67.0.patch → oxfmt@0.71.0.patch} +7 -7
- package/skills/blume-migrate/references/docusaurus.md +4 -4
- package/skills/blume-migrate/references/fumadocs.md +17 -13
- package/skills/blume-migrate/references/monorepo.md +5 -5
- package/skills/blume-migrate/references/nextra.md +8 -5
- package/skills/blume-migrate/references/starlight.md +9 -7
- package/src/ai/ask-context.ts +33 -3
- package/src/ai/ask-limits.ts +13 -0
- package/src/ai/ask.ts +24 -6
- package/src/ai/changelog-markdown.ts +11 -6
- package/src/ai/component-markdown.ts +1 -1
- package/src/ai/cors.ts +12 -3
- package/src/ai/mcp/query.ts +14 -6
- package/src/ai/openapi-components.ts +28 -4
- package/src/ai/relative-links.ts +4 -38
- package/src/analytics/clics.ts +58 -0
- package/src/analytics/head.ts +5 -0
- package/src/analytics/index.ts +2 -0
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +91 -56
- package/src/astro/integration.ts +72 -22
- package/src/astro/markdown-negotiation.ts +3 -0
- package/src/astro/module-types.ts +3 -1
- package/src/astro/pages.ts +23 -0
- package/src/astro/render-deps.ts +10 -5
- package/src/astro/runtime-deps.ts +23 -2
- package/src/astro/templates.ts +129 -81
- package/src/audit/catalog.ts +19 -3
- package/src/audit/checks/links.ts +14 -1
- 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/run.ts +3 -0
- package/src/audit/types.ts +2 -0
- package/src/audit/url.ts +14 -5
- package/src/blume-modules.d.ts +5 -1
- package/src/cli/args.ts +51 -0
- package/src/cli/build-failure.ts +23 -0
- package/src/cli/commands/audit.ts +10 -1
- package/src/cli/commands/dev.ts +18 -2
- package/src/cli/commands/doctor.ts +45 -12
- package/src/cli/commands/eval.ts +36 -4
- package/src/cli/commands/init.ts +6 -4
- package/src/cli/commands/validate.ts +10 -1
- package/src/cli/init/scaffold.ts +9 -6
- package/src/cli/prepare.ts +6 -3
- package/src/cli/required-secrets.ts +3 -2
- package/src/components/content/ApiPlayground.astro +6 -2
- package/src/components/content/api-field.ts +4 -1
- package/src/components/content/api-page.ts +31 -7
- package/src/components/content/mermaid-element.ts +15 -1
- package/src/components/content/view-switcher.ts +7 -4
- package/src/components/islands/hooks.ts +27 -1
- package/src/components/layout/NavTree.astro +49 -5
- package/src/components/layout/NavTreeScript.astro +18 -0
- package/src/components/layout/PageActions.astro +139 -24
- package/src/components/layout/PageLayout.astro +13 -3
- package/src/components/layout/RootLayout.astro +27 -14
- package/src/components/layout/Search.astro +17 -3
- package/src/components/layout/TableOfContents.astro +24 -17
- package/src/components/layout/analytics-client.ts +8 -8
- package/src/components/layout/head-scripts.ts +6 -1
- package/src/components/layout/search/algolia.ts +10 -1
- package/src/components/layout/search/analytics.ts +42 -14
- package/src/components/layout/search/endpoint.ts +48 -5
- package/src/components/layout/search/pagefind.ts +114 -5
- package/src/components/layout/search/types.ts +12 -0
- package/src/components/layout/search/typesense.ts +18 -6
- 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 +24 -1
- package/src/components/openapi/ParametersTable.astro +8 -4
- package/src/components/openapi/Playground.astro +7 -1
- package/src/components/openapi/RequestBody.astro +19 -2
- package/src/components/openapi/Responses.astro +1 -0
- package/src/components/openapi/SchemaTable.astro +15 -3
- package/src/components/openapi/async-snippets.ts +61 -5
- package/src/components/openapi/async.ts +123 -29
- 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 +77 -58
- package/src/components/openapi/playground-schema.ts +1 -1
- package/src/components/openapi/schema-tree.ts +44 -14
- package/src/components/openapi/security.ts +10 -0
- package/src/components/openapi/snippets.ts +5 -3
- package/src/components/openapi/validate-json.ts +4 -3
- package/src/components/powered-by-middleware.ts +33 -0
- package/src/core/changelog-index.ts +31 -1
- package/src/core/component-diagnostics.ts +53 -0
- package/src/core/component-overrides.ts +32 -0
- package/src/core/config-input.ts +42 -6
- package/src/core/data.ts +2 -0
- package/src/core/diagnostics.ts +5 -0
- package/src/core/i18n-ui.ts +2 -0
- package/src/core/includes.ts +1 -1
- package/src/core/links.ts +47 -17
- package/src/core/powered-by.ts +12 -0
- package/src/core/probe.ts +26 -6
- package/src/core/project-graph.ts +59 -18
- package/src/core/redirect-patterns.ts +36 -7
- package/src/core/schema.ts +26 -6
- 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/lower.ts +19 -3
- package/src/core/sources/mdx-remote.ts +62 -10
- package/src/core/sources/normalize.ts +227 -41
- package/src/core/sources/notion.ts +34 -10
- package/src/core/sources/obsidian.ts +16 -3
- package/src/core/sources/payload.ts +38 -15
- 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 +18 -0
- package/src/core/ui-packs/ar.ts +1 -0
- package/src/core/ui-packs/bg.ts +1 -0
- package/src/core/ui-packs/bn.ts +1 -0
- package/src/core/ui-packs/ca.ts +1 -0
- package/src/core/ui-packs/cs.ts +1 -0
- package/src/core/ui-packs/da.ts +1 -0
- package/src/core/ui-packs/de.ts +1 -0
- package/src/core/ui-packs/el.ts +1 -0
- package/src/core/ui-packs/es.ts +1 -0
- package/src/core/ui-packs/fa.ts +1 -0
- package/src/core/ui-packs/fi.ts +1 -0
- package/src/core/ui-packs/fr.ts +1 -0
- package/src/core/ui-packs/he.ts +1 -0
- package/src/core/ui-packs/hi.ts +1 -0
- package/src/core/ui-packs/hr.ts +1 -0
- package/src/core/ui-packs/hu.ts +1 -0
- package/src/core/ui-packs/id.ts +1 -0
- package/src/core/ui-packs/it.ts +1 -0
- package/src/core/ui-packs/ja.ts +1 -0
- package/src/core/ui-packs/ko.ts +1 -0
- package/src/core/ui-packs/nl.ts +1 -0
- package/src/core/ui-packs/no.ts +1 -0
- package/src/core/ui-packs/pl.ts +1 -0
- package/src/core/ui-packs/pt-br.ts +1 -0
- package/src/core/ui-packs/pt.ts +1 -0
- package/src/core/ui-packs/ro.ts +1 -0
- package/src/core/ui-packs/ru.ts +1 -0
- package/src/core/ui-packs/sk.ts +1 -0
- package/src/core/ui-packs/sr.ts +1 -0
- package/src/core/ui-packs/sv.ts +1 -0
- package/src/core/ui-packs/th.ts +1 -0
- package/src/core/ui-packs/tr.ts +1 -0
- package/src/core/ui-packs/uk.ts +1 -0
- package/src/core/ui-packs/vi.ts +1 -0
- package/src/core/ui-packs/zh-tw.ts +1 -0
- package/src/core/ui-packs/zh.ts +1 -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 +2 -1
- package/src/deploy/cloudflare-negotiation.ts +36 -7
- package/src/deploy/headers.ts +15 -1
- package/src/deploy/node-headers.ts +32 -20
- package/src/deploy/platforms/cloudflare.ts +14 -9
- package/src/deploy/platforms/netlify.ts +2 -1
- package/src/deploy/platforms/node.ts +12 -2
- package/src/deploy/platforms/types.ts +21 -7
- package/src/deploy/platforms/vercel.ts +115 -17
- package/src/deploy/redirects.ts +66 -6
- package/src/deploy/rss.ts +3 -1
- package/src/deploy/sitemap.ts +39 -5
- package/src/deploy/vercel-negotiation.ts +325 -103
- 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/base-links.ts +15 -14
- package/src/markdown/package-commands.ts +9 -8
- package/src/markdown/relative-links.ts +3 -2
- package/src/narration/build.ts +218 -40
- package/src/narration/provider.ts +89 -9
- 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 +15 -3
- package/src/openapi/parse.ts +127 -2
- package/src/openapi/references.ts +43 -3
- package/src/openapi/render-mdx.ts +68 -8
- package/src/openapi/sentence.ts +29 -2
- package/src/openapi/source.ts +39 -14
- package/src/ratelimit/index.ts +1 -1
- package/src/ratelimit/runtime.ts +37 -19
- package/src/ratelimit/upstash.ts +40 -10
- package/src/reference/graphql.ts +15 -1
- package/src/reference/index.ts +1 -0
- package/src/reference/openapi.ts +2 -2
- package/src/reference/options.ts +29 -1
- package/src/registry/eject.ts +8 -2
- 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/orama-index.ts +163 -31
- package/src/search/source-pages.ts +29 -0
- package/src/search/sync/algolia.ts +99 -9
- package/src/search/sync/index.ts +52 -13
- package/src/search/sync/typesense.ts +72 -27
- package/src/seo/jsonld.ts +38 -20
- package/src/sources/contentful.ts +12 -0
- package/src/sources/github-releases.ts +7 -1
- package/src/sources/notion.ts +7 -0
- package/src/sources/shared.ts +3 -0
- package/src/theme/color.ts +9 -10
- package/src/theme/entry.ts +43 -6
- package/src/translate/validate.ts +23 -1
- package/dist/cli/chunk-0gz36akr.js.map +0 -12
- package/dist/cli/chunk-2n4ps1b3.js.map +0 -15
- package/dist/cli/chunk-43zcf4gz.js.map +0 -36
- package/dist/cli/chunk-4ejxbzee.js +0 -39
- package/dist/cli/chunk-4ejxbzee.js.map +0 -10
- package/dist/cli/chunk-4h8z9vv5.js.map +0 -16
- package/dist/cli/chunk-713mngdq.js.map +0 -14
- package/dist/cli/chunk-9xr4dgee.js.map +0 -10
- package/dist/cli/chunk-amrb6hgh.js +0 -145
- package/dist/cli/chunk-amrb6hgh.js.map +0 -11
- package/dist/cli/chunk-nd1821sk.js.map +0 -10
- package/dist/cli/chunk-rekqz4qg.js.map +0 -10
- package/dist/cli/chunk-ta27feev.js.map +0 -10
- package/dist/cli/chunk-xkz5xbtv.js.map +0 -213
- package/dist/cli/chunk-y5h4r2y0.js.map +0 -10
- package/dist/cli/chunk-zf748avv.js.map +0 -37
- /package/dist/cli/{chunk-9geymqns.js.map → chunk-0w6hs479.js.map} +0 -0
- /package/dist/cli/{chunk-y4ykbark.js.map → chunk-1f882900.js.map} +0 -0
- /package/dist/cli/{chunk-py62fewh.js.map → chunk-53jqw8z0.js.map} +0 -0
- /package/dist/cli/{chunk-5wj2qwn2.js.map → chunk-58bt3hag.js.map} +0 -0
- /package/dist/cli/{chunk-e7vvk5ya.js.map → chunk-5cmts6dv.js.map} +0 -0
- /package/dist/cli/{chunk-g2z9x01v.js.map → chunk-9qzgg6mj.js.map} +0 -0
- /package/dist/cli/{chunk-q3wxxq39.js.map → chunk-a57yh0h9.js.map} +0 -0
- /package/dist/cli/{chunk-2f3ndkpw.js.map → chunk-desvm72z.js.map} +0 -0
- /package/dist/cli/{chunk-gp84za0h.js.map → chunk-dhwtqnnd.js.map} +0 -0
- /package/dist/cli/{chunk-2f7n4qzt.js.map → chunk-dqhg54mr.js.map} +0 -0
- /package/dist/cli/{chunk-zhvd6adm.js.map → chunk-gfc5fqvf.js.map} +0 -0
- /package/dist/cli/{chunk-p804f3pe.js.map → chunk-hvcxng5f.js.map} +0 -0
- /package/dist/cli/{chunk-1n228xqb.js.map → chunk-kdpzw38a.js.map} +0 -0
- /package/dist/cli/{chunk-6bm0xpgd.js.map → chunk-s0bdnc7v.js.map} +0 -0
- /package/dist/cli/{chunk-cmtcnh9f.js.map → chunk-tfycddbt.js.map} +0 -0
- /package/dist/cli/{chunk-ntv4qrt7.js.map → chunk-y4msrwm9.js.map} +0 -0
- /package/dist/cli/{chunk-yj17vs39.js.map → chunk-ydp3065p.js.map} +0 -0
|
@@ -41,15 +41,19 @@ export interface MessageServerOption {
|
|
|
41
41
|
/** `protocol://host+pathname` — what the reader picks between. */
|
|
42
42
|
label: string;
|
|
43
43
|
/**
|
|
44
|
-
* The spec server with its host/pathname variables at their defaults
|
|
45
|
-
* snippet builders read
|
|
44
|
+
* The spec server with its host/pathname variables at their defaults and
|
|
45
|
+
* its `security` refs resolved; the snippet builders read
|
|
46
|
+
* host/pathname/protocol/security.
|
|
46
47
|
*/
|
|
47
48
|
server: AsyncApiServerObject;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
export interface MessageModel {
|
|
51
52
|
action: AsyncApiAction;
|
|
52
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Channel address with `{param}` templates intact, e.g. `user/{id}/signedup`
|
|
55
|
+
* — or the Kafka binding's `topic` when the channel names one.
|
|
56
|
+
*/
|
|
53
57
|
address: string;
|
|
54
58
|
/**
|
|
55
59
|
* Whether the panel offers a live connection. Only WebSocket bindings can be
|
|
@@ -57,6 +61,8 @@ export interface MessageModel {
|
|
|
57
61
|
* CLI samples rather than faked connectivity.
|
|
58
62
|
*/
|
|
59
63
|
connectable: boolean;
|
|
64
|
+
/** Example Kafka message key, sampled from the first message's binding. */
|
|
65
|
+
key?: string;
|
|
60
66
|
params: MessageParam[];
|
|
61
67
|
payload: MessagePayload;
|
|
62
68
|
/** Normalized binding key (`ws`, `kafka`, `mqtt`, …) when the spec implies one. */
|
|
@@ -149,7 +155,7 @@ export const buildMessage = (
|
|
|
149
155
|
} catch {
|
|
150
156
|
payload = undefined;
|
|
151
157
|
}
|
|
152
|
-
|
|
158
|
+
const sample: MessageSample = {
|
|
153
159
|
action: model.action,
|
|
154
160
|
address: model.address.replaceAll(PARAM_TEMPLATE, (template, name) => {
|
|
155
161
|
const value = values.params[String(name)] ?? "";
|
|
@@ -158,6 +164,10 @@ export const buildMessage = (
|
|
|
158
164
|
payload,
|
|
159
165
|
server: custom === "" ? picked?.server : customServer(custom),
|
|
160
166
|
};
|
|
167
|
+
if (model.key !== undefined) {
|
|
168
|
+
sample.key = model.key;
|
|
169
|
+
}
|
|
170
|
+
return sample;
|
|
161
171
|
};
|
|
162
172
|
|
|
163
173
|
/**
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
declaredExample,
|
|
4
4
|
exampleValue,
|
|
5
5
|
objectProperties,
|
|
6
|
+
parameterDescription,
|
|
6
7
|
resolveSchema,
|
|
7
8
|
toJson,
|
|
8
9
|
} from "./helpers.ts";
|
|
@@ -142,7 +143,7 @@ const modelParams = (
|
|
|
142
143
|
const required = where === "path" ? true : param.required === true;
|
|
143
144
|
const schema = resolveSchema(schemas, param.schema);
|
|
144
145
|
params.push({
|
|
145
|
-
description: param
|
|
146
|
+
description: parameterDescription(param, schemas),
|
|
146
147
|
enum: schema.enum?.map(String),
|
|
147
148
|
in: where,
|
|
148
149
|
name: param.name,
|
|
@@ -330,6 +331,19 @@ const authInput = (
|
|
|
330
331
|
}
|
|
331
332
|
};
|
|
332
333
|
|
|
334
|
+
/**
|
|
335
|
+
* The playground's credential inputs for an operation's security: the first
|
|
336
|
+
* alternative only — the spec's preferred way to authorize, matching what the
|
|
337
|
+
* static samples always showed.
|
|
338
|
+
*/
|
|
339
|
+
export const playgroundAuth = (
|
|
340
|
+
security: OperationSecurity
|
|
341
|
+
): PlaygroundAuthInput[] =>
|
|
342
|
+
(security.alternatives[0] ?? []).flatMap((resolved) => {
|
|
343
|
+
const input = authInput(resolved);
|
|
344
|
+
return input ? [input] : [];
|
|
345
|
+
});
|
|
346
|
+
|
|
333
347
|
/** Derive the playground request model for one operation, at build time. */
|
|
334
348
|
export const operationModel = (args: {
|
|
335
349
|
method: string;
|
|
@@ -344,12 +358,7 @@ export const operationModel = (args: {
|
|
|
344
358
|
components?: ComponentsLike;
|
|
345
359
|
security: OperationSecurity;
|
|
346
360
|
}): PlaygroundModel => ({
|
|
347
|
-
|
|
348
|
-
// what the static samples always showed.
|
|
349
|
-
auth: (args.security.alternatives[0] ?? []).flatMap((resolved) => {
|
|
350
|
-
const input = authInput(resolved);
|
|
351
|
-
return input ? [input] : [];
|
|
352
|
-
}),
|
|
361
|
+
auth: playgroundAuth(args.security),
|
|
353
362
|
authOptional: args.security.optional,
|
|
354
363
|
body: modelBody(args.requestBody, args.schemas, args.components),
|
|
355
364
|
method: args.method.toUpperCase(),
|
|
@@ -26,16 +26,34 @@ import { fetchRefusesMethod, sampleLanguages } from "./snippets.ts";
|
|
|
26
26
|
import type { RequestSample } from "./snippets.ts";
|
|
27
27
|
import { validateJson } from "./validate-json.ts";
|
|
28
28
|
|
|
29
|
+
const OPENAPI_PROXY_SETTING =
|
|
30
|
+
"`playground: { proxy: true }` on the `openapi()` reference";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The Blume config setting that turns on the proxy for a panel, keyed by the
|
|
34
|
+
* `data-proxy-config` the rendering surface stamps on it: an `openapi()` or
|
|
35
|
+
* `graphql()` reference's `playground` option, or `api.playground` for
|
|
36
|
+
* hand-written API pages.
|
|
37
|
+
*/
|
|
38
|
+
const PROXY_SETTINGS = new Map([
|
|
39
|
+
["api", "`api: { playground: { proxy: true } }`"],
|
|
40
|
+
["graphql", "`playground: { proxy: true }` on the `graphql()` reference"],
|
|
41
|
+
["openapi", OPENAPI_PROXY_SETTING],
|
|
42
|
+
]);
|
|
43
|
+
|
|
29
44
|
/**
|
|
30
45
|
* A failed fetch surfaces as a TypeError with no status — almost always the
|
|
31
46
|
* browser's CORS wall, not the API being down — so the message explains the
|
|
32
|
-
* one fix docs authors control instead of parroting "failed to fetch"
|
|
47
|
+
* one fix docs authors control instead of parroting "failed to fetch", naming
|
|
48
|
+
* the setting for the surface this panel is on and the server output the
|
|
49
|
+
* built-in proxy needs.
|
|
33
50
|
*/
|
|
34
|
-
const
|
|
51
|
+
const corsMessage = (config: string): string =>
|
|
35
52
|
"The browser blocked this request before it reached the API — the API " +
|
|
36
53
|
"likely does not allow cross-origin requests from this docs site. Set " +
|
|
37
|
-
|
|
38
|
-
"config to route playground requests through the docs server instead."
|
|
54
|
+
`${PROXY_SETTINGS.get(config) ?? OPENAPI_PROXY_SETTING} in the Blume ` +
|
|
55
|
+
"config to route playground requests through the docs server instead. " +
|
|
56
|
+
"The proxy needs server output: a host adapter in `deployment`.";
|
|
39
57
|
|
|
40
58
|
/**
|
|
41
59
|
* `Cookie` is a forbidden header name: a page cannot set it, so a credential
|
|
@@ -253,6 +271,59 @@ const line = (className: string, text: string): HTMLElement => {
|
|
|
253
271
|
return el;
|
|
254
272
|
};
|
|
255
273
|
|
|
274
|
+
/** Render one settled HTTP exchange: status + time, headers, pretty body. */
|
|
275
|
+
const renderResponse = (
|
|
276
|
+
region: HTMLElement,
|
|
277
|
+
res: Response,
|
|
278
|
+
ms: number,
|
|
279
|
+
text: string
|
|
280
|
+
): void => {
|
|
281
|
+
region.textContent = "";
|
|
282
|
+
region.append(
|
|
283
|
+
line(
|
|
284
|
+
"font-mono font-semibold text-foreground text-sm",
|
|
285
|
+
`${res.status} ${res.statusText} \u00B7 ${ms} ms`.trim()
|
|
286
|
+
)
|
|
287
|
+
);
|
|
288
|
+
const table = document.createElement("table");
|
|
289
|
+
table.className = "w-full text-start text-xs";
|
|
290
|
+
for (const [name, value] of res.headers) {
|
|
291
|
+
const row = document.createElement("tr");
|
|
292
|
+
const header = document.createElement("th");
|
|
293
|
+
header.setAttribute("scope", "row");
|
|
294
|
+
header.className = "pe-3 align-top font-medium text-muted-foreground";
|
|
295
|
+
header.textContent = name;
|
|
296
|
+
const cell = document.createElement("td");
|
|
297
|
+
cell.className = "break-all font-mono text-foreground";
|
|
298
|
+
cell.textContent = value;
|
|
299
|
+
row.append(header, cell);
|
|
300
|
+
table.append(row);
|
|
301
|
+
}
|
|
302
|
+
region.append(table);
|
|
303
|
+
const pre = document.createElement("pre");
|
|
304
|
+
pre.className =
|
|
305
|
+
"overflow-x-auto rounded-blume border border-border p-3 font-mono text-foreground text-xs";
|
|
306
|
+
const code = document.createElement("code");
|
|
307
|
+
code.textContent = prettyBody(text);
|
|
308
|
+
pre.append(code);
|
|
309
|
+
region.append(pre);
|
|
310
|
+
// At xl the panel is its own scroll region capped to the viewport, so a
|
|
311
|
+
// response appended under a tall form can land below the panel's fold
|
|
312
|
+
// where nothing brings it into view. Scroll the panel alone — "nearest",
|
|
313
|
+
// by hand — and never the document: below xl the panel does not scroll,
|
|
314
|
+
// and a document scroll would carry the form (Send, the body editor, its
|
|
315
|
+
// errors) off the top on a phone.
|
|
316
|
+
const panel = region.closest<HTMLElement>("[data-operation-panel]");
|
|
317
|
+
if (panel && panel.scrollHeight > panel.clientHeight) {
|
|
318
|
+
const box = panel.getBoundingClientRect();
|
|
319
|
+
const target = region.getBoundingClientRect();
|
|
320
|
+
const delta = Math.min(target.bottom - box.bottom, target.top - box.top);
|
|
321
|
+
if (delta > 0) {
|
|
322
|
+
panel.scrollBy({ top: delta });
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
256
327
|
/**
|
|
257
328
|
* Wire the playground inside `root` (the `<blume-playground>` element). Reads
|
|
258
329
|
* the server-rendered model JSON, keeps the request samples in sync with the
|
|
@@ -294,6 +365,7 @@ export const initPlayground = (root: HTMLElement): void => {
|
|
|
294
365
|
const response = root.querySelector<HTMLElement>("[data-response]");
|
|
295
366
|
const storageKey = root.dataset.storageKey ?? "";
|
|
296
367
|
const proxy = root.dataset.proxy ?? "";
|
|
368
|
+
const proxyConfig = root.dataset.proxyConfig ?? "";
|
|
297
369
|
|
|
298
370
|
/** True while a send is outstanding, so a second click can't race it. */
|
|
299
371
|
let sending = false;
|
|
@@ -451,59 +523,6 @@ export const initPlayground = (root: HTMLElement): void => {
|
|
|
451
523
|
}
|
|
452
524
|
};
|
|
453
525
|
|
|
454
|
-
/** Render one settled HTTP exchange: status + time, headers, pretty body. */
|
|
455
|
-
const renderResponse = (
|
|
456
|
-
region: HTMLElement,
|
|
457
|
-
res: Response,
|
|
458
|
-
ms: number,
|
|
459
|
-
text: string
|
|
460
|
-
): void => {
|
|
461
|
-
region.textContent = "";
|
|
462
|
-
region.append(
|
|
463
|
-
line(
|
|
464
|
-
"font-mono font-semibold text-foreground text-sm",
|
|
465
|
-
`${res.status} ${res.statusText} \u00B7 ${ms} ms`.trim()
|
|
466
|
-
)
|
|
467
|
-
);
|
|
468
|
-
const table = document.createElement("table");
|
|
469
|
-
table.className = "w-full text-start text-xs";
|
|
470
|
-
for (const [name, value] of res.headers) {
|
|
471
|
-
const row = document.createElement("tr");
|
|
472
|
-
const header = document.createElement("th");
|
|
473
|
-
header.setAttribute("scope", "row");
|
|
474
|
-
header.className = "pe-3 align-top font-medium text-muted-foreground";
|
|
475
|
-
header.textContent = name;
|
|
476
|
-
const cell = document.createElement("td");
|
|
477
|
-
cell.className = "break-all font-mono text-foreground";
|
|
478
|
-
cell.textContent = value;
|
|
479
|
-
row.append(header, cell);
|
|
480
|
-
table.append(row);
|
|
481
|
-
}
|
|
482
|
-
region.append(table);
|
|
483
|
-
const pre = document.createElement("pre");
|
|
484
|
-
pre.className =
|
|
485
|
-
"overflow-x-auto rounded-blume border border-border p-3 font-mono text-foreground text-xs";
|
|
486
|
-
const code = document.createElement("code");
|
|
487
|
-
code.textContent = prettyBody(text);
|
|
488
|
-
pre.append(code);
|
|
489
|
-
region.append(pre);
|
|
490
|
-
// At xl the panel is its own scroll region capped to the viewport, so a
|
|
491
|
-
// response appended under a tall form can land below the panel's fold
|
|
492
|
-
// where nothing brings it into view. Scroll the panel alone — "nearest",
|
|
493
|
-
// by hand — and never the document: below xl the panel does not scroll,
|
|
494
|
-
// and a document scroll would carry the form (Send, the body editor, its
|
|
495
|
-
// errors) off the top on a phone.
|
|
496
|
-
const panel = region.closest<HTMLElement>("[data-operation-panel]");
|
|
497
|
-
if (panel && panel.scrollHeight > panel.clientHeight) {
|
|
498
|
-
const box = panel.getBoundingClientRect();
|
|
499
|
-
const target = region.getBoundingClientRect();
|
|
500
|
-
const delta = Math.min(target.bottom - box.bottom, target.top - box.top);
|
|
501
|
-
if (delta > 0) {
|
|
502
|
-
panel.scrollBy({ top: delta });
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
};
|
|
506
|
-
|
|
507
526
|
/**
|
|
508
527
|
* Send the real request. HTTP error statuses render like any response; only
|
|
509
528
|
* a rejected fetch (the CORS wall) gets the explanatory message. One request
|
|
@@ -607,7 +626,7 @@ export const initPlayground = (root: HTMLElement): void => {
|
|
|
607
626
|
const crossOrigin = !proxy && !sample.url.startsWith("/");
|
|
608
627
|
message =
|
|
609
628
|
crossOrigin && (await reachable(sample.url))
|
|
610
|
-
?
|
|
629
|
+
? corsMessage(proxyConfig)
|
|
611
630
|
: UNREACHABLE_MESSAGE;
|
|
612
631
|
}
|
|
613
632
|
response.textContent = "";
|
|
@@ -62,7 +62,7 @@ const isReadOnly = (
|
|
|
62
62
|
* Prune a spec schema into the tiny subset `validate-json.ts` understands:
|
|
63
63
|
* `$ref`s resolved inline, cycles cut (the visited set is copied per branch so
|
|
64
64
|
* a ref reused by siblings still prunes fully), depth capped. Structure beyond
|
|
65
|
-
* the cut simply goes unvalidated
|
|
65
|
+
* the cut simply goes unvalidated, so it can never block a send.
|
|
66
66
|
*/
|
|
67
67
|
const pruneSchema = (
|
|
68
68
|
schema: SchemaLike | undefined,
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
objectProperties,
|
|
3
3
|
refName,
|
|
4
4
|
resolveSchema,
|
|
5
|
+
soleAllOfMember,
|
|
5
6
|
typeLabel,
|
|
6
7
|
} from "./helpers.ts";
|
|
7
8
|
import type { SchemaLike, SpecValue } from "./helpers.ts";
|
|
@@ -67,6 +68,15 @@ export type SchemaNode =
|
|
|
67
68
|
const isString = (value: SpecValue): value is string =>
|
|
68
69
|
typeof value === "string";
|
|
69
70
|
|
|
71
|
+
/**
|
|
72
|
+
* The `$ref` a schema stands for: its own, or its member's when it is a
|
|
73
|
+
* single-member `allOf` wrapper, which plans (and stops at a circle) the same.
|
|
74
|
+
*/
|
|
75
|
+
const refOf = (schema: SchemaLike): string | undefined => {
|
|
76
|
+
const ref = schema.$ref ?? soleAllOfMember(schema)?.$ref;
|
|
77
|
+
return isString(ref) ? ref : undefined;
|
|
78
|
+
};
|
|
79
|
+
|
|
70
80
|
const typesOf = (schema: SchemaLike): (string | undefined)[] =>
|
|
71
81
|
Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
72
82
|
|
|
@@ -88,13 +98,32 @@ interface PendingRef {
|
|
|
88
98
|
slot: SchemaSlot;
|
|
89
99
|
}
|
|
90
100
|
|
|
91
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* Which way a schema's data travels, when its table has one: a request body
|
|
103
|
+
* leaves out the `readOnly` fields the server generates, and a response the
|
|
104
|
+
* `writeOnly` ones it never returns, as the examples beside them do.
|
|
105
|
+
*/
|
|
106
|
+
export type SchemaDirection = "request" | "response";
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Plan the table tree for one schema (a request body, a response, a payload).
|
|
110
|
+
* With a `direction`, every table in the tree leaves out the fields that
|
|
111
|
+
* don't travel that way.
|
|
112
|
+
*/
|
|
92
113
|
export const schemaTree = (
|
|
93
114
|
root: SchemaLike,
|
|
94
|
-
schemas: Record<string, SchemaLike
|
|
115
|
+
schemas: Record<string, SchemaLike>,
|
|
116
|
+
direction?: SchemaDirection
|
|
95
117
|
): SchemaNode => {
|
|
96
118
|
const queue: PendingRef[] = [];
|
|
97
119
|
const expanded = new Set<string>();
|
|
120
|
+
const omitted = direction === "request" ? "readOnly" : "writeOnly";
|
|
121
|
+
|
|
122
|
+
/** Whether a property stays out of this tree's tables. */
|
|
123
|
+
const hidden = (property: SchemaLike): boolean =>
|
|
124
|
+
direction !== undefined &&
|
|
125
|
+
(property[omitted] === true ||
|
|
126
|
+
resolveSchema(schemas, property)[omitted] === true);
|
|
98
127
|
|
|
99
128
|
/**
|
|
100
129
|
* A table for `schema`, where `ancestors` are the named schemas already
|
|
@@ -107,8 +136,9 @@ export const schemaTree = (
|
|
|
107
136
|
ancestors: string[],
|
|
108
137
|
resolved = false
|
|
109
138
|
): SchemaSlot => {
|
|
110
|
-
|
|
111
|
-
|
|
139
|
+
const ref = resolved ? undefined : refOf(schema);
|
|
140
|
+
if (ref) {
|
|
141
|
+
const name = refName(ref);
|
|
112
142
|
if (ancestors.includes(name)) {
|
|
113
143
|
return { node: { kind: "circular", name } };
|
|
114
144
|
}
|
|
@@ -132,10 +162,8 @@ export const schemaTree = (
|
|
|
132
162
|
}
|
|
133
163
|
// A row discloses nested structure — never a model inside itself.
|
|
134
164
|
const rowChildren = (property: SchemaLike): SchemaSlot | undefined => {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
ancestors.includes(refName(property.$ref))
|
|
138
|
-
) {
|
|
165
|
+
const propertyRef = refOf(property);
|
|
166
|
+
if (propertyRef && ancestors.includes(refName(propertyRef))) {
|
|
139
167
|
return undefined;
|
|
140
168
|
}
|
|
141
169
|
const target = resolveSchema(schemas, property);
|
|
@@ -147,12 +175,14 @@ export const schemaTree = (
|
|
|
147
175
|
: undefined;
|
|
148
176
|
};
|
|
149
177
|
const { properties, required } = objectProperties(schema, schemas);
|
|
150
|
-
const rows: SchemaRow[] = properties
|
|
151
|
-
|
|
152
|
-
name,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
178
|
+
const rows: SchemaRow[] = properties
|
|
179
|
+
.filter(([, property]) => !hidden(property))
|
|
180
|
+
.map(([name, property]) => ({
|
|
181
|
+
children: rowChildren(property),
|
|
182
|
+
name,
|
|
183
|
+
required: required.has(name),
|
|
184
|
+
schema: property,
|
|
185
|
+
}));
|
|
156
186
|
// Shared properties beside a `oneOf`/`anyOf` (`amount` and `currency`
|
|
157
187
|
// next to `Card | BankAccount`) render above the variants, planned first
|
|
158
188
|
// as they read first.
|
|
@@ -32,6 +32,11 @@ export interface ResolvedScheme {
|
|
|
32
32
|
/** The scheme object; undefined when the requirement names an unknown one. */
|
|
33
33
|
scheme?: SecuritySchemeLike;
|
|
34
34
|
scopes: string[];
|
|
35
|
+
/**
|
|
36
|
+
* AsyncAPI: the servers that declare this scheme, set only when the
|
|
37
|
+
* channel's servers don't all declare the same ones.
|
|
38
|
+
*/
|
|
39
|
+
servers?: string[];
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
/** The security state one operation renders. */
|
|
@@ -40,6 +45,11 @@ export interface OperationSecurity {
|
|
|
40
45
|
alternatives: ResolvedScheme[][];
|
|
41
46
|
/** True when an empty requirement also allows unauthenticated calls. */
|
|
42
47
|
optional: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* AsyncAPI: the servers that declare no security while others do, so the
|
|
50
|
+
* schemes apply on the other servers only.
|
|
51
|
+
*/
|
|
52
|
+
unauthenticatedServers?: string[];
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
/**
|
|
@@ -1053,19 +1053,21 @@ export const sampleLanguageInfo = (raw: string): SampleLanguageInfo | null => {
|
|
|
1053
1053
|
return language ? { label: language.label, lang: language.lang } : null;
|
|
1054
1054
|
};
|
|
1055
1055
|
|
|
1056
|
+
/** `openapi()`'s default `codeSamples`, which hand-written endpoint pages always use. */
|
|
1057
|
+
export const DEFAULT_SAMPLE_LANGUAGES = ["curl", "js", "python"];
|
|
1058
|
+
|
|
1056
1059
|
/**
|
|
1057
1060
|
* The sample languages to render, resolved from config ids (unknown ids
|
|
1058
|
-
* dropped). `false`
|
|
1061
|
+
* dropped), in order. `false` and an empty list both render none.
|
|
1059
1062
|
*/
|
|
1060
1063
|
export const sampleLanguages = (ids: string[] | false): SampleLanguage[] => {
|
|
1061
1064
|
if (ids === false) {
|
|
1062
1065
|
return [];
|
|
1063
1066
|
}
|
|
1064
|
-
const wanted = ids.length > 0 ? ids : ["curl", "js", "python"];
|
|
1065
1067
|
const byId = new Map(LANGUAGES.map((entry) => [entry.id, entry]));
|
|
1066
1068
|
const out: SampleLanguage[] = [];
|
|
1067
1069
|
const seen = new Set<string>();
|
|
1068
|
-
for (const raw of
|
|
1070
|
+
for (const raw of ids) {
|
|
1069
1071
|
const id = sampleLanguageId(raw);
|
|
1070
1072
|
const language = byId.get(id);
|
|
1071
1073
|
if (language && !seen.has(id)) {
|
|
@@ -4,9 +4,10 @@ import type { ValidationSchema } from "./request.ts";
|
|
|
4
4
|
* Minimal JSON-schema validation for the playground body editor. Client-safe
|
|
5
5
|
* and dependency-free by design: the server prunes the operation's schema into
|
|
6
6
|
* the tiny `ValidationSchema` subset (`operation-model.ts`), so a full
|
|
7
|
-
* draft-2020 validator would be dead weight in the browser bundle.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* draft-2020 validator would be dead weight in the browser bundle. The checks
|
|
8
|
+
* catch the common "typo'd a required field" mistakes, and any error they
|
|
9
|
+
* report blocks the Try it send (`playground-client.ts`) and the event
|
|
10
|
+
* composer's connect and send (`message-composer.ts`).
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
/** An already-parsed JSON object — string keys, parsed-JSON values. */
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from "astro";
|
|
2
|
+
|
|
3
|
+
import { POWERED_BY_HEADERS } from "../core/powered-by.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Names Blume in the responses Astro renders (wired by the integration unless
|
|
7
|
+
* `poweredBy` is `false`), the server-rendered ones a host's own header rules
|
|
8
|
+
* don't reach. Innermost, so a page or the project's own middleware that sets
|
|
9
|
+
* a header of the same name keeps its value. Headers are set in place; a
|
|
10
|
+
* response whose headers are immutable (a proxied `fetch()` result) is copied
|
|
11
|
+
* first.
|
|
12
|
+
*/
|
|
13
|
+
export const onRequest: MiddlewareHandler = async (_context, render) => {
|
|
14
|
+
const response = await render();
|
|
15
|
+
const missing = Object.entries(POWERED_BY_HEADERS).filter(
|
|
16
|
+
([name]) => !response.headers.has(name)
|
|
17
|
+
);
|
|
18
|
+
if (missing.length === 0) {
|
|
19
|
+
return response;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
for (const [name, value] of missing) {
|
|
23
|
+
response.headers.set(name, value);
|
|
24
|
+
}
|
|
25
|
+
return response;
|
|
26
|
+
} catch {
|
|
27
|
+
const copy = new Response(response.body, response);
|
|
28
|
+
for (const [name, value] of missing) {
|
|
29
|
+
copy.headers.set(name, value);
|
|
30
|
+
}
|
|
31
|
+
return copy;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UIStrings } from "./i18n-ui.ts";
|
|
2
|
+
import { resolveLocalizable } from "./localizable.ts";
|
|
3
|
+
import type { LocalizableLabel, ResolvedConfig } from "./schema.ts";
|
|
2
4
|
import { sourcesOfKind } from "./sources/collection.ts";
|
|
3
5
|
import type { PageRecord } from "./types.ts";
|
|
4
6
|
|
|
@@ -22,3 +24,31 @@ export const hasChangelogIndex = (
|
|
|
22
24
|
page.contentType === "changelog" &&
|
|
23
25
|
!(page.meta.draft || page.meta.sidebar.hidden)
|
|
24
26
|
) || sourcesOfKind(config, "github-releases").length > 0;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A locale's UI strings with the index's title and description taken from
|
|
30
|
+
* the `changelog` config where it sets them (a string, or a per-locale map
|
|
31
|
+
* resolved like a header label), so every surface that reads the
|
|
32
|
+
* `changelog` strings (the page, its OG card, its Markdown mirror) agrees.
|
|
33
|
+
*/
|
|
34
|
+
export const withChangelogIndexText = (
|
|
35
|
+
config: ResolvedConfig,
|
|
36
|
+
ui: UIStrings,
|
|
37
|
+
locale?: string
|
|
38
|
+
): UIStrings => {
|
|
39
|
+
const text = (label: LocalizableLabel | undefined, fallback: string) =>
|
|
40
|
+
label === undefined
|
|
41
|
+
? fallback
|
|
42
|
+
: resolveLocalizable(label, locale, config.i18n?.defaultLocale);
|
|
43
|
+
return {
|
|
44
|
+
...ui,
|
|
45
|
+
changelog: {
|
|
46
|
+
...ui.changelog,
|
|
47
|
+
description: text(
|
|
48
|
+
config.changelog?.description,
|
|
49
|
+
ui.changelog.description
|
|
50
|
+
),
|
|
51
|
+
title: text(config.changelog?.title, ui.changelog.title),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { relative } from "pathe";
|
|
2
|
+
|
|
1
3
|
import { BUILTIN_MDX_TAGS } from "./builtin-tags.ts";
|
|
2
4
|
import type { Diagnostic, PageRecord } from "./types.ts";
|
|
3
5
|
|
|
@@ -42,3 +44,54 @@ export const validateUsedComponents = (
|
|
|
42
44
|
}
|
|
43
45
|
return diagnostics;
|
|
44
46
|
};
|
|
47
|
+
|
|
48
|
+
/** What example discovery found: where it looked, and each example's key. */
|
|
49
|
+
export interface ExampleKeys {
|
|
50
|
+
/** Absolute directory the examples were discovered under. */
|
|
51
|
+
dir: string;
|
|
52
|
+
examples: readonly { path: string }[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Warn about each `<Component path>` in an `.mdx` page that names no
|
|
57
|
+
* discovered example. The page still renders, with a "No example found" box
|
|
58
|
+
* where the preview should be, so without this a typo or a moved example
|
|
59
|
+
* ships silently. Reported at the `path` value, in the partial that holds it
|
|
60
|
+
* when an `<include>` brought it in; a file shared by several locales is
|
|
61
|
+
* reported once. `extraTags` are the project's own components (islands +
|
|
62
|
+
* overrides), as for {@link validateUsedComponents}: one named `Component`
|
|
63
|
+
* replaces the built-in and resolves `path` its own way, so none is checked.
|
|
64
|
+
*/
|
|
65
|
+
export const missingExampleDiagnostics = (
|
|
66
|
+
pages: readonly PageRecord[],
|
|
67
|
+
discovery: ExampleKeys,
|
|
68
|
+
root: string,
|
|
69
|
+
extraTags: ReadonlySet<string>
|
|
70
|
+
): Diagnostic[] => {
|
|
71
|
+
if (extraTags.has("Component")) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
const known = new Set(discovery.examples.map((example) => example.path));
|
|
75
|
+
const dir = relative(root, discovery.dir) || ".";
|
|
76
|
+
const diagnostics: Diagnostic[] = [];
|
|
77
|
+
const seen = new Set<string>();
|
|
78
|
+
for (const page of pages) {
|
|
79
|
+
for (const use of page.examplesUsed ?? []) {
|
|
80
|
+
const file = use.file ?? page.sourcePath ?? page.id;
|
|
81
|
+
const key = `${file}:${use.line}:${use.column}`;
|
|
82
|
+
if (!(known.has(use.path) || seen.has(key))) {
|
|
83
|
+
seen.add(key);
|
|
84
|
+
diagnostics.push({
|
|
85
|
+
code: "BLUME_EXAMPLE_NOT_FOUND",
|
|
86
|
+
column: use.column,
|
|
87
|
+
file,
|
|
88
|
+
line: use.line,
|
|
89
|
+
message: `<Component path="${use.path}"> in ${page.route} names no example, so the page shows "No example found" in its place.`,
|
|
90
|
+
severity: "warning",
|
|
91
|
+
suggestion: `Fix the path, or add the example under ${dir}/: \`path\` is its location there, without the extension.`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return diagnostics;
|
|
97
|
+
};
|
|
@@ -69,6 +69,29 @@ type Group = (typeof GROUPS)[number];
|
|
|
69
69
|
|
|
70
70
|
const isGroup = (name: string): name is Group => GROUP_SET.has(name);
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* The `layout` keys the built-in chrome reads (`RootLayout.astro` and
|
|
74
|
+
* `Header.astro`). Any other key is never rendered, so it's warned about
|
|
75
|
+
* rather than silently dropped; a typo or wrong case would otherwise leave
|
|
76
|
+
* the built-in in place with no sign why.
|
|
77
|
+
*/
|
|
78
|
+
const LAYOUT_SLOTS = [
|
|
79
|
+
"Layout",
|
|
80
|
+
"Header",
|
|
81
|
+
"Logo",
|
|
82
|
+
"Search",
|
|
83
|
+
"Sidebar",
|
|
84
|
+
"MobileNav",
|
|
85
|
+
"Breadcrumbs",
|
|
86
|
+
"TableOfContents",
|
|
87
|
+
"Pagination",
|
|
88
|
+
"Feedback",
|
|
89
|
+
"PageHeader",
|
|
90
|
+
"PageFooter",
|
|
91
|
+
"Footer",
|
|
92
|
+
];
|
|
93
|
+
const LAYOUT_SLOT_SET: ReadonlySet<string> = new Set(LAYOUT_SLOTS);
|
|
94
|
+
|
|
72
95
|
/** The authoring forms an override accepts; the fix every rejection points at. */
|
|
73
96
|
export const ACCEPTED_OVERRIDE_FORMS =
|
|
74
97
|
"Each override must be an imported identifier, a path string, or a `{ component, client, media }` object literal whose `component` is an imported identifier or a path string.";
|
|
@@ -628,6 +651,15 @@ const collectGroupOverrides = (
|
|
|
628
651
|
if (normalized) {
|
|
629
652
|
result[name].push(normalized);
|
|
630
653
|
}
|
|
654
|
+
if (
|
|
655
|
+
name === "layout" &&
|
|
656
|
+
normalized &&
|
|
657
|
+
!LAYOUT_SLOT_SET.has(normalized.key)
|
|
658
|
+
) {
|
|
659
|
+
context.warnings.push(
|
|
660
|
+
`Layout override "${normalized.key}" isn't a layout slot, so nothing renders it. Use one of: ${LAYOUT_SLOTS.join(", ")}.`
|
|
661
|
+
);
|
|
662
|
+
}
|
|
631
663
|
}
|
|
632
664
|
};
|
|
633
665
|
|