blume 2.0.1 → 2.0.3
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 +147 -0
- package/dist/cli/{chunk-qwsrynx5.js → chunk-1d7ve1dm.js} +38 -19
- package/dist/cli/{chunk-qwsrynx5.js.map → chunk-1d7ve1dm.js.map} +4 -4
- package/dist/cli/{chunk-s6jhgk0q.js → chunk-2eytanqx.js} +2 -2
- package/dist/cli/{chunk-kdp5q7ke.js → chunk-2hsdwb9n.js} +18 -19
- package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-2hsdwb9n.js.map} +2 -2
- package/dist/cli/{chunk-hdpx1tax.js → chunk-2z928egk.js} +5 -5
- package/dist/cli/{chunk-jwyddg7y.js → chunk-35d4wj9f.js} +30 -24
- package/dist/cli/chunk-35d4wj9f.js.map +15 -0
- package/dist/cli/{chunk-ah61y8py.js → chunk-364znk6q.js} +2 -2
- package/dist/cli/{chunk-jts8mvcz.js → chunk-3em5wd2y.js} +25 -6
- package/dist/cli/{chunk-jts8mvcz.js.map → chunk-3em5wd2y.js.map} +3 -3
- package/dist/cli/{chunk-s1p84fyh.js → chunk-5f86nr5m.js} +63 -22
- package/dist/cli/chunk-5f86nr5m.js.map +11 -0
- package/dist/cli/{chunk-2hn4b8z7.js → chunk-5m5nmvyq.js} +170 -76
- package/dist/cli/chunk-5m5nmvyq.js.map +13 -0
- package/dist/cli/{chunk-epjnccmv.js → chunk-5xvm6tfj.js} +18 -15
- package/dist/cli/chunk-5xvm6tfj.js.map +10 -0
- package/dist/cli/{chunk-fz5wtpmh.js → chunk-6dsbexzp.js} +18 -15
- package/dist/cli/chunk-6dsbexzp.js.map +10 -0
- package/dist/cli/{chunk-vtk4a6dg.js → chunk-8ktnccpt.js} +1 -1
- package/dist/cli/{chunk-6hsn950k.js → chunk-9t7a85s3.js} +178 -48
- package/dist/cli/chunk-9t7a85s3.js.map +10 -0
- package/dist/cli/{chunk-fxypxtvm.js → chunk-a58773jm.js} +2 -2
- package/dist/cli/{chunk-mb2919y2.js → chunk-acanzt5p.js} +17 -6
- package/dist/cli/chunk-acanzt5p.js.map +10 -0
- package/dist/cli/{chunk-27g6wdth.js → chunk-akbpwfxc.js} +90 -26
- package/dist/cli/chunk-akbpwfxc.js.map +10 -0
- package/dist/cli/{chunk-wm7js3j9.js → chunk-b07cmahc.js} +2 -2
- package/dist/cli/{chunk-wgm7m9qk.js → chunk-c8chx29p.js} +179 -51
- package/dist/cli/chunk-c8chx29p.js.map +36 -0
- package/dist/cli/{chunk-qs4q5p4e.js → chunk-crgn1q09.js} +32 -14
- package/dist/cli/chunk-crgn1q09.js.map +10 -0
- package/dist/cli/chunk-e04dxsz1.js +39 -0
- package/dist/cli/chunk-e04dxsz1.js.map +10 -0
- package/dist/cli/{chunk-yt5n7ppj.js → chunk-ey84smr6.js} +17 -7
- package/dist/cli/chunk-ey84smr6.js.map +10 -0
- package/dist/cli/{chunk-f2z5v128.js → chunk-g4hq16wv.js} +14 -15
- package/dist/cli/{chunk-f2z5v128.js.map → chunk-g4hq16wv.js.map} +2 -2
- package/dist/cli/{chunk-fa25z98p.js → chunk-ga0pf4aj.js} +9 -8
- package/dist/cli/chunk-ga0pf4aj.js.map +11 -0
- package/dist/cli/{chunk-kpf8rrjc.js → chunk-hm3vjy5s.js} +109 -58
- package/dist/cli/chunk-hm3vjy5s.js.map +19 -0
- package/dist/cli/{chunk-fs23ddbb.js → chunk-j85vccga.js} +625 -750
- package/dist/cli/chunk-j85vccga.js.map +36 -0
- package/dist/cli/{chunk-ch6g3ar0.js → chunk-p3v96n38.js} +6 -6
- package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-p3v96n38.js.map} +3 -3
- package/dist/cli/{chunk-q5163e60.js → chunk-p73c0m7w.js} +21 -19
- package/dist/cli/chunk-p73c0m7w.js.map +11 -0
- package/dist/cli/{chunk-dh8cwk36.js → chunk-pehfxfta.js} +24 -9
- package/dist/cli/chunk-pehfxfta.js.map +10 -0
- package/dist/cli/{chunk-qkqwkpte.js → chunk-pv29h0wf.js} +3688 -1313
- package/dist/cli/chunk-pv29h0wf.js.map +190 -0
- package/dist/cli/{chunk-6vm74dry.js → chunk-q58y5e6a.js} +10 -10
- package/dist/cli/{chunk-6vm74dry.js.map → chunk-q58y5e6a.js.map} +3 -3
- package/dist/cli/{chunk-zxcczpyx.js → chunk-r20tn01b.js} +1 -1
- package/dist/cli/{chunk-m3vmjgmq.js → chunk-r9rcc4w7.js} +16 -8
- package/dist/cli/chunk-r9rcc4w7.js.map +10 -0
- package/dist/cli/{chunk-5shv93fd.js → chunk-tkacnehg.js} +2 -2
- package/dist/cli/{chunk-zxh4d9vy.js → chunk-tzmab476.js} +4 -4
- package/dist/cli/{chunk-yw7dm696.js → chunk-vg9r4eb9.js} +24 -11
- package/dist/cli/chunk-vg9r4eb9.js.map +14 -0
- package/dist/cli/{chunk-79jhk4py.js → chunk-wrr3j9w9.js} +260 -132
- package/dist/cli/chunk-wrr3j9w9.js.map +35 -0
- package/dist/cli/{chunk-6crbhc3x.js → chunk-yfyb25rh.js} +54 -27
- package/dist/cli/chunk-yfyb25rh.js.map +14 -0
- package/dist/cli/index.js +162 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +7 -0
- package/dist/types/ai/component-markdown.d.ts +4 -4
- 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 +11 -4
- package/dist/types/ai/skills.d.ts +4 -1
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/ai/tar.d.ts +1 -3
- package/dist/types/analytics/databuddy.d.ts +43 -0
- package/dist/types/analytics/index.d.ts +4 -0
- package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
- package/dist/types/analytics/schema.d.ts +28 -0
- package/dist/types/astro/integration.d.ts +3 -2
- package/dist/types/cli/env.d.ts +5 -0
- package/dist/types/cli/init/scaffold.d.ts +19 -3
- package/dist/types/cli/init/starter-spec.d.ts +11 -0
- package/dist/types/core/base-path.d.ts +24 -1
- package/dist/types/core/config-input.d.ts +13 -11
- package/dist/types/core/config.d.ts +2 -2
- package/dist/types/core/directive-diagnostics.d.ts +12 -0
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/heading-markers.d.ts +5 -7
- package/dist/types/core/i18n-ui.d.ts +31 -0
- package/dist/types/core/i18n.d.ts +9 -1
- package/dist/types/core/last-modified.d.ts +10 -0
- package/dist/types/core/links.d.ts +3 -1
- package/dist/types/core/load-module.d.ts +10 -0
- package/dist/types/core/locale-links.d.ts +12 -2
- package/dist/types/core/meta.d.ts +13 -1
- package/dist/types/core/nav-diagnostics.d.ts +10 -0
- package/dist/types/core/navigation.d.ts +38 -0
- package/dist/types/core/ordering-prefix.d.ts +4 -0
- package/dist/types/core/safe-links.d.ts +3 -1
- package/dist/types/core/schema.d.ts +59 -13
- package/dist/types/core/sources/github-releases.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +38 -13
- package/dist/types/core/sources/normalize.d.ts +23 -2
- package/dist/types/core/sources/remote.d.ts +11 -1
- package/dist/types/core/sources/resolve.d.ts +12 -0
- package/dist/types/core/sources/types.d.ts +31 -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 +9 -0
- package/dist/types/deploy/adapters/node.d.ts +5 -2
- package/dist/types/deploy/adapters/types.d.ts +7 -0
- package/dist/types/deploy/artifacts.d.ts +6 -4
- package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
- package/dist/types/deploy/headers.d.ts +36 -7
- package/dist/types/deploy/node-headers.d.ts +43 -8
- package/dist/types/deploy/platforms/netlify.d.ts +27 -2
- package/dist/types/deploy/platforms/node.d.ts +6 -5
- package/dist/types/deploy/platforms/types.d.ts +15 -0
- package/dist/types/deploy/platforms/vercel.d.ts +3 -2
- package/dist/types/deploy/redirects.d.ts +31 -15
- package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
- package/dist/types/markdown/directives.d.ts +62 -0
- package/dist/types/markdown/features.d.ts +21 -0
- package/dist/types/markdown/mdast.d.ts +63 -0
- package/dist/types/openapi/asyncapi.d.ts +4 -2
- package/dist/types/openapi/model.d.ts +20 -6
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +20 -9
- package/docs/08-faq.mdx +10 -3
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +7 -5
- package/docs/cli/audit.mdx +19 -3
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +4 -1
- package/docs/cli/translate.mdx +4 -4
- package/docs/cli/version.mdx +1 -1
- package/docs/configuration/analytics.mdx +42 -2
- package/docs/configuration/assistant.mdx +1 -1
- package/docs/configuration/customization.mdx +6 -3
- package/docs/configuration/index.mdx +5 -3
- package/docs/configuration/search.mdx +2 -2
- package/docs/content/components.mdx +2 -2
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +3 -1
- package/docs/content/index.mdx +8 -4
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +7 -3
- package/docs/content/navigation.mdx +29 -4
- package/docs/content/sources.mdx +18 -16
- package/docs/content/syntax.mdx +14 -0
- package/docs/content/versioning.mdx +2 -1
- package/docs/discoverability/agent-discovery.mdx +22 -8
- package/docs/discoverability/index.mdx +4 -3
- package/docs/discoverability/llms-txt.mdx +2 -5
- package/docs/discoverability/markdown.mdx +6 -4
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +3 -2
- package/docs/discoverability/open-graph.mdx +8 -4
- package/docs/discoverability/rss.mdx +4 -2
- package/docs/references/asyncapi.mdx +2 -2
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/openapi.mdx +6 -4
- package/package.json +1 -1
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +6 -6
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +3 -3
- package/skills/blume-migrate/references/monorepo.md +1 -1
- package/skills/blume-migrate/references/nextra.md +2 -2
- package/skills/blume-migrate/references/starlight.md +5 -5
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +9 -4
- package/skills/blume-update-docs/references/audit-checklist.md +1 -1
- package/src/ai/agent-readability.ts +2 -2
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/ai-catalog.ts +6 -2
- package/src/ai/api/handlers.ts +2 -2
- package/src/ai/api/spec.ts +17 -4
- package/src/ai/api-catalog.ts +13 -3
- package/src/ai/ask-context.ts +14 -2
- package/src/ai/ask-data.ts +26 -12
- package/src/ai/changelog-markdown.ts +2 -2
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/link-headers.ts +22 -8
- package/src/ai/llms.ts +22 -10
- package/src/ai/markdown.ts +23 -11
- package/src/ai/mcp/discovery.ts +2 -2
- package/src/ai/mcp/query.ts +2 -2
- package/src/ai/mcp/server.ts +80 -9
- package/src/ai/openapi-components.ts +22 -6
- package/src/ai/relative-links.ts +99 -15
- package/src/ai/serializers.ts +2 -1
- package/src/ai/skills.ts +14 -1
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/tar.ts +139 -12
- package/src/ai/visibility.ts +45 -14
- package/src/analytics/databuddy.ts +67 -0
- package/src/analytics/head.ts +8 -0
- package/src/analytics/index.ts +7 -0
- package/src/analytics/one-dollar-stats.ts +86 -0
- package/src/analytics/posthog.ts +21 -3
- package/src/analytics/schema.ts +4 -0
- package/src/astro/generate.ts +72 -28
- package/src/astro/include-hmr.ts +31 -12
- package/src/astro/include-refresh.ts +19 -8
- package/src/astro/integration.ts +108 -14
- package/src/astro/runtime-modules.ts +28 -13
- package/src/astro/templates.ts +139 -57
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +25 -5
- package/src/audit/checks/content.ts +20 -2
- package/src/audit/checks/i18n.ts +46 -8
- package/src/audit/checks/indexability.ts +39 -19
- package/src/audit/checks/links.ts +22 -1
- package/src/audit/checks/llms.ts +6 -3
- package/src/audit/checks/network.ts +3 -1
- package/src/audit/checks/og-image.ts +10 -0
- package/src/audit/checks/robots.ts +6 -1
- package/src/audit/checks/sitemap.ts +56 -31
- package/src/audit/checks/social.ts +21 -2
- package/src/audit/crawl.ts +88 -15
- package/src/audit/graph.ts +3 -1
- package/src/audit/report.ts +54 -17
- package/src/audit/run.ts +13 -9
- package/src/audit/snapshot.ts +5 -0
- package/src/audit/types.ts +18 -0
- package/src/audit/url.ts +37 -6
- package/src/cli/args.ts +32 -0
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +11 -1
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/doctor.ts +3 -1
- package/src/cli/commands/eval.ts +20 -18
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +18 -18
- package/src/cli/commands/upgrade.ts +11 -0
- package/src/cli/commands/validate.ts +3 -1
- package/src/cli/dev-lock.ts +157 -37
- package/src/cli/eject-scripts.ts +32 -7
- package/src/cli/env.ts +12 -1
- package/src/cli/init/scaffold.ts +117 -11
- package/src/cli/init/starter-spec.ts +235 -0
- package/src/cli/report-format.ts +11 -6
- package/src/components/colors.ts +19 -0
- package/src/components/content/AccordionItem.astro +26 -22
- package/src/components/content/Badge.astro +7 -12
- package/src/components/content/Card.astro +2 -2
- package/src/components/content/Component.astro +11 -5
- package/src/components/content/Expandable.astro +5 -1
- package/src/components/content/Frame.astro +2 -7
- package/src/components/content/GithubInfo.astro +12 -2
- package/src/components/content/Prompt.astro +2 -7
- package/src/components/content/Tab.astro +0 -1
- package/src/components/content/Tabs.astro +58 -5
- package/src/components/content/Tile.astro +1 -1
- package/src/components/content/Tooltip.astro +69 -7
- package/src/components/content/Tree.astro +7 -2
- package/src/components/content/TypeTable.astro +10 -5
- package/src/components/content/Update.astro +8 -2
- package/src/components/content/auto-type-table.ts +4 -1
- package/src/components/content/badge-color.ts +20 -0
- package/src/components/content/base-href.ts +14 -22
- package/src/components/content/inline-markdown.ts +27 -7
- package/src/components/copy-feedback.ts +35 -8
- package/src/components/islands/assistant.tsx +37 -6
- package/src/components/islands/base-path.ts +47 -10
- package/src/components/islands/hooks.ts +42 -21
- package/src/components/islands/webmcp.ts +16 -10
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Breadcrumbs.astro +5 -2
- package/src/components/layout/DiscoveryLinks.astro +9 -5
- package/src/components/layout/Header.astro +23 -10
- package/src/components/layout/LanguageSwitcher.astro +2 -2
- package/src/components/layout/Logo.astro +5 -0
- package/src/components/layout/NavSelector.astro +8 -3
- package/src/components/layout/NavTabMenu.astro +133 -0
- package/src/components/layout/NavTree.astro +31 -12
- package/src/components/layout/NavTreeCache.astro +5 -2
- package/src/components/layout/NavTreeScript.astro +45 -5
- package/src/components/layout/PageActions.astro +4 -3
- package/src/components/layout/PageLayout.astro +28 -13
- package/src/components/layout/Pagination.astro +3 -3
- package/src/components/layout/ReferenceLayout.astro +4 -1
- package/src/components/layout/RootLayout.astro +25 -12
- package/src/components/layout/Search.astro +38 -14
- package/src/components/layout/VersionBanner.astro +2 -2
- package/src/components/layout/analytics-client.ts +14 -0
- 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/GraphqlType.astro +11 -3
- package/src/components/openapi/MessageComposer.astro +1 -1
- package/src/components/openapi/Operation.astro +23 -5
- package/src/components/openapi/PanelTabs.astro +4 -1
- package/src/components/openapi/Playground.astro +8 -2
- package/src/components/openapi/RequestPanel.astro +13 -6
- package/src/components/openapi/SchemaProperty.astro +11 -33
- package/src/components/openapi/SchemaTable.astro +34 -52
- package/src/components/openapi/async.ts +38 -6
- package/src/components/openapi/helpers.ts +100 -12
- package/src/components/openapi/message-composer.ts +14 -1
- package/src/components/openapi/message-model.ts +12 -2
- package/src/components/openapi/message.ts +21 -3
- package/src/components/openapi/operation-model.ts +119 -17
- package/src/components/openapi/panel.ts +31 -5
- package/src/components/openapi/param-style.ts +181 -0
- package/src/components/openapi/playground-client.ts +110 -23
- package/src/components/openapi/playground-schema.ts +25 -6
- package/src/components/openapi/request.ts +192 -26
- package/src/components/openapi/schema-tree.ts +209 -0
- package/src/components/openapi/snippets.ts +113 -19
- package/src/components/openapi/validate-json.ts +1 -1
- package/src/components/openapi/ws-client.ts +18 -2
- package/src/core/base-path.ts +69 -8
- package/src/core/config-input.ts +13 -11
- package/src/core/config.ts +18 -4
- package/src/core/diagnostics.ts +219 -30
- package/src/core/directive-diagnostics.ts +99 -0
- package/src/core/frontmatter.ts +21 -18
- package/src/core/graph.ts +120 -11
- package/src/core/heading-markers.ts +5 -18
- package/src/core/i18n-ui.ts +39 -2
- package/src/core/i18n.ts +44 -5
- package/src/core/last-modified.ts +25 -3
- package/src/core/links.ts +7 -4
- package/src/core/load-module.ts +20 -0
- package/src/core/locale-links.ts +22 -18
- package/src/core/manifest.ts +3 -2
- package/src/core/meta.ts +89 -12
- package/src/core/nav-diagnostics.ts +56 -1
- package/src/core/navigation.ts +272 -83
- package/src/core/ordering-prefix.ts +27 -0
- package/src/core/project-graph.ts +50 -6
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +94 -18
- package/src/core/sources/assets.ts +83 -41
- package/src/core/sources/contentful-rich-text.ts +28 -20
- package/src/core/sources/contentful.ts +25 -12
- package/src/core/sources/filesystem.ts +25 -3
- package/src/core/sources/github-releases.ts +131 -11
- package/src/core/sources/lexical.ts +30 -20
- package/src/core/sources/lower.ts +276 -56
- package/src/core/sources/mdx-remote.ts +52 -16
- package/src/core/sources/normalize.ts +456 -119
- package/src/core/sources/notion.ts +77 -34
- package/src/core/sources/obsidian.ts +40 -9
- package/src/core/sources/payload.ts +1 -0
- package/src/core/sources/portable-text.ts +85 -49
- package/src/core/sources/remote.ts +18 -2
- package/src/core/sources/resolve.ts +52 -33
- package/src/core/sources/sanity.ts +1 -0
- package/src/core/sources/strapi-blocks.ts +28 -19
- package/src/core/sources/strapi.ts +1 -0
- package/src/core/sources/types.ts +31 -0
- package/src/core/sources/watch.ts +20 -7
- package/src/core/standard-schema.ts +10 -6
- package/src/core/types.ts +9 -0
- package/src/core/ui-packs/ar.ts +13 -0
- package/src/core/ui-packs/bg.ts +13 -0
- package/src/core/ui-packs/bn.ts +13 -0
- package/src/core/ui-packs/ca.ts +13 -0
- package/src/core/ui-packs/cs.ts +13 -0
- package/src/core/ui-packs/da.ts +13 -0
- package/src/core/ui-packs/de.ts +13 -0
- package/src/core/ui-packs/el.ts +13 -0
- package/src/core/ui-packs/es.ts +13 -0
- package/src/core/ui-packs/fa.ts +13 -0
- package/src/core/ui-packs/fi.ts +13 -0
- package/src/core/ui-packs/fr.ts +13 -0
- package/src/core/ui-packs/he.ts +13 -0
- package/src/core/ui-packs/hi.ts +13 -0
- package/src/core/ui-packs/hr.ts +13 -0
- package/src/core/ui-packs/hu.ts +13 -0
- package/src/core/ui-packs/id.ts +13 -0
- package/src/core/ui-packs/it.ts +13 -0
- package/src/core/ui-packs/ja.ts +13 -0
- package/src/core/ui-packs/ko.ts +13 -0
- package/src/core/ui-packs/nl.ts +13 -0
- package/src/core/ui-packs/no.ts +13 -0
- package/src/core/ui-packs/pl.ts +13 -0
- package/src/core/ui-packs/pt-br.ts +13 -0
- package/src/core/ui-packs/pt.ts +13 -0
- package/src/core/ui-packs/ro.ts +13 -0
- package/src/core/ui-packs/ru.ts +13 -0
- package/src/core/ui-packs/sk.ts +13 -0
- package/src/core/ui-packs/sr.ts +13 -0
- package/src/core/ui-packs/sv.ts +13 -0
- package/src/core/ui-packs/th.ts +13 -0
- package/src/core/ui-packs/tr.ts +13 -0
- package/src/core/ui-packs/uk.ts +13 -0
- package/src/core/ui-packs/vi.ts +13 -0
- package/src/core/ui-packs/zh-tw.ts +13 -0
- package/src/core/ui-packs/zh.ts +13 -0
- package/src/core/version-cut.ts +69 -17
- package/src/core/versions.ts +4 -1
- package/src/deploy/adapters/node.ts +5 -2
- package/src/deploy/adapters/registry.ts +2 -1
- package/src/deploy/adapters/types.ts +13 -1
- package/src/deploy/artifacts.ts +52 -11
- package/src/deploy/cloudflare-negotiation.ts +27 -16
- package/src/deploy/headers.ts +75 -55
- package/src/deploy/node-headers.ts +148 -27
- package/src/deploy/platforms/cloudflare.ts +13 -3
- package/src/deploy/platforms/netlify.ts +83 -5
- package/src/deploy/platforms/node.ts +8 -5
- package/src/deploy/platforms/static.ts +2 -0
- package/src/deploy/platforms/types.ts +15 -0
- package/src/deploy/platforms/vercel.ts +10 -3
- package/src/deploy/redirects.ts +68 -21
- 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 +35 -3
- package/src/eval/agents.ts +10 -2
- package/src/eval/run.ts +25 -0
- package/src/markdown/base-links.ts +74 -29
- package/src/markdown/directives.ts +242 -36
- package/src/markdown/features.ts +17 -0
- package/src/markdown/index.ts +13 -9
- package/src/markdown/mdast.ts +5 -2
- package/src/markdown/relative-links.ts +15 -27
- package/src/markdown/route-snapshot.ts +37 -0
- package/src/og/card.ts +149 -9
- package/src/og/derive.ts +156 -5
- package/src/og/index.ts +1 -0
- package/src/openapi/asyncapi.ts +4 -2
- package/src/openapi/graphql-build.ts +28 -2
- package/src/openapi/model.ts +99 -27
- package/src/openapi/proxy.ts +63 -10
- package/src/openapi/render-mdx.ts +51 -3
- package/src/registry/eject.ts +297 -43
- package/src/search/adapters/version-scope.ts +30 -0
- package/src/search/documents.ts +89 -27
- package/src/search/popular.ts +2 -1
- package/src/search/sync/algolia.ts +36 -2
- package/src/seo/jsonld.ts +7 -3
- package/src/sources/registry.ts +5 -0
- package/src/theme/entry.ts +11 -4
- package/src/translate/agents.ts +6 -1
- package/src/translate/ledger.ts +26 -3
- package/src/translate/meta.ts +76 -24
- package/src/translate/run.ts +14 -8
- package/src/translate/validate.ts +14 -2
- package/src/translate/work-list.ts +91 -19
- package/src/upgrade/upgrade.ts +36 -4
- package/dist/cli/chunk-27g6wdth.js.map +0 -10
- package/dist/cli/chunk-2hn4b8z7.js.map +0 -12
- package/dist/cli/chunk-6crbhc3x.js.map +0 -14
- package/dist/cli/chunk-6hsn950k.js.map +0 -10
- package/dist/cli/chunk-79jhk4py.js.map +0 -35
- package/dist/cli/chunk-82bbrxdn.js +0 -51
- package/dist/cli/chunk-82bbrxdn.js.map +0 -10
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-ce574jw2.js +0 -23
- package/dist/cli/chunk-ce574jw2.js.map +0 -10
- package/dist/cli/chunk-dh8cwk36.js.map +0 -10
- package/dist/cli/chunk-epjnccmv.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-fs23ddbb.js.map +0 -35
- package/dist/cli/chunk-fz5wtpmh.js.map +0 -10
- package/dist/cli/chunk-jwyddg7y.js.map +0 -15
- package/dist/cli/chunk-kpf8rrjc.js.map +0 -19
- package/dist/cli/chunk-m3vmjgmq.js.map +0 -10
- package/dist/cli/chunk-mb2919y2.js.map +0 -10
- package/dist/cli/chunk-q5163e60.js.map +0 -11
- package/dist/cli/chunk-qkqwkpte.js.map +0 -182
- package/dist/cli/chunk-qs4q5p4e.js.map +0 -10
- package/dist/cli/chunk-s1p84fyh.js.map +0 -10
- package/dist/cli/chunk-wgm7m9qk.js.map +0 -36
- package/dist/cli/chunk-yt5n7ppj.js.map +0 -10
- package/dist/cli/chunk-yw7dm696.js.map +0 -14
- /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-2eytanqx.js.map} +0 -0
- /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-2z928egk.js.map} +0 -0
- /package/dist/cli/{chunk-ah61y8py.js.map → chunk-364znk6q.js.map} +0 -0
- /package/dist/cli/{chunk-vtk4a6dg.js.map → chunk-8ktnccpt.js.map} +0 -0
- /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-a58773jm.js.map} +0 -0
- /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-b07cmahc.js.map} +0 -0
- /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-r20tn01b.js.map} +0 -0
- /package/dist/cli/{chunk-5shv93fd.js.map → chunk-tkacnehg.js.map} +0 -0
- /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-tzmab476.js.map} +0 -0
package/src/openapi/model.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { Document, OperationObject } from "@scalar/openapi-types/3.1";
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
AsyncApiAction,
|
|
5
|
+
AsyncApiDocument,
|
|
6
|
+
AsyncApiSpecValue,
|
|
7
|
+
} from "./asyncapi.ts";
|
|
4
8
|
// Type-only, so the import can't cycle at runtime (graphql.ts imports the
|
|
5
9
|
// collector from here).
|
|
6
10
|
import type { GraphqlDocument, GraphqlMember } from "./graphql.ts";
|
|
@@ -99,7 +103,10 @@ export interface ApiOperationRef {
|
|
|
99
103
|
channelId?: string;
|
|
100
104
|
}
|
|
101
105
|
|
|
102
|
-
/**
|
|
106
|
+
/**
|
|
107
|
+
* A tag/section: the spec's declared tags in their declared order, then any
|
|
108
|
+
* undeclared tag an operation uses, in first-seen order.
|
|
109
|
+
*/
|
|
103
110
|
export interface ApiTagRef {
|
|
104
111
|
slug: string;
|
|
105
112
|
name: string;
|
|
@@ -212,6 +219,40 @@ export const specAddresses = (spec: ApiSpecData): SpecAddresses => {
|
|
|
212
219
|
return { addresses, label: "Base URL" };
|
|
213
220
|
};
|
|
214
221
|
|
|
222
|
+
const SERVER_VARIABLE = /\{(?<name>[^{}]+)\}/gu;
|
|
223
|
+
|
|
224
|
+
const isDocumentObject = (
|
|
225
|
+
value: AsyncApiSpecValue
|
|
226
|
+
): value is Record<string, AsyncApiSpecValue> =>
|
|
227
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
228
|
+
|
|
229
|
+
// YAML reads an unquoted `default: 8443` as a number; it is still the port.
|
|
230
|
+
const isVariableDefault = (
|
|
231
|
+
value: AsyncApiSpecValue
|
|
232
|
+
): value is string | number =>
|
|
233
|
+
typeof value === "string" || typeof value === "number";
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* A server URL template — an OpenAPI `servers[].url`, an AsyncAPI server's
|
|
237
|
+
* `host` or `pathname` — with each `{variable}` replaced by the `default` its
|
|
238
|
+
* `variables` map declares. Code samples, the playground's Send, and the
|
|
239
|
+
* proxy allowlist all need a real address, and
|
|
240
|
+
* `https://{region}.api.example.com` is not one. A variable the map doesn't
|
|
241
|
+
* define with a default (invalid per both specs) stays templated.
|
|
242
|
+
*/
|
|
243
|
+
export const withServerDefaults = (
|
|
244
|
+
template: string,
|
|
245
|
+
variables: AsyncApiSpecValue
|
|
246
|
+
): string =>
|
|
247
|
+
template.replaceAll(SERVER_VARIABLE, (match, name: string) => {
|
|
248
|
+
const variable =
|
|
249
|
+
isDocumentObject(variables) && Object.hasOwn(variables, name)
|
|
250
|
+
? variables[name]
|
|
251
|
+
: undefined;
|
|
252
|
+
const value = isDocumentObject(variable) ? variable.default : undefined;
|
|
253
|
+
return isVariableDefault(value) ? String(value) : match;
|
|
254
|
+
});
|
|
255
|
+
|
|
215
256
|
// The runtime object check stands guard because the document was parsed from
|
|
216
257
|
// arbitrary YAML/JSON: a spec can put a scalar where the type promises an
|
|
217
258
|
// operation object.
|
|
@@ -219,9 +260,18 @@ const isOperation = (
|
|
|
219
260
|
value: OperationObject | undefined
|
|
220
261
|
): value is OperationObject => typeof value === "object" && value !== null;
|
|
221
262
|
|
|
222
|
-
/**
|
|
223
|
-
const
|
|
224
|
-
typeof
|
|
263
|
+
/** Whether a spec value is text YAML may have read as a number. */
|
|
264
|
+
const isText = <Value>(value: Value): value is Value & (string | number) =>
|
|
265
|
+
typeof value === "string" || typeof value === "number";
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* A spec field that names something, as a string. YAML reads an unquoted
|
|
269
|
+
* `operationId: 404` or `tags: [2024]` as a number, which still names the
|
|
270
|
+
* operation or tag; anything else a hand-written spec puts there counts as
|
|
271
|
+
* absent.
|
|
272
|
+
*/
|
|
273
|
+
const specText = <Value>(value: Value): string | undefined =>
|
|
274
|
+
isText(value) ? String(value) : undefined;
|
|
225
275
|
|
|
226
276
|
/**
|
|
227
277
|
* Assign each distinct tag name a unique slug. `slugify` can collapse
|
|
@@ -254,9 +304,6 @@ export const tagSlugger = (): ((name: string) => string) => {
|
|
|
254
304
|
/** An operation before the collector assigns its unique key and route. */
|
|
255
305
|
type CollectedOperation = Omit<ApiOperationRef, "route" | "tagSlug">;
|
|
256
306
|
|
|
257
|
-
/** A document's declared tag entry (`tags[n]`). */
|
|
258
|
-
type SpecTag = NonNullable<ApiDocument["tags"]>[number];
|
|
259
|
-
|
|
260
307
|
/** The flattened output both extractors produce. */
|
|
261
308
|
export interface CollectedOperations {
|
|
262
309
|
operations: ApiOperationRef[];
|
|
@@ -276,9 +323,10 @@ export interface ExtractedOperations extends CollectedOperations {
|
|
|
276
323
|
|
|
277
324
|
/**
|
|
278
325
|
* The collector behind both extractors (OpenAPI here, AsyncAPI in
|
|
279
|
-
* `asyncapi.ts`): first-seen tag ordering, key de-duplication
|
|
280
|
-
* gains its method/action as a suffix), and the shared route
|
|
281
|
-
* URL shape and slug rules can never drift between the two spec
|
|
326
|
+
* `asyncapi.ts`): declared-then-first-seen tag ordering, key de-duplication
|
|
327
|
+
* (a repeated key gains its method/action as a suffix), and the shared route
|
|
328
|
+
* template — so URL shape and slug rules can never drift between the two spec
|
|
329
|
+
* kinds.
|
|
282
330
|
*/
|
|
283
331
|
export const operationCollector = (
|
|
284
332
|
baseRoute: string,
|
|
@@ -310,15 +358,27 @@ export const operationCollector = (
|
|
|
310
358
|
});
|
|
311
359
|
};
|
|
312
360
|
|
|
361
|
+
// Declared tags in the order the spec's `tags` list gives them, then any
|
|
362
|
+
// tag an operation uses without declaring it, in first-use order. The
|
|
363
|
+
// declared order is the author's section order, not an accident of which
|
|
364
|
+
// path happens to come first.
|
|
365
|
+
const declared = [...tagMeta.keys()];
|
|
366
|
+
const rank = (name: string): number => {
|
|
367
|
+
const index = declared.indexOf(name);
|
|
368
|
+
return index === -1 ? declared.length : index;
|
|
369
|
+
};
|
|
370
|
+
|
|
313
371
|
const finish = (): CollectedOperations => ({
|
|
314
372
|
operations,
|
|
315
|
-
tags: tagOrder
|
|
316
|
-
|
|
317
|
-
name
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
373
|
+
tags: tagOrder
|
|
374
|
+
.toSorted((a, b) => rank(a) - rank(b))
|
|
375
|
+
.map((name) => ({
|
|
376
|
+
description: tagMeta.get(name) ?? "",
|
|
377
|
+
name,
|
|
378
|
+
// The same slugger instance, so every tag resolves to the slug its
|
|
379
|
+
// operations were routed under.
|
|
380
|
+
slug: slugForTag(name),
|
|
381
|
+
})),
|
|
322
382
|
});
|
|
323
383
|
|
|
324
384
|
return { add, finish };
|
|
@@ -328,7 +388,8 @@ export const operationCollector = (
|
|
|
328
388
|
* Flatten a 3.1 document into a route-mapped operation list and its ordered
|
|
329
389
|
* tags. Operations inherit the first tag they declare; keys are de-duplicated so
|
|
330
390
|
* a repeated `operationId` still yields distinct routes. `warnings` reports
|
|
331
|
-
* anything skipped (a `$ref` path item), so missing operations
|
|
391
|
+
* anything skipped (a `$ref` path item, webhooks), so missing operations
|
|
392
|
+
* aren't silent.
|
|
332
393
|
*/
|
|
333
394
|
export const extractOperations = (
|
|
334
395
|
document: ApiDocument,
|
|
@@ -336,9 +397,10 @@ export const extractOperations = (
|
|
|
336
397
|
): ExtractedOperations => {
|
|
337
398
|
const warnings: string[] = [];
|
|
338
399
|
const tagMeta = new Map(
|
|
339
|
-
(document.tags ?? [])
|
|
340
|
-
.
|
|
341
|
-
|
|
400
|
+
(document.tags ?? []).flatMap((tag): [string, string][] => {
|
|
401
|
+
const name = specText(tag.name);
|
|
402
|
+
return name === undefined ? [] : [[name, tag.description ?? ""]];
|
|
403
|
+
})
|
|
342
404
|
);
|
|
343
405
|
const collector = operationCollector(baseRoute, tagMeta);
|
|
344
406
|
|
|
@@ -358,19 +420,29 @@ export const extractOperations = (
|
|
|
358
420
|
if (!isOperation(operation)) {
|
|
359
421
|
continue;
|
|
360
422
|
}
|
|
423
|
+
const operationId = specText(operation.operationId);
|
|
361
424
|
collector.add({
|
|
362
425
|
deprecated: operation.deprecated ?? false,
|
|
363
|
-
description: operation.description ?? "",
|
|
364
|
-
key: operationKey(method, path,
|
|
426
|
+
description: specText(operation.description) ?? "",
|
|
427
|
+
key: operationKey(method, path, operationId),
|
|
365
428
|
method,
|
|
366
|
-
operationId
|
|
429
|
+
operationId,
|
|
367
430
|
path,
|
|
368
|
-
summary: operation.summary ?? "",
|
|
369
|
-
tag: operation.tags?.[0] ?? UNTAGGED,
|
|
431
|
+
summary: specText(operation.summary) ?? "",
|
|
432
|
+
tag: specText(operation.tags?.[0]) ?? UNTAGGED,
|
|
370
433
|
});
|
|
371
434
|
}
|
|
372
435
|
}
|
|
373
436
|
|
|
437
|
+
// OpenAPI 3.1 webhooks (requests the API sends, not ones it serves) have no
|
|
438
|
+
// page renderer; say so rather than dropping them silently.
|
|
439
|
+
const webhooks = Object.keys(document.webhooks ?? {});
|
|
440
|
+
if (webhooks.length > 0) {
|
|
441
|
+
warnings.push(
|
|
442
|
+
`The spec declares ${webhooks.length === 1 ? "a webhook" : `${webhooks.length} webhooks`} under "webhooks" (${webhooks.join(", ")}); webhooks aren't rendered, so they are missing from the reference.`
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
|
|
374
446
|
return { ...collector.finish(), warnings };
|
|
375
447
|
};
|
|
376
448
|
|
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),
|
|
@@ -90,6 +90,9 @@ const codeSpans = (text: string, tree: Root): [number, number][] => {
|
|
|
90
90
|
return spans;
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
+
/** Stands in for `<` when locating code spans (see `mdxSafe`). */
|
|
94
|
+
const HTML_MASK = "";
|
|
95
|
+
|
|
93
96
|
/**
|
|
94
97
|
* Escape MDX-special syntax in prose while leaving code verbatim. A spec is
|
|
95
98
|
* someone else's content, so a link whose destination isn't a web, mail, or
|
|
@@ -101,8 +104,14 @@ const mdxSafe = (text: string): string => {
|
|
|
101
104
|
const unsafe = unsafeLinkSpans(tree);
|
|
102
105
|
const insideUnsafe = (offset: number): boolean =>
|
|
103
106
|
unsafe.some((span) => offset >= span.start && offset < span.end);
|
|
107
|
+
// Code spans come from a parse with every `<` masked. The emitted MDX
|
|
108
|
+
// escapes each `<` outside code to `<`, so no line of it is an HTML
|
|
109
|
+
// block — but CommonMark reads `<div>` as one and never looks for the code
|
|
110
|
+
// spans inside it, which would leave their braces to be escaped and shown
|
|
111
|
+
// as a literal `{`. The mask is one code unit, so offsets line up.
|
|
112
|
+
const masked = text.replaceAll("<", HTML_MASK);
|
|
104
113
|
const segments = [
|
|
105
|
-
...codeSpans(
|
|
114
|
+
...codeSpans(masked, fromMarkdown(masked))
|
|
106
115
|
.filter(([start]) => !insideUnsafe(start))
|
|
107
116
|
.map(([start, end]) => ({ end, start, text: text.slice(start, end) })),
|
|
108
117
|
...unsafe,
|
|
@@ -117,6 +126,45 @@ const mdxSafe = (text: string): string => {
|
|
|
117
126
|
return out + escapeProse(text.slice(cursor));
|
|
118
127
|
};
|
|
119
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
|
+
|
|
120
168
|
/**
|
|
121
169
|
* Frontmatter emitted for one operation or overview page. Boolean flags are
|
|
122
170
|
* assigned only when set, so absent keys stay absent in the staged MDX.
|
|
@@ -240,7 +288,7 @@ const operationDescription = (
|
|
|
240
288
|
/** Prepend a markdown description (if any) above a component invocation. */
|
|
241
289
|
const withDescription = (description: string, component: string): string =>
|
|
242
290
|
description.trim()
|
|
243
|
-
? `${
|
|
291
|
+
? `${descriptionMdx(description)}\n\n${component}`
|
|
244
292
|
: component;
|
|
245
293
|
|
|
246
294
|
export const operationMdx = (
|
|
@@ -356,7 +404,7 @@ export const overviewMdx = (
|
|
|
356
404
|
continue;
|
|
357
405
|
}
|
|
358
406
|
const description = tag.description.trim()
|
|
359
|
-
? [
|
|
407
|
+
? [descriptionMdx(tag.description)]
|
|
360
408
|
: [];
|
|
361
409
|
tagSections.push(
|
|
362
410
|
[
|