blume 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +113 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-6k4ftwze.js → chunk-0gz36akr.js} +18 -2
- package/dist/cli/{chunk-6k4ftwze.js.map → chunk-0gz36akr.js.map} +3 -3
- package/dist/cli/{chunk-zp79m0ts.js → chunk-1n228xqb.js} +2 -2
- package/dist/cli/{chunk-ddndchfr.js → chunk-2f3ndkpw.js} +57 -29
- package/dist/cli/chunk-2f3ndkpw.js.map +14 -0
- package/dist/cli/{chunk-fsmrqk8a.js → chunk-2f7n4qzt.js} +8 -2
- package/dist/cli/{chunk-fsmrqk8a.js.map → chunk-2f7n4qzt.js.map} +3 -3
- package/dist/cli/{chunk-ppzjqwx2.js → chunk-2n4ps1b3.js} +17 -18
- package/dist/cli/{chunk-ppzjqwx2.js.map → chunk-2n4ps1b3.js.map} +3 -3
- package/dist/cli/{chunk-5r8g91qn.js → chunk-43zcf4gz.js} +398 -159
- package/dist/cli/chunk-43zcf4gz.js.map +36 -0
- package/dist/cli/chunk-4ejxbzee.js +39 -0
- package/dist/cli/chunk-4ejxbzee.js.map +10 -0
- package/dist/cli/{chunk-hr8ne106.js → chunk-4h8z9vv5.js} +296 -77
- package/dist/cli/chunk-4h8z9vv5.js.map +16 -0
- package/dist/cli/{chunk-k7pj68a8.js → chunk-5cg2rzgf.js} +18 -16
- package/dist/cli/{chunk-k7pj68a8.js.map → chunk-5cg2rzgf.js.map} +2 -2
- package/dist/cli/{chunk-h2ez8dzb.js → chunk-5ffywsmb.js} +4 -4
- package/dist/cli/{chunk-g698a744.js → chunk-5wj2qwn2.js} +5 -5
- package/dist/cli/chunk-6bm0xpgd.js +18 -0
- package/dist/cli/chunk-6bm0xpgd.js.map +10 -0
- package/dist/cli/{chunk-3yce002v.js → chunk-713mngdq.js} +15 -8
- package/dist/cli/chunk-713mngdq.js.map +14 -0
- package/dist/cli/{chunk-91ws1n6j.js → chunk-9geymqns.js} +17 -15
- package/dist/cli/{chunk-91ws1n6j.js.map → chunk-9geymqns.js.map} +2 -2
- package/dist/cli/{chunk-6dtt0zfn.js → chunk-9xr4dgee.js} +27 -18
- package/dist/cli/chunk-9xr4dgee.js.map +10 -0
- package/dist/cli/{chunk-sqw4ekg1.js → chunk-amrb6hgh.js} +2 -2
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-wdrt2k2v.js → chunk-cmtcnh9f.js} +90 -26
- package/dist/cli/chunk-cmtcnh9f.js.map +10 -0
- package/dist/cli/chunk-cy5bm0j0.js +104 -0
- package/dist/cli/chunk-cy5bm0j0.js.map +11 -0
- package/dist/cli/{chunk-7mbqtmgb.js → chunk-e7vvk5ya.js} +21 -12
- package/dist/cli/chunk-e7vvk5ya.js.map +10 -0
- package/dist/cli/{chunk-qkb5a8sa.js → chunk-g2z9x01v.js} +6 -98
- package/dist/cli/chunk-g2z9x01v.js.map +10 -0
- package/dist/cli/{chunk-273ygyr4.js → chunk-ga0pf4aj.js} +7 -7
- package/dist/cli/{chunk-273ygyr4.js.map → chunk-ga0pf4aj.js.map} +3 -3
- package/dist/cli/{chunk-h7k3nq3v.js → chunk-gp84za0h.js} +2 -2
- package/dist/cli/{chunk-hqp2ajnh.js → chunk-h2a48yhd.js} +195 -73
- package/dist/cli/chunk-h2a48yhd.js.map +36 -0
- package/dist/cli/{chunk-pbg5a4s3.js → chunk-jnwj5kjj.js} +71 -47
- package/dist/cli/chunk-jnwj5kjj.js.map +19 -0
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-8g8ytmgx.js → chunk-nd1821sk.js} +21 -19
- package/dist/cli/{chunk-8g8ytmgx.js.map → chunk-nd1821sk.js.map} +2 -2
- package/dist/cli/{chunk-w4bxdvsa.js → chunk-ntv4qrt7.js} +17 -15
- package/dist/cli/{chunk-w4bxdvsa.js.map → chunk-ntv4qrt7.js.map} +2 -2
- package/dist/cli/{chunk-bfwp9vp6.js → chunk-p804f3pe.js} +7 -7
- package/dist/cli/{chunk-4e9b9ra6.js → chunk-py62fewh.js} +6 -6
- package/dist/cli/{chunk-4e9b9ra6.js.map → chunk-py62fewh.js.map} +1 -1
- package/dist/cli/chunk-q3wxxq39.js +126 -0
- package/dist/cli/chunk-q3wxxq39.js.map +11 -0
- package/dist/cli/{chunk-j85scx15.js → chunk-rekqz4qg.js} +142 -46
- package/dist/cli/chunk-rekqz4qg.js.map +10 -0
- package/dist/cli/{chunk-00gs3wqs.js → chunk-ta27feev.js} +1 -1
- package/dist/cli/{chunk-v6ya5kcb.js → chunk-xkz5xbtv.js} +4031 -1132
- package/dist/cli/chunk-xkz5xbtv.js.map +213 -0
- package/dist/cli/{chunk-bbnwccaz.js → chunk-y4ykbark.js} +2 -2
- package/dist/cli/{chunk-n1yg3tj3.js → chunk-y5h4r2y0.js} +6 -6
- package/dist/cli/{chunk-n1yg3tj3.js.map → chunk-y5h4r2y0.js.map} +3 -3
- package/dist/cli/{chunk-nfcyttvj.js → chunk-yj17vs39.js} +9 -9
- package/dist/cli/{chunk-nfcyttvj.js.map → chunk-yj17vs39.js.map} +1 -1
- package/dist/cli/{chunk-7vtckvaw.js → chunk-yxmk4pec.js} +16 -14
- package/dist/cli/{chunk-7vtckvaw.js.map → chunk-yxmk4pec.js.map} +2 -2
- package/dist/cli/{chunk-gs7r695n.js → chunk-zccbjcj0.js} +22 -8
- package/dist/cli/{chunk-gs7r695n.js.map → chunk-zccbjcj0.js.map} +3 -3
- package/dist/cli/{chunk-xh43dwgw.js → chunk-zf748avv.js} +415 -225
- package/dist/cli/chunk-zf748avv.js.map +37 -0
- package/dist/cli/{chunk-d1v5rhy0.js → chunk-zhvd6adm.js} +16 -14
- package/dist/cli/{chunk-d1v5rhy0.js.map → chunk-zhvd6adm.js.map} +2 -2
- package/dist/cli/index.js +28 -20
- package/dist/cli/index.js.map +5 -5
- package/dist/types/ai/agent-surface.d.ts +8 -7
- package/dist/types/ai/ai-catalog.d.ts +7 -0
- package/dist/types/ai/ask-context.d.ts +22 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/link-headers.d.ts +8 -1
- package/dist/types/ai/openapi-components.d.ts +5 -2
- package/dist/types/ai/relative-links.d.ts +9 -7
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +20 -1
- package/dist/types/ai/tar.d.ts +1 -3
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
- package/dist/types/analytics/schema.d.ts +14 -0
- package/dist/types/astro/integration.d.ts +11 -2
- package/dist/types/captcha/hcaptcha.d.ts +27 -0
- package/dist/types/captcha/index.d.ts +28 -0
- package/dist/types/captcha/schema.d.ts +29 -0
- package/dist/types/captcha/turnstile.d.ts +28 -0
- package/dist/types/components/content/api-field.d.ts +59 -0
- package/dist/types/components/content/api-page.d.ts +95 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/helpers.d.ts +137 -0
- package/dist/types/components/openapi/security.d.ts +85 -0
- package/dist/types/consent/ethyca.d.ts +48 -0
- package/dist/types/consent/index.d.ts +37 -0
- package/dist/types/consent/native.d.ts +28 -0
- package/dist/types/consent/osano.d.ts +42 -0
- package/dist/types/consent/schema.d.ts +110 -0
- package/dist/types/core/base-path.d.ts +21 -7
- package/dist/types/core/config-input.d.ts +196 -27
- package/dist/types/core/data.d.ts +49 -4
- package/dist/types/core/directive-diagnostics.d.ts +12 -0
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/heading-markers.d.ts +5 -7
- package/dist/types/core/i18n-ui.d.ts +86 -0
- package/dist/types/core/i18n.d.ts +2 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/last-modified.d.ts +10 -0
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/meta.d.ts +8 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/redirect-patterns.d.ts +144 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +558 -56
- package/dist/types/core/sources/lower.d.ts +29 -16
- package/dist/types/core/sources/normalize.d.ts +13 -1
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/sources/watch.d.ts +12 -5
- package/dist/types/core/standard-schema.d.ts +5 -0
- package/dist/types/core/types.d.ts +1 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/artifacts.d.ts +6 -4
- package/dist/types/deploy/headers.d.ts +5 -0
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +5 -0
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/types.d.ts +8 -0
- package/dist/types/deploy/platforms/vercel.d.ts +6 -0
- package/dist/types/deploy/redirects.d.ts +61 -22
- package/dist/types/deploy/vercel-negotiation.d.ts +9 -0
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/directives.d.ts +62 -0
- package/dist/types/markdown/features.d.ts +24 -2
- package/dist/types/markdown/mdast.d.ts +63 -0
- 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/asyncapi.d.ts +4 -2
- package/dist/types/openapi/model.d.ts +12 -6
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +13 -0
- package/dist/types/openapi/references.d.ts +14 -4
- package/dist/types/ratelimit/cloudflare.d.ts +39 -0
- package/dist/types/ratelimit/index.d.ts +27 -0
- package/dist/types/ratelimit/memory.d.ts +36 -0
- package/dist/types/ratelimit/schema.d.ts +111 -0
- package/dist/types/ratelimit/upstash.d.ts +21 -0
- package/dist/types/ratelimit/wrangler.d.ts +23 -0
- package/dist/types/reference/asyncapi.d.ts +10 -10
- package/dist/types/reference/graphql.d.ts +13 -10
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +45 -5
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +60 -36
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +4 -0
- package/dist/types/seo/metatags.d.ts +20 -0
- package/docs/02-deployment.mdx +44 -6
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/08-faq.mdx +1 -1
- package/docs/advanced/changelog.mdx +2 -2
- package/docs/advanced/custom-pages.mdx +3 -3
- package/docs/advanced/skills.mdx +14 -0
- package/docs/cli/audit.mdx +38 -2
- package/docs/cli/evals.mdx +3 -3
- package/docs/cli/index.mdx +1 -0
- package/docs/cli/translate.mdx +3 -3
- package/docs/cli/version.mdx +1 -1
- package/docs/configuration/analytics.mdx +22 -1
- package/docs/configuration/assistant.mdx +188 -36
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +6 -4
- package/docs/configuration/index.mdx +63 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +69 -0
- package/docs/configuration/search.mdx +30 -2
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +107 -1
- package/docs/content/frontmatter.mdx +77 -1
- package/docs/content/i18n.mdx +40 -3
- package/docs/content/includes.mdx +16 -0
- package/docs/content/index.mdx +4 -2
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +4 -1
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +28 -6
- package/docs/content/sources/contentful.mdx +32 -0
- package/docs/content/sources/custom.mdx +39 -0
- package/docs/content/sources/github-releases.mdx +31 -0
- package/docs/content/sources/index.mdx +91 -0
- package/docs/content/sources/meta.ts +16 -0
- package/docs/content/sources/notion.mdx +32 -0
- package/docs/content/sources/obsidian.mdx +37 -0
- package/docs/content/sources/payload.mdx +30 -0
- package/docs/content/sources/remote-mdx.mdx +40 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +31 -0
- package/docs/content/syntax.mdx +81 -2
- package/docs/content/variables.mdx +41 -0
- package/docs/content/versioning.mdx +1 -1
- package/docs/discoverability/agent-discovery.mdx +30 -3
- package/docs/discoverability/index.mdx +3 -2
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/markdown.mdx +2 -2
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/discoverability/open-graph.mdx +5 -3
- package/docs/discoverability/rss.mdx +1 -1
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +2 -2
- package/docs/references/graphql.mdx +3 -3
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +106 -5
- package/docs/references/scalar.mdx +3 -1
- package/package.json +36 -1
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +5 -5
- package/skills/blume-migrate/references/docusaurus.md +3 -3
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +3 -3
- package/skills/blume-migrate/references/starlight.md +2 -1
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +67 -16
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +4 -3
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +12 -5
- package/src/ai/api/handlers.ts +2 -2
- package/src/ai/api/spec.ts +2 -2
- package/src/ai/api-catalog.ts +6 -2
- package/src/ai/ask-context.ts +73 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/changelog-markdown.ts +2 -2
- package/src/ai/component-markdown.ts +75 -0
- package/src/ai/cors.ts +2 -0
- package/src/ai/index.ts +12 -0
- package/src/ai/link-headers.ts +14 -5
- package/src/ai/llms.ts +24 -9
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/mcp/discovery.ts +2 -2
- package/src/ai/mcp/query.ts +2 -2
- package/src/ai/mcp/server.ts +2 -2
- package/src/ai/openapi-components.ts +31 -9
- package/src/ai/relative-links.ts +42 -26
- package/src/ai/serializers.ts +2 -1
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +49 -3
- package/src/ai/tar.ts +139 -12
- package/src/ai/write-skill.ts +97 -0
- package/src/analytics/head.ts +4 -0
- package/src/analytics/index.ts +5 -0
- package/src/analytics/one-dollar-stats.ts +86 -0
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +133 -19
- package/src/astro/include-hmr.ts +31 -12
- package/src/astro/include-refresh.ts +19 -8
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +143 -14
- package/src/astro/module-types.ts +6 -0
- package/src/astro/runtime-modules.ts +28 -13
- package/src/astro/templates.ts +364 -67
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +19 -0
- package/src/audit/checks/contrast.ts +183 -0
- package/src/audit/checks/i18n.ts +2 -3
- package/src/audit/checks/indexability.ts +2 -3
- package/src/audit/checks/links.ts +13 -13
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/graph.ts +3 -1
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +14 -9
- package/src/audit/snapshot.ts +5 -0
- package/src/audit/types.ts +2 -1
- package/src/blume-modules.d.ts +7 -0
- package/src/captcha/client.ts +152 -0
- package/src/captcha/hcaptcha.ts +36 -0
- package/src/captcha/index.ts +28 -0
- package/src/captcha/schema.ts +32 -0
- package/src/captcha/turnstile.ts +38 -0
- package/src/captcha/verify.ts +71 -0
- package/src/cli/args.ts +32 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/audit.ts +4 -1
- package/src/cli/commands/doctor.ts +25 -17
- package/src/cli/commands/eval.ts +19 -11
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/commands/translate.ts +9 -12
- package/src/cli/commands/validate.ts +3 -1
- package/src/cli/dev-lock.ts +157 -37
- package/src/cli/index.ts +5 -0
- package/src/cli/report-format.ts +11 -6
- package/src/cli/required-secrets.ts +71 -29
- package/src/components/BlumePage.astro +2 -0
- package/src/components/colors.ts +19 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +62 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Badge.astro +5 -3
- package/src/components/content/Color.astro +1 -0
- package/src/components/content/Component.astro +2 -2
- 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/Tab.astro +0 -1
- package/src/components/content/Tabs.astro +4 -0
- package/src/components/content/Tile.astro +1 -0
- package/src/components/content/Tooltip.astro +1 -0
- package/src/components/content/Tree.astro +1 -0
- package/src/components/content/TypeTable.astro +4 -1
- package/src/components/content/View.astro +21 -0
- package/src/components/content/ViewSwitcher.astro +168 -0
- package/src/components/content/api-field.ts +100 -0
- package/src/components/content/api-page.ts +224 -0
- package/src/components/content/badge-color.ts +5 -2
- package/src/components/content/base-href.ts +13 -36
- 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 +125 -18
- package/src/components/islands/base-path.ts +47 -10
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +145 -40
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/islands/webmcp.ts +4 -2
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +11 -4
- 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/DiscoveryLinks.astro +9 -5
- package/src/components/layout/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +124 -82
- package/src/components/layout/LanguageSwitcher.astro +50 -17
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +35 -9
- package/src/components/layout/NavTabMenu.astro +3 -3
- package/src/components/layout/NavTree.astro +16 -6
- package/src/components/layout/PageActions.astro +4 -3
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +78 -9
- package/src/components/layout/Pagination.astro +3 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +313 -50
- package/src/components/layout/Search.astro +64 -30
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/VersionBanner.astro +2 -2
- package/src/components/layout/analytics-client.ts +12 -0
- package/src/components/layout/consent/native.ts +79 -0
- package/src/components/layout/consent/types.ts +37 -0
- package/src/components/layout/footer-links.ts +53 -0
- package/src/components/layout/footer-socials.ts +87 -0
- package/src/components/layout/locale-redirect.ts +107 -0
- package/src/components/layout/nav-utils.ts +83 -0
- package/src/components/layout/page-feedback.ts +96 -0
- package/src/components/layout/search/analytics.ts +98 -0
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/types.ts +20 -0
- package/src/components/layout/search/typesense.ts +5 -1
- package/src/components/layout/toc-active.ts +41 -0
- package/src/components/layout/toc-element.ts +8 -14
- package/src/components/openapi/ApiTagOperations.astro +2 -2
- package/src/components/openapi/AsyncApiOperation.astro +7 -4
- package/src/components/openapi/GraphqlChip.astro +2 -2
- package/src/components/openapi/Operation.astro +163 -13
- package/src/components/openapi/Playground.astro +4 -4
- package/src/components/openapi/RequestBody.astro +6 -4
- package/src/components/openapi/RequestPanel.astro +63 -8
- package/src/components/openapi/Responses.astro +6 -4
- package/src/components/openapi/SchemaTable.astro +7 -0
- package/src/components/openapi/async-snippets.ts +4 -4
- package/src/components/openapi/async.ts +38 -6
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/helpers.ts +19 -9
- package/src/components/openapi/message-composer.ts +6 -1
- package/src/components/openapi/message.ts +17 -2
- package/src/components/openapi/operation-model.ts +81 -11
- package/src/components/openapi/panel.ts +4 -2
- package/src/components/openapi/param-style.ts +181 -0
- package/src/components/openapi/playground-client.ts +73 -16
- package/src/components/openapi/request.ts +190 -26
- package/src/components/openapi/schema-tree.ts +30 -24
- package/src/components/openapi/security.ts +6 -3
- package/src/components/openapi/snippets.ts +953 -13
- package/src/components/openapi/ws-client.ts +18 -2
- 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/base-path.ts +62 -16
- package/src/core/builtin-tags.ts +5 -0
- package/src/core/client-address.ts +19 -0
- package/src/core/config-input.ts +203 -27
- package/src/core/data.ts +44 -4
- package/src/core/diagnostics.ts +5 -2
- package/src/core/directive-diagnostics.ts +99 -0
- package/src/core/footer.ts +26 -0
- package/src/core/frontmatter.ts +21 -18
- package/src/core/graph.ts +39 -36
- package/src/core/heading-markers.ts +5 -18
- package/src/core/i18n-ui.ts +82 -2
- package/src/core/i18n.ts +31 -3
- package/src/core/includes.ts +20 -3
- package/src/core/last-modified.ts +25 -3
- package/src/core/links.ts +16 -2
- package/src/core/locale-links.ts +5 -1
- package/src/core/localizable.ts +26 -0
- package/src/core/meta.ts +33 -19
- package/src/core/navigation.ts +71 -20
- package/src/core/page-modes.ts +56 -0
- package/src/core/project-graph.ts +138 -10
- package/src/core/redirect-patterns.ts +491 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +342 -68
- package/src/core/sources/contentful-rich-text.ts +27 -20
- package/src/core/sources/filesystem.ts +20 -2
- package/src/core/sources/github-releases.ts +25 -6
- package/src/core/sources/lexical.ts +23 -18
- package/src/core/sources/lower.ts +201 -34
- package/src/core/sources/mdx-remote.ts +51 -16
- package/src/core/sources/normalize.ts +327 -91
- package/src/core/sources/notion.ts +52 -25
- package/src/core/sources/obsidian.ts +23 -6
- package/src/core/sources/portable-text.ts +38 -21
- package/src/core/sources/read.ts +8 -3
- package/src/core/sources/strapi-blocks.ts +20 -16
- package/src/core/sources/watch.ts +20 -7
- package/src/core/standard-schema.ts +10 -6
- package/src/core/types.ts +1 -1
- package/src/core/ui-packs/ar.ts +43 -0
- package/src/core/ui-packs/bg.ts +45 -0
- package/src/core/ui-packs/bn.ts +43 -0
- package/src/core/ui-packs/ca.ts +46 -0
- package/src/core/ui-packs/cs.ts +44 -0
- package/src/core/ui-packs/da.ts +45 -0
- package/src/core/ui-packs/de.ts +46 -0
- package/src/core/ui-packs/el.ts +45 -0
- package/src/core/ui-packs/es.ts +46 -0
- package/src/core/ui-packs/fa.ts +45 -0
- package/src/core/ui-packs/fi.ts +45 -0
- package/src/core/ui-packs/fr.ts +46 -0
- package/src/core/ui-packs/he.ts +43 -0
- package/src/core/ui-packs/hi.ts +44 -0
- package/src/core/ui-packs/hr.ts +45 -0
- package/src/core/ui-packs/hu.ts +44 -0
- package/src/core/ui-packs/id.ts +45 -0
- package/src/core/ui-packs/it.ts +45 -0
- package/src/core/ui-packs/ja.ts +45 -0
- package/src/core/ui-packs/ko.ts +44 -0
- package/src/core/ui-packs/nl.ts +46 -0
- package/src/core/ui-packs/no.ts +44 -0
- package/src/core/ui-packs/pl.ts +45 -0
- package/src/core/ui-packs/pt-br.ts +46 -0
- package/src/core/ui-packs/pt.ts +45 -0
- package/src/core/ui-packs/ro.ts +45 -0
- package/src/core/ui-packs/ru.ts +45 -0
- package/src/core/ui-packs/sk.ts +44 -0
- package/src/core/ui-packs/sr.ts +45 -0
- package/src/core/ui-packs/sv.ts +44 -0
- package/src/core/ui-packs/th.ts +43 -0
- package/src/core/ui-packs/tr.ts +45 -0
- package/src/core/ui-packs/uk.ts +45 -0
- package/src/core/ui-packs/vi.ts +45 -0
- package/src/core/ui-packs/zh-tw.ts +43 -0
- package/src/core/ui-packs/zh.ts +43 -0
- package/src/core/variables.ts +103 -0
- package/src/core/version-cut.ts +52 -15
- package/src/deploy/artifacts.ts +104 -14
- package/src/deploy/cloudflare-negotiation.ts +39 -17
- package/src/deploy/headers.ts +10 -5
- package/src/deploy/node-headers.ts +64 -10
- package/src/deploy/platforms/cloudflare.ts +44 -3
- package/src/deploy/platforms/netlify.ts +34 -1
- package/src/deploy/platforms/node.ts +1 -0
- package/src/deploy/platforms/static.ts +1 -0
- package/src/deploy/platforms/types.ts +8 -0
- package/src/deploy/platforms/vercel.ts +38 -2
- package/src/deploy/redirects.ts +139 -36
- package/src/deploy/robots.ts +2 -2
- package/src/deploy/rss.ts +4 -3
- package/src/deploy/sitemap.ts +7 -5
- package/src/deploy/vercel-negotiation.ts +36 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/base-links.ts +34 -36
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/directives.ts +242 -36
- package/src/markdown/features.ts +20 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +35 -11
- package/src/markdown/math.ts +4 -4
- package/src/markdown/mdast.ts +5 -2
- package/src/markdown/relative-links.ts +12 -4
- package/src/markdown/variables.ts +56 -0
- package/src/markdown/views.ts +82 -0
- package/src/narration/build.ts +412 -0
- package/src/narration/player.ts +249 -0
- package/src/narration/provider.ts +29 -0
- package/src/narration/script.ts +592 -0
- package/src/og/card.ts +136 -11
- package/src/og/derive.ts +41 -31
- package/src/og/index.ts +1 -0
- package/src/openapi/asyncapi.ts +4 -2
- package/src/openapi/model.ts +77 -36
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +55 -2
- package/src/openapi/proxy.ts +63 -10
- package/src/openapi/references.ts +21 -5
- package/src/openapi/render-mdx.ts +46 -3
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +1 -1
- package/src/ratelimit/cloudflare.ts +54 -0
- package/src/ratelimit/index.ts +30 -0
- package/src/ratelimit/memory.ts +45 -0
- package/src/ratelimit/runtime.ts +229 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +30 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +5 -2
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +51 -7
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +201 -28
- package/src/registry/registry.ts +7 -0
- package/src/search/adapters/version-scope.ts +30 -0
- package/src/search/documents.ts +93 -28
- package/src/search/orama-index.ts +28 -3
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/popular.ts +2 -1
- package/src/search/sync/algolia.ts +15 -4
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +5 -0
- package/src/seo/jsonld.ts +7 -3
- package/src/seo/metatags.ts +67 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +56 -3
- package/src/theme/palette.ts +121 -45
- package/src/translate/meta.ts +68 -24
- package/src/translate/prompts.ts +1 -0
- package/src/translate/run.ts +3 -3
- package/src/translate/validate.ts +12 -3
- package/src/translate/work-list.ts +56 -17
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-3yce002v.js.map +0 -14
- package/dist/cli/chunk-5r8g91qn.js.map +0 -34
- package/dist/cli/chunk-6dtt0zfn.js.map +0 -10
- package/dist/cli/chunk-7mbqtmgb.js.map +0 -10
- package/dist/cli/chunk-ddndchfr.js.map +0 -14
- package/dist/cli/chunk-esh98wmb.js +0 -23
- package/dist/cli/chunk-esh98wmb.js.map +0 -10
- package/dist/cli/chunk-hqp2ajnh.js.map +0 -35
- package/dist/cli/chunk-hr8ne106.js.map +0 -13
- package/dist/cli/chunk-j85scx15.js.map +0 -10
- package/dist/cli/chunk-mqc662a6.js +0 -75
- package/dist/cli/chunk-mqc662a6.js.map +0 -11
- package/dist/cli/chunk-pbg5a4s3.js.map +0 -19
- package/dist/cli/chunk-qkb5a8sa.js.map +0 -10
- package/dist/cli/chunk-v6ya5kcb.js.map +0 -189
- package/dist/cli/chunk-wdrt2k2v.js.map +0 -10
- package/dist/cli/chunk-xh43dwgw.js.map +0 -36
- package/docs/content/sources.mdx +0 -338
- /package/dist/cli/{chunk-zp79m0ts.js.map → chunk-1n228xqb.js.map} +0 -0
- /package/dist/cli/{chunk-h2ez8dzb.js.map → chunk-5ffywsmb.js.map} +0 -0
- /package/dist/cli/{chunk-g698a744.js.map → chunk-5wj2qwn2.js.map} +0 -0
- /package/dist/cli/{chunk-sqw4ekg1.js.map → chunk-amrb6hgh.js.map} +0 -0
- /package/dist/cli/{chunk-h7k3nq3v.js.map → chunk-gp84za0h.js.map} +0 -0
- /package/dist/cli/{chunk-bfwp9vp6.js.map → chunk-p804f3pe.js.map} +0 -0
- /package/dist/cli/{chunk-00gs3wqs.js.map → chunk-ta27feev.js.map} +0 -0
- /package/dist/cli/{chunk-bbnwccaz.js.map → chunk-y4ykbark.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
|
@@ -18,6 +18,7 @@ import { normalizeAsyncApiDocument } from "./asyncapi.ts";
|
|
|
18
18
|
import { buildGraphqlDocument } from "./graphql-build.ts";
|
|
19
19
|
import type { GraphqlDocument } from "./graphql.ts";
|
|
20
20
|
import type { ApiDocument } from "./model.ts";
|
|
21
|
+
import { applyOverlay, isJsonObject, overlayDocument } from "./overlay.ts";
|
|
21
22
|
import { SpecDependencyError } from "./spec-dependency-error.ts";
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -75,6 +76,11 @@ export class InvalidSpecError extends Error {
|
|
|
75
76
|
|
|
76
77
|
/** Where and whether to cache a remote spec's text between runs. */
|
|
77
78
|
export interface SpecFetchOptions {
|
|
79
|
+
/**
|
|
80
|
+
* Overlay documents (local paths or `http(s)` URLs) applied in order to
|
|
81
|
+
* the parsed spec, before it's upgraded. See `overlay.ts`.
|
|
82
|
+
*/
|
|
83
|
+
overlays?: readonly string[];
|
|
78
84
|
/** Dir for a last-good on-disk copy of a remote spec (offline fallback). */
|
|
79
85
|
cacheDir?: string;
|
|
80
86
|
/**
|
|
@@ -310,13 +316,60 @@ const readSpecText = async (
|
|
|
310
316
|
const isApiDocument = <Value>(value: Value): value is Value & ApiDocument =>
|
|
311
317
|
typeof value === "object" && value !== null;
|
|
312
318
|
|
|
319
|
+
/**
|
|
320
|
+
* Read a spec and apply its overlays, in order, to the parsed document as
|
|
321
|
+
* written (before any upgrade: an overlay targets its spec's own version).
|
|
322
|
+
* The overlays are read like the spec, local or remote, cached alike.
|
|
323
|
+
*/
|
|
324
|
+
const readOverlaid = async (
|
|
325
|
+
spec: string,
|
|
326
|
+
root: string,
|
|
327
|
+
options: SpecFetchOptions
|
|
328
|
+
): Promise<{ document: ReturnType<typeof normalize>; warnings: string[] }> => {
|
|
329
|
+
const [read, ...overlays] = await Promise.all(
|
|
330
|
+
[spec, ...(options.overlays ?? [])].map((path) =>
|
|
331
|
+
readSpecText(path, root, options)
|
|
332
|
+
)
|
|
333
|
+
);
|
|
334
|
+
const document = normalize(read?.text ?? "");
|
|
335
|
+
for (const [index, overlay] of overlays.entries()) {
|
|
336
|
+
const name = options.overlays?.[index] ?? "";
|
|
337
|
+
const parsed = overlayDocument(normalize(overlay.text), name);
|
|
338
|
+
// A spec that isn't a mapping has nothing to overlay; the caller
|
|
339
|
+
// rejects it as it would without overlays.
|
|
340
|
+
if (isJsonObject(document)) {
|
|
341
|
+
applyOverlay(document, parsed, name);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
document,
|
|
346
|
+
warnings: [read, ...overlays].flatMap((entry) => entry?.warnings ?? []),
|
|
347
|
+
};
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* A spec with its overlays applied, as JSON text: what the Scalar embed
|
|
352
|
+
* inlines, since it can't apply overlays itself.
|
|
353
|
+
*/
|
|
354
|
+
export const readOverlaidSpec = async (
|
|
355
|
+
spec: string,
|
|
356
|
+
root: string,
|
|
357
|
+
options: SpecFetchOptions
|
|
358
|
+
): Promise<{ text: string; warnings: string[] }> => {
|
|
359
|
+
const { document, warnings } = await readOverlaid(spec, root, options);
|
|
360
|
+
return { text: JSON.stringify(document), warnings };
|
|
361
|
+
};
|
|
362
|
+
|
|
313
363
|
export const parseSpec = async (
|
|
314
364
|
spec: string,
|
|
315
365
|
root: string,
|
|
316
366
|
options: SpecFetchOptions = {}
|
|
317
367
|
): Promise<ParsedSpec> => {
|
|
318
|
-
const {
|
|
319
|
-
|
|
368
|
+
const { document: normalized, warnings } = await readOverlaid(
|
|
369
|
+
spec,
|
|
370
|
+
root,
|
|
371
|
+
options
|
|
372
|
+
);
|
|
320
373
|
const { specification } = upgrade(normalized);
|
|
321
374
|
// Reject a non-mapping here so the renderer never sees a non-document.
|
|
322
375
|
if (!isApiDocument(specification)) {
|
package/src/openapi/proxy.ts
CHANGED
|
@@ -12,25 +12,52 @@
|
|
|
12
12
|
* network and stays safe to bundle into the generated endpoint file.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
import { PROXY_HEADERS_HEADER } from "../components/openapi/request.ts";
|
|
15
16
|
import { readCappedBody } from "../core/request-body.ts";
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
|
-
* Request headers never forwarded upstream
|
|
19
|
-
* connection (not the upstream one),
|
|
20
|
-
* misattribute the docs site,
|
|
21
|
-
* to an arbitrary target
|
|
22
|
-
* by the
|
|
19
|
+
* Request headers never forwarded upstream, even when the playground names
|
|
20
|
+
* them: hop-by-hop headers describe this connection (not the upstream one),
|
|
21
|
+
* `host`/`origin`/`referer` would leak or misattribute the docs site, `cookie`
|
|
22
|
+
* would forward reader credentials to an arbitrary target, and the rest are
|
|
23
|
+
* set or rewritten by the platform in front of the docs server — the
|
|
24
|
+
* reader's address, the edge's own identity — whatever the browser sent.
|
|
25
|
+
* `accept-encoding`/`content-length` are recomputed by the runtime's own
|
|
26
|
+
* fetch.
|
|
23
27
|
*/
|
|
24
28
|
const REQUEST_DROP = {
|
|
25
29
|
"accept-encoding": true,
|
|
30
|
+
"cdn-loop": true,
|
|
26
31
|
connection: true,
|
|
27
32
|
"content-length": true,
|
|
28
33
|
cookie: true,
|
|
34
|
+
forwarded: true,
|
|
29
35
|
host: true,
|
|
36
|
+
"keep-alive": true,
|
|
30
37
|
origin: true,
|
|
38
|
+
"proxy-authorization": true,
|
|
31
39
|
referer: true,
|
|
40
|
+
te: true,
|
|
41
|
+
trailer: true,
|
|
42
|
+
"transfer-encoding": true,
|
|
43
|
+
"true-client-ip": true,
|
|
44
|
+
upgrade: true,
|
|
45
|
+
via: true,
|
|
46
|
+
"x-client-ip": true,
|
|
47
|
+
"x-real-ip": true,
|
|
32
48
|
} satisfies Record<string, true>;
|
|
33
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Platform header families, dropped like {@link REQUEST_DROP}: Cloudflare's
|
|
52
|
+
* (`cf-connecting-ip`, the Access `cf-access-jwt-assertion`), the
|
|
53
|
+
* `x-forwarded-*` set, Vercel's (`x-vercel-oidc-token`), Netlify's, Fly's,
|
|
54
|
+
* and AWS load balancers' (`x-amzn-oidc-data`).
|
|
55
|
+
*/
|
|
56
|
+
const PLATFORM_HEADER = /^(?:cf-|x-forwarded-|x-vercel-|x-nf-|fly-|x-amzn-)/u;
|
|
57
|
+
|
|
58
|
+
/** The {@link PROXY_HEADERS_HEADER} name as `Headers` iterates it. */
|
|
59
|
+
const DECLARED = PROXY_HEADERS_HEADER.toLowerCase();
|
|
60
|
+
|
|
34
61
|
/**
|
|
35
62
|
* Upstream response headers never returned to the browser: the runtime's
|
|
36
63
|
* fetch already decoded the body (so `content-encoding`/`content-length` no
|
|
@@ -99,20 +126,45 @@ const DOCUMENT_TYPE =
|
|
|
99
126
|
const badRequest = (error: string): Response =>
|
|
100
127
|
Response.json({ error }, { status: 400 });
|
|
101
128
|
|
|
102
|
-
/**
|
|
129
|
+
/**
|
|
130
|
+
* Copy headers, skipping the given denylist and any name `keep` rejects
|
|
131
|
+
* (names are already lowercase).
|
|
132
|
+
*/
|
|
103
133
|
const filterHeaders = (
|
|
104
134
|
source: Headers,
|
|
105
|
-
drop: Record<string, true
|
|
135
|
+
drop: Record<string, true>,
|
|
136
|
+
keep: (name: string) => boolean = () => true
|
|
106
137
|
): Headers => {
|
|
107
138
|
const headers = new Headers();
|
|
108
139
|
for (const [name, value] of source) {
|
|
109
|
-
if (!drop[name]) {
|
|
140
|
+
if (!drop[name] && keep(name)) {
|
|
110
141
|
headers.set(name, value);
|
|
111
142
|
}
|
|
112
143
|
}
|
|
113
144
|
return headers;
|
|
114
145
|
};
|
|
115
146
|
|
|
147
|
+
/**
|
|
148
|
+
* The headers to send upstream: only those the playground set itself, which
|
|
149
|
+
* it names in {@link PROXY_HEADERS_HEADER}. Forwarding everything else minus
|
|
150
|
+
* a denylist would hand the documented API whatever the browser and the
|
|
151
|
+
* platform attach on their own — the HTTP Basic credentials of a docs site
|
|
152
|
+
* behind a password (a same-origin fetch with no `Authorization` of its own
|
|
153
|
+
* carries them), a Cloudflare Access assertion, a Vercel OIDC token.
|
|
154
|
+
*/
|
|
155
|
+
const forwardedHeaders = (source: Headers): Headers => {
|
|
156
|
+
const named = new Set(
|
|
157
|
+
(source.get(DECLARED) ?? "")
|
|
158
|
+
.split(",")
|
|
159
|
+
.map((name) => name.trim().toLowerCase())
|
|
160
|
+
);
|
|
161
|
+
return filterHeaders(
|
|
162
|
+
source,
|
|
163
|
+
REQUEST_DROP,
|
|
164
|
+
(name) => named.has(name) && !PLATFORM_HEADER.test(name)
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
|
|
116
168
|
/** A 403 for a target no configured spec declares as one of its servers. */
|
|
117
169
|
const forbidden = (origin: string): Response =>
|
|
118
170
|
Response.json(
|
|
@@ -186,7 +238,8 @@ const followUpstream = async (args: {
|
|
|
186
238
|
/**
|
|
187
239
|
* Build the `/_api-proxy` fetch handler. The client sends its REAL method,
|
|
188
240
|
* headers, and body to `?url=<encodeURIComponent(target)>`; the handler
|
|
189
|
-
* forwards
|
|
241
|
+
* forwards the method, the body, and the headers the client names (see
|
|
242
|
+
* {@link forwardedHeaders}), and mirrors the upstream response
|
|
190
243
|
* (minus {@link RESPONSE_DROP}) with an `x-blume-proxy` marker. An unreachable
|
|
191
244
|
* upstream is a 502 with a JSON `error`.
|
|
192
245
|
*
|
|
@@ -252,7 +305,7 @@ export const createPlaygroundProxyHandler = (
|
|
|
252
305
|
allowed,
|
|
253
306
|
body,
|
|
254
307
|
fetchImpl,
|
|
255
|
-
headers:
|
|
308
|
+
headers: forwardedHeaders(request.headers),
|
|
256
309
|
hop: 0,
|
|
257
310
|
method: request.method,
|
|
258
311
|
signal: AbortSignal.timeout(timeoutMs),
|
|
@@ -28,8 +28,8 @@ export type BlumeReferenceKind = Exclude<ReferenceKind, "scalar">;
|
|
|
28
28
|
|
|
29
29
|
/** Per-adapter display options for the Blume renderer. */
|
|
30
30
|
export interface ReferenceDisplay {
|
|
31
|
-
/** Code-sample languages shown per operation. */
|
|
32
|
-
codeSamples: string[];
|
|
31
|
+
/** Code-sample languages shown per operation; `false` for none. */
|
|
32
|
+
codeSamples: string[] | false;
|
|
33
33
|
/** Whether nested schema rows start expanded. */
|
|
34
34
|
expandSchemas: boolean;
|
|
35
35
|
/**
|
|
@@ -67,6 +67,11 @@ export interface ReferenceSource {
|
|
|
67
67
|
seoDescriptionSuffix: boolean;
|
|
68
68
|
/** Local path or `http(s)` URL, verbatim from config. */
|
|
69
69
|
spec: string;
|
|
70
|
+
/**
|
|
71
|
+
* OpenAPI Overlay documents applied to `spec` in order (`openapi()` and
|
|
72
|
+
* `scalar()` only).
|
|
73
|
+
*/
|
|
74
|
+
overlays?: string[];
|
|
70
75
|
/**
|
|
71
76
|
* URL of the live GraphQL endpoint the playground and code samples target
|
|
72
77
|
* (GraphQL only — a schema, unlike an OpenAPI document, names no server).
|
|
@@ -184,6 +189,7 @@ interface SourceRow {
|
|
|
184
189
|
route?: string;
|
|
185
190
|
seoDescriptionSuffix: boolean;
|
|
186
191
|
spec: string;
|
|
192
|
+
overlays?: string[];
|
|
187
193
|
}
|
|
188
194
|
|
|
189
195
|
/**
|
|
@@ -255,6 +261,9 @@ const referencesFor = (
|
|
|
255
261
|
if (source.endpoint !== undefined) {
|
|
256
262
|
reference.endpoint = source.endpoint;
|
|
257
263
|
}
|
|
264
|
+
if (source.overlays !== undefined) {
|
|
265
|
+
reference.overlays = source.overlays;
|
|
266
|
+
}
|
|
258
267
|
return reference;
|
|
259
268
|
});
|
|
260
269
|
};
|
|
@@ -363,11 +372,18 @@ export const builtinProxyReferences = (
|
|
|
363
372
|
ref.display.playground.proxy === true
|
|
364
373
|
);
|
|
365
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Whether hand-written endpoint pages (`api` frontmatter) send their Try it
|
|
377
|
+
* requests through the built-in proxy: `api.playground.proxy: true`.
|
|
378
|
+
*/
|
|
379
|
+
export const apiPagesUseBuiltinProxy = (config: ResolvedConfig): boolean =>
|
|
380
|
+
config.api.playground.enabled && config.api.playground.proxy === true;
|
|
381
|
+
|
|
366
382
|
/**
|
|
367
383
|
* Whether the built-in playground CORS proxy endpoint (`/_api-proxy`) must be
|
|
368
384
|
* generated: some Blume-rendered reference's playground opted into it with
|
|
369
|
-
* `proxy: true
|
|
370
|
-
* two can never disagree.
|
|
385
|
+
* `proxy: true`, or the hand-written endpoint pages' did. Shared by the server
|
|
386
|
+
* feature gate and the generator so the two can never disagree.
|
|
371
387
|
*/
|
|
372
388
|
export const needsPlaygroundProxy = (config: ResolvedConfig): boolean =>
|
|
373
|
-
builtinProxyReferences(config).length > 0;
|
|
389
|
+
builtinProxyReferences(config).length > 0 || apiPagesUseBuiltinProxy(config);
|
|
@@ -126,6 +126,45 @@ const mdxSafe = (text: string): string => {
|
|
|
126
126
|
return out + escapeProse(text.slice(cursor));
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
+
// A fence opener: up to three columns of indentation, then a run of three or
|
|
130
|
+
// more backticks or tildes.
|
|
131
|
+
const FENCE_OPEN = /^ {0,3}(?<fence>`{3,}|~{3,})/u;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Close a fenced code block the text leaves open. An unclosed fence runs to
|
|
135
|
+
* the end of the document, so the component appended after a description
|
|
136
|
+
* would render as code, and the page would lose its parameters, responses,
|
|
137
|
+
* and playground. Only the last top-level block can run that far — a fence in
|
|
138
|
+
* a quote or list closes with its container — and it's read from the same
|
|
139
|
+
* `<`-masked parse as `mdxSafe`, since the emitted MDX has no HTML blocks to
|
|
140
|
+
* hide a fence in.
|
|
141
|
+
*/
|
|
142
|
+
const closeOpenFence = (text: string): string => {
|
|
143
|
+
const last = fromMarkdown(text.replaceAll("<", HTML_MASK)).children.at(-1);
|
|
144
|
+
if (last?.type !== "code") {
|
|
145
|
+
return text;
|
|
146
|
+
}
|
|
147
|
+
// fromMarkdown always stamps positions; 0 is an unreachable guard.
|
|
148
|
+
const block = text.slice(last.position?.start.offset ?? 0);
|
|
149
|
+
const fence = FENCE_OPEN.exec(block)?.groups?.fence;
|
|
150
|
+
// No fence: indented code, which MDX reads as a paragraph.
|
|
151
|
+
if (!fence) {
|
|
152
|
+
return text;
|
|
153
|
+
}
|
|
154
|
+
const lines = block.split("\n");
|
|
155
|
+
const closer = new RegExp(
|
|
156
|
+
`^ {0,3}${fence[0]}{${fence.length},}[ \\t\\r]*$`,
|
|
157
|
+
"u"
|
|
158
|
+
);
|
|
159
|
+
return lines.length > 1 && closer.test(lines.at(-1) ?? "")
|
|
160
|
+
? text
|
|
161
|
+
: `${text}\n${fence}`;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/** Spec prose as MDX that is safe to follow with a component. */
|
|
165
|
+
const descriptionMdx = (text: string): string =>
|
|
166
|
+
mdxSafe(closeOpenFence(text.trim()));
|
|
167
|
+
|
|
129
168
|
/**
|
|
130
169
|
* Frontmatter emitted for one operation or overview page. Boolean flags are
|
|
131
170
|
* assigned only when set, so absent keys stay absent in the staged MDX.
|
|
@@ -231,7 +270,8 @@ const operationDescription = (
|
|
|
231
270
|
// method (see `extractGraphqlOperations`).
|
|
232
271
|
subject = `${operation.path} ${GRAPHQL_MEMBER_PHRASES[operation.method as GraphqlMember]}`;
|
|
233
272
|
} else {
|
|
234
|
-
|
|
273
|
+
// A webhook is a request the API sends, named rather than pathed.
|
|
274
|
+
subject = `${operation.method.toUpperCase()} ${operation.path} ${operation.webhook ? "webhook" : "endpoint"}`;
|
|
235
275
|
}
|
|
236
276
|
const suffix = `Reference for the ${subject} in the ${apiPhrase(spec)}.`;
|
|
237
277
|
// Room for the joining space and the period `asSentence` may add, so a
|
|
@@ -249,7 +289,7 @@ const operationDescription = (
|
|
|
249
289
|
/** Prepend a markdown description (if any) above a component invocation. */
|
|
250
290
|
const withDescription = (description: string, component: string): string =>
|
|
251
291
|
description.trim()
|
|
252
|
-
? `${
|
|
292
|
+
? `${descriptionMdx(description)}\n\n${component}`
|
|
253
293
|
: component;
|
|
254
294
|
|
|
255
295
|
export const operationMdx = (
|
|
@@ -309,6 +349,9 @@ export const operationMdx = (
|
|
|
309
349
|
sidebar.badge = method;
|
|
310
350
|
}
|
|
311
351
|
const tags = graphql ? [operation.tag] : [operation.tag, method];
|
|
352
|
+
if (operation.webhook) {
|
|
353
|
+
tags.push("Webhook");
|
|
354
|
+
}
|
|
312
355
|
return {
|
|
313
356
|
body: withDescription(
|
|
314
357
|
description,
|
|
@@ -365,7 +408,7 @@ export const overviewMdx = (
|
|
|
365
408
|
continue;
|
|
366
409
|
}
|
|
367
410
|
const description = tag.description.trim()
|
|
368
|
-
? [
|
|
411
|
+
? [descriptionMdx(tag.description)]
|
|
369
412
|
: [];
|
|
370
413
|
tagSections.push(
|
|
371
414
|
[
|
package/src/openapi/scalar.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { scalarReferenceTemplate } from "../astro/templates.ts";
|
|
|
6
6
|
import type { ResolvedConfig } from "../core/schema.ts";
|
|
7
7
|
import { trimChar } from "../core/trim.ts";
|
|
8
8
|
import { resolveAccent, resolveRadius } from "../theme/palette.ts";
|
|
9
|
+
import { readOverlaidSpec } from "./parse.ts";
|
|
9
10
|
import { resolveReferences } from "./references.ts";
|
|
10
11
|
import type { ReferenceSource } from "./references.ts";
|
|
11
12
|
|
|
@@ -53,14 +54,44 @@ const themeConfiguration = (config: ResolvedConfig, override?: string) => {
|
|
|
53
54
|
};
|
|
54
55
|
};
|
|
55
56
|
|
|
57
|
+
/** A source's Scalar spec config, or none when its overlays failed. */
|
|
58
|
+
interface SpecConfiguration {
|
|
59
|
+
config?: { content: string } | { url: string };
|
|
60
|
+
warning?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The spec with its overlays applied, inlined: Scalar can't apply overlays
|
|
65
|
+
* itself. A failed overlay skips the page rather than embed the spec without
|
|
66
|
+
* it, since an overlay is often what hides the internal operations.
|
|
67
|
+
*/
|
|
68
|
+
const overlaidConfiguration = async (
|
|
69
|
+
ref: ReferenceSource,
|
|
70
|
+
root: string
|
|
71
|
+
): Promise<SpecConfiguration> => {
|
|
72
|
+
try {
|
|
73
|
+
const { text, warnings } = await readOverlaidSpec(ref.spec, root, {
|
|
74
|
+
overlays: ref.overlays,
|
|
75
|
+
});
|
|
76
|
+
return { config: { content: text }, warning: warnings[0] };
|
|
77
|
+
} catch (error) {
|
|
78
|
+
// SAFETY: reading, parsing, and overlaying throw Error instances.
|
|
79
|
+
const { message } = error as Error;
|
|
80
|
+
return {
|
|
81
|
+
warning: `API reference ${ref.route} was skipped: its overlays couldn't be applied to "${ref.spec}" (${message}).`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
56
86
|
/** Build the Scalar spec config for a source: inline `content` or remote `url`. */
|
|
57
87
|
const specConfiguration = async (
|
|
58
|
-
|
|
88
|
+
ref: ReferenceSource,
|
|
59
89
|
root: string
|
|
60
|
-
): Promise<{
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
90
|
+
): Promise<SpecConfiguration> => {
|
|
91
|
+
const { spec } = ref;
|
|
92
|
+
if (ref.overlays?.length) {
|
|
93
|
+
return await overlaidConfiguration(ref, root);
|
|
94
|
+
}
|
|
64
95
|
if (URL_SPEC.test(spec)) {
|
|
65
96
|
return { config: { url: spec } };
|
|
66
97
|
}
|
|
@@ -133,7 +164,7 @@ export const buildReferenceFiles = async (options: {
|
|
|
133
164
|
const built = await Promise.all(
|
|
134
165
|
accepted.map(async (ref) => ({
|
|
135
166
|
ref,
|
|
136
|
-
spec: await specConfiguration(ref
|
|
167
|
+
spec: await specConfiguration(ref, root),
|
|
137
168
|
}))
|
|
138
169
|
);
|
|
139
170
|
|
|
@@ -142,6 +173,9 @@ export const buildReferenceFiles = async (options: {
|
|
|
142
173
|
if (spec.warning) {
|
|
143
174
|
warnings.push(spec.warning);
|
|
144
175
|
}
|
|
176
|
+
if (!spec.config) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
145
179
|
const pagePath = referencePagePath(ref.route);
|
|
146
180
|
// `theme` is the one option Blume maps (a named theme replaces the
|
|
147
181
|
// accent/radius layering); every other `scalar()` option is forwarded
|