blume 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +82 -0
- package/dist/cli/{chunk-vtk4a6dg.js → chunk-00gs3wqs.js} +1 -1
- package/dist/cli/{chunk-fa25z98p.js → chunk-273ygyr4.js} +4 -3
- package/dist/cli/chunk-273ygyr4.js.map +11 -0
- package/dist/cli/{chunk-yw7dm696.js → chunk-3yce002v.js} +21 -8
- package/dist/cli/{chunk-yw7dm696.js.map → chunk-3yce002v.js.map} +3 -3
- package/dist/cli/{chunk-yt5n7ppj.js → chunk-4e9b9ra6.js} +17 -7
- package/dist/cli/chunk-4e9b9ra6.js.map +10 -0
- package/dist/cli/{chunk-fs23ddbb.js → chunk-5r8g91qn.js} +352 -676
- package/dist/cli/chunk-5r8g91qn.js.map +34 -0
- package/dist/cli/{chunk-6vm74dry.js → chunk-6dtt0zfn.js} +8 -8
- package/dist/cli/{chunk-qwsrynx5.js → chunk-6k4ftwze.js} +38 -19
- package/dist/cli/{chunk-qwsrynx5.js.map → chunk-6k4ftwze.js.map} +4 -4
- package/dist/cli/{chunk-qs4q5p4e.js → chunk-7mbqtmgb.js} +16 -7
- package/dist/cli/chunk-7mbqtmgb.js.map +10 -0
- package/dist/cli/{chunk-q5163e60.js → chunk-7vtckvaw.js} +21 -19
- package/dist/cli/chunk-7vtckvaw.js.map +11 -0
- package/dist/cli/{chunk-kdp5q7ke.js → chunk-8g8ytmgx.js} +17 -18
- package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-8g8ytmgx.js.map} +2 -2
- package/dist/cli/{chunk-epjnccmv.js → chunk-91ws1n6j.js} +18 -15
- package/dist/cli/chunk-91ws1n6j.js.map +10 -0
- package/dist/cli/{chunk-fxypxtvm.js → chunk-bbnwccaz.js} +2 -2
- package/dist/cli/{chunk-m3vmjgmq.js → chunk-bfwp9vp6.js} +16 -8
- package/dist/cli/chunk-bfwp9vp6.js.map +10 -0
- package/dist/cli/{chunk-f2z5v128.js → chunk-d1v5rhy0.js} +14 -15
- package/dist/cli/{chunk-f2z5v128.js.map → chunk-d1v5rhy0.js.map} +2 -2
- package/dist/cli/{chunk-6crbhc3x.js → chunk-ddndchfr.js} +21 -6
- package/dist/cli/chunk-ddndchfr.js.map +14 -0
- package/dist/cli/{chunk-ce574jw2.js → chunk-esh98wmb.js} +1 -1
- package/dist/cli/{chunk-zxcczpyx.js → chunk-fsmrqk8a.js} +1 -1
- package/dist/cli/{chunk-hdpx1tax.js → chunk-g698a744.js} +5 -5
- package/dist/cli/{chunk-jts8mvcz.js → chunk-gs7r695n.js} +9 -3
- package/dist/cli/{chunk-jts8mvcz.js.map → chunk-gs7r695n.js.map} +3 -3
- package/dist/cli/{chunk-zxh4d9vy.js → chunk-h2ez8dzb.js} +4 -4
- package/dist/cli/{chunk-5shv93fd.js → chunk-h7k3nq3v.js} +2 -2
- package/dist/cli/{chunk-79jhk4py.js → chunk-hqp2ajnh.js} +251 -122
- package/dist/cli/chunk-hqp2ajnh.js.map +35 -0
- package/dist/cli/{chunk-2hn4b8z7.js → chunk-hr8ne106.js} +109 -40
- package/dist/cli/chunk-hr8ne106.js.map +13 -0
- package/dist/cli/{chunk-6hsn950k.js → chunk-j85scx15.js} +62 -18
- package/dist/cli/chunk-j85scx15.js.map +10 -0
- package/dist/cli/{chunk-s1p84fyh.js → chunk-k7pj68a8.js} +63 -22
- package/dist/cli/chunk-k7pj68a8.js.map +11 -0
- package/dist/cli/{chunk-ah61y8py.js → chunk-mqc662a6.js} +2 -2
- package/dist/cli/{chunk-ch6g3ar0.js → chunk-n1yg3tj3.js} +4 -4
- package/dist/cli/{chunk-mb2919y2.js → chunk-nfcyttvj.js} +17 -6
- package/dist/cli/chunk-nfcyttvj.js.map +10 -0
- package/dist/cli/{chunk-kpf8rrjc.js → chunk-pbg5a4s3.js} +56 -24
- package/dist/cli/chunk-pbg5a4s3.js.map +19 -0
- package/dist/cli/{chunk-jwyddg7y.js → chunk-ppzjqwx2.js} +21 -14
- package/dist/cli/{chunk-jwyddg7y.js.map → chunk-ppzjqwx2.js.map} +4 -4
- package/dist/cli/{chunk-dh8cwk36.js → chunk-qkb5a8sa.js} +24 -9
- package/dist/cli/chunk-qkb5a8sa.js.map +10 -0
- package/dist/cli/{chunk-wm7js3j9.js → chunk-sqw4ekg1.js} +2 -2
- package/dist/cli/{chunk-qkqwkpte.js → chunk-v6ya5kcb.js} +3083 -953
- package/dist/cli/chunk-v6ya5kcb.js.map +189 -0
- package/dist/cli/{chunk-fz5wtpmh.js → chunk-w4bxdvsa.js} +18 -15
- package/dist/cli/chunk-w4bxdvsa.js.map +10 -0
- package/dist/cli/{chunk-27g6wdth.js → chunk-wdrt2k2v.js} +2 -2
- package/dist/cli/{chunk-wgm7m9qk.js → chunk-xh43dwgw.js} +158 -43
- package/dist/cli/chunk-xh43dwgw.js.map +36 -0
- package/dist/cli/{chunk-s6jhgk0q.js → chunk-zp79m0ts.js} +2 -2
- package/dist/cli/index.js +160 -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/relative-links.d.ts +9 -4
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/analytics/databuddy.d.ts +43 -0
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/schema.d.ts +14 -0
- 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 +9 -0
- package/dist/types/core/config-input.d.ts +4 -4
- package/dist/types/core/config.d.ts +2 -2
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/i18n-ui.d.ts +31 -0
- package/dist/types/core/i18n.d.ts +7 -1
- 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 +5 -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 +52 -13
- package/dist/types/core/sources/github-releases.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +14 -2
- package/dist/types/core/sources/normalize.d.ts +10 -1
- 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/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/cloudflare-negotiation.d.ts +3 -2
- package/dist/types/deploy/headers.d.ts +31 -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 +7 -0
- package/dist/types/deploy/platforms/vercel.d.ts +3 -2
- package/dist/types/deploy/redirects.d.ts +7 -2
- package/dist/types/deploy/vercel-negotiation.d.ts +3 -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 +17 -8
- package/docs/08-faq.mdx +9 -2
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +4 -2
- package/docs/cli/audit.mdx +2 -2
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +2 -2
- package/docs/cli/index.mdx +4 -1
- package/docs/cli/translate.mdx +1 -1
- package/docs/configuration/analytics.mdx +23 -2
- package/docs/configuration/assistant.mdx +1 -1
- package/docs/configuration/customization.mdx +4 -3
- package/docs/configuration/index.mdx +5 -3
- package/docs/configuration/search.mdx +1 -1
- package/docs/content/components.mdx +1 -1
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +1 -1
- package/docs/content/index.mdx +4 -2
- package/docs/content/meta.mdx +5 -3
- package/docs/content/navigation.mdx +29 -4
- package/docs/content/sources.mdx +18 -12
- package/docs/content/versioning.mdx +1 -0
- package/docs/discoverability/agent-discovery.mdx +21 -7
- package/docs/discoverability/index.mdx +2 -2
- package/docs/discoverability/llms-txt.mdx +2 -5
- package/docs/discoverability/markdown.mdx +5 -3
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +3 -2
- package/docs/discoverability/open-graph.mdx +6 -4
- package/docs/discoverability/rss.mdx +3 -1
- package/docs/references/asyncapi.mdx +1 -1
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/openapi.mdx +3 -3
- 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/mintlify.md +3 -3
- package/skills/blume-migrate/references/monorepo.md +1 -1
- package/skills/blume-migrate/references/nextra.md +1 -1
- package/skills/blume-migrate/references/starlight.md +5 -5
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +2 -2
- package/skills/blume-update-docs/references/audit-checklist.md +1 -1
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/api/spec.ts +15 -2
- package/src/ai/api-catalog.ts +7 -1
- package/src/ai/ask-context.ts +14 -2
- package/src/ai/ask-data.ts +26 -12
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/link-headers.ts +8 -3
- package/src/ai/llms.ts +4 -3
- package/src/ai/markdown.ts +23 -11
- package/src/ai/mcp/server.ts +78 -7
- package/src/ai/relative-links.ts +78 -10
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/visibility.ts +45 -14
- package/src/analytics/databuddy.ts +67 -0
- package/src/analytics/head.ts +4 -0
- package/src/analytics/index.ts +2 -0
- package/src/analytics/posthog.ts +21 -3
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +71 -27
- package/src/astro/templates.ts +61 -23
- 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 +14 -0
- 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/report.ts +54 -17
- package/src/audit/run.ts +1 -0
- package/src/audit/types.ts +18 -0
- package/src/audit/url.ts +37 -6
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +7 -0
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/eval.ts +1 -7
- 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 +9 -6
- package/src/cli/commands/upgrade.ts +11 -0
- 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/components/content/AccordionItem.astro +26 -22
- package/src/components/content/Badge.astro +2 -9
- package/src/components/content/Card.astro +2 -2
- package/src/components/content/Component.astro +9 -3
- 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/Tabs.astro +54 -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 +17 -0
- package/src/components/content/base-href.ts +18 -3
- package/src/components/content/inline-markdown.ts +27 -7
- package/src/components/copy-feedback.ts +35 -8
- package/src/components/islands/assistant.tsx +16 -2
- package/src/components/islands/hooks.ts +7 -2
- package/src/components/islands/webmcp.ts +12 -8
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Header.astro +22 -9
- package/src/components/layout/Logo.astro +5 -0
- package/src/components/layout/NavSelector.astro +6 -1
- package/src/components/layout/NavTabMenu.astro +133 -0
- package/src/components/layout/NavTree.astro +15 -6
- package/src/components/layout/NavTreeCache.astro +5 -2
- package/src/components/layout/NavTreeScript.astro +45 -5
- package/src/components/layout/PageLayout.astro +22 -8
- package/src/components/layout/ReferenceLayout.astro +4 -1
- package/src/components/layout/RootLayout.astro +21 -8
- package/src/components/layout/Search.astro +5 -1
- package/src/components/layout/analytics-client.ts +2 -0
- package/src/components/openapi/GraphqlType.astro +11 -3
- package/src/components/openapi/MessageComposer.astro +1 -1
- package/src/components/openapi/Operation.astro +21 -5
- package/src/components/openapi/PanelTabs.astro +4 -1
- package/src/components/openapi/Playground.astro +8 -2
- package/src/components/openapi/RequestPanel.astro +9 -5
- package/src/components/openapi/SchemaProperty.astro +11 -33
- package/src/components/openapi/SchemaTable.astro +27 -52
- package/src/components/openapi/helpers.ts +90 -12
- package/src/components/openapi/message-composer.ts +8 -0
- package/src/components/openapi/message-model.ts +12 -2
- package/src/components/openapi/message.ts +4 -1
- package/src/components/openapi/operation-model.ts +40 -8
- package/src/components/openapi/panel.ts +29 -5
- package/src/components/openapi/playground-client.ts +37 -7
- package/src/components/openapi/playground-schema.ts +25 -6
- package/src/components/openapi/request.ts +2 -0
- package/src/components/openapi/schema-tree.ts +203 -0
- package/src/components/openapi/snippets.ts +30 -15
- package/src/components/openapi/validate-json.ts +1 -1
- package/src/core/base-path.ts +15 -0
- package/src/core/config-input.ts +4 -4
- package/src/core/config.ts +18 -4
- package/src/core/diagnostics.ts +217 -30
- package/src/core/graph.ts +120 -11
- package/src/core/i18n-ui.ts +39 -2
- package/src/core/i18n.ts +13 -2
- package/src/core/links.ts +7 -4
- package/src/core/load-module.ts +20 -0
- package/src/core/locale-links.ts +17 -17
- package/src/core/manifest.ts +3 -2
- package/src/core/meta.ts +69 -6
- package/src/core/nav-diagnostics.ts +56 -1
- package/src/core/navigation.ts +245 -76
- package/src/core/ordering-prefix.ts +27 -0
- package/src/core/project-graph.ts +23 -1
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +70 -14
- package/src/core/sources/assets.ts +83 -41
- package/src/core/sources/contentful-rich-text.ts +3 -2
- package/src/core/sources/contentful.ts +25 -12
- package/src/core/sources/filesystem.ts +5 -1
- package/src/core/sources/github-releases.ts +106 -5
- package/src/core/sources/lexical.ts +9 -4
- package/src/core/sources/lower.ts +79 -26
- package/src/core/sources/mdx-remote.ts +1 -0
- package/src/core/sources/normalize.ts +132 -30
- package/src/core/sources/notion.ts +26 -10
- package/src/core/sources/obsidian.ts +17 -3
- package/src/core/sources/payload.ts +1 -0
- package/src/core/sources/portable-text.ts +63 -44
- 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 +9 -4
- package/src/core/sources/strapi.ts +1 -0
- package/src/core/sources/types.ts +31 -0
- 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 +17 -2
- 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 +25 -5
- package/src/deploy/cloudflare-negotiation.ts +23 -4
- package/src/deploy/headers.ts +67 -51
- package/src/deploy/node-headers.ts +148 -27
- package/src/deploy/platforms/cloudflare.ts +1 -0
- package/src/deploy/platforms/netlify.ts +82 -5
- package/src/deploy/platforms/node.ts +7 -5
- package/src/deploy/platforms/static.ts +1 -0
- package/src/deploy/platforms/types.ts +7 -0
- package/src/deploy/platforms/vercel.ts +9 -3
- package/src/deploy/redirects.ts +14 -3
- 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 +55 -8
- package/src/markdown/index.ts +6 -3
- package/src/markdown/relative-links.ts +3 -23
- package/src/markdown/route-snapshot.ts +37 -0
- package/src/og/card.ts +20 -4
- package/src/og/derive.ts +145 -4
- package/src/openapi/graphql-build.ts +28 -2
- package/src/openapi/model.ts +77 -13
- package/src/openapi/render-mdx.ts +10 -1
- package/src/registry/eject.ts +119 -22
- package/src/search/documents.ts +22 -1
- package/src/search/sync/algolia.ts +36 -2
- 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 +11 -3
- package/src/translate/run.ts +11 -5
- package/src/translate/validate.ts +10 -1
- package/src/translate/work-list.ts +36 -3
- package/src/upgrade/upgrade.ts +36 -4
- 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-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-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-vtk4a6dg.js.map → chunk-00gs3wqs.js.map} +0 -0
- /package/dist/cli/{chunk-6vm74dry.js.map → chunk-6dtt0zfn.js.map} +0 -0
- /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-bbnwccaz.js.map} +0 -0
- /package/dist/cli/{chunk-ce574jw2.js.map → chunk-esh98wmb.js.map} +0 -0
- /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-fsmrqk8a.js.map} +0 -0
- /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-g698a744.js.map} +0 -0
- /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-h2ez8dzb.js.map} +0 -0
- /package/dist/cli/{chunk-5shv93fd.js.map → chunk-h7k3nq3v.js.map} +0 -0
- /package/dist/cli/{chunk-ah61y8py.js.map → chunk-mqc662a6.js.map} +0 -0
- /package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-n1yg3tj3.js.map} +0 -0
- /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-sqw4ekg1.js.map} +0 -0
- /package/dist/cli/{chunk-27g6wdth.js.map → chunk-wdrt2k2v.js.map} +0 -0
- /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-zp79m0ts.js.map} +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { withServerDefaults } from "../../openapi/model.ts";
|
|
1
2
|
import {
|
|
3
|
+
declaredExample,
|
|
2
4
|
exampleValue,
|
|
3
5
|
objectProperties,
|
|
4
6
|
resolveSchema,
|
|
@@ -30,9 +32,30 @@ import type { OperationSecurity, ResolvedScheme } from "./security.ts";
|
|
|
30
32
|
|
|
31
33
|
interface MediaTypeLike {
|
|
32
34
|
schema?: SchemaLike;
|
|
33
|
-
example?:
|
|
35
|
+
example?: SpecValue;
|
|
36
|
+
examples?: SpecValue;
|
|
34
37
|
}
|
|
35
38
|
|
|
39
|
+
/** A server entry: its URL template and the variables that fill it. */
|
|
40
|
+
export interface ServerLike {
|
|
41
|
+
url?: string;
|
|
42
|
+
variables?: SpecValue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The servers an operation is sent to: its own `servers` when it declares
|
|
47
|
+
* any, else its path item's, else the document's — each level overrides the
|
|
48
|
+
* one above it, as the OpenAPI spec defines.
|
|
49
|
+
*/
|
|
50
|
+
export const effectiveServers = (
|
|
51
|
+
operation: ServerLike[] | undefined,
|
|
52
|
+
pathItem: ServerLike[] | undefined,
|
|
53
|
+
document: ServerLike[] | undefined
|
|
54
|
+
): ServerLike[] =>
|
|
55
|
+
[operation, pathItem, document].find(
|
|
56
|
+
(servers) => Array.isArray(servers) && servers.length > 0
|
|
57
|
+
) ?? [];
|
|
58
|
+
|
|
36
59
|
/** Primitive types the flat-body fields UI can edit directly. */
|
|
37
60
|
const PRIMITIVE_TYPES = {
|
|
38
61
|
boolean: true,
|
|
@@ -78,7 +101,9 @@ const modelParams = (
|
|
|
78
101
|
required,
|
|
79
102
|
type: scalarType(param.schema, schemas),
|
|
80
103
|
value: required
|
|
81
|
-
? inputValue(
|
|
104
|
+
? inputValue(
|
|
105
|
+
declaredExample(param) ?? exampleValue(param.schema, schemas)
|
|
106
|
+
)
|
|
82
107
|
: "",
|
|
83
108
|
});
|
|
84
109
|
}
|
|
@@ -127,7 +152,12 @@ const bodyFields = (
|
|
|
127
152
|
description: propertySchema.description,
|
|
128
153
|
enum: propertySchema.enum?.map(String),
|
|
129
154
|
name,
|
|
130
|
-
required:
|
|
155
|
+
// A `readOnly` property's `required` binds responses only: a request
|
|
156
|
+
// shouldn't send the server-generated field at all.
|
|
157
|
+
required:
|
|
158
|
+
required.has(name) &&
|
|
159
|
+
property.readOnly !== true &&
|
|
160
|
+
propertySchema.readOnly !== true,
|
|
131
161
|
type,
|
|
132
162
|
value: inputValue(defaults?.[name]),
|
|
133
163
|
});
|
|
@@ -145,10 +175,8 @@ const modelBody = (
|
|
|
145
175
|
return undefined;
|
|
146
176
|
}
|
|
147
177
|
const [contentType, mediaType] = media;
|
|
148
|
-
// SAFETY: `example` comes from the parsed spec document (YAML/JSON), whose
|
|
149
|
-
// values are exactly the JSON-shaped tree `SpecValue` models.
|
|
150
178
|
const exampleData =
|
|
151
|
-
(mediaType
|
|
179
|
+
declaredExample(mediaType) ?? exampleValue(mediaType.schema, schemas);
|
|
152
180
|
return {
|
|
153
181
|
contentType,
|
|
154
182
|
example: toJson(exampleData) ?? "",
|
|
@@ -241,7 +269,8 @@ export const operationModel = (args: {
|
|
|
241
269
|
/** Pre-merged/resolved (`mergeParameters` output). */
|
|
242
270
|
parameters: ParameterLike[];
|
|
243
271
|
requestBody?: { content?: Record<string, MediaTypeLike> };
|
|
244
|
-
servers
|
|
272
|
+
/** The operation's effective servers (`effectiveServers` output). */
|
|
273
|
+
servers: ServerLike[];
|
|
245
274
|
schemas: Record<string, SchemaLike>;
|
|
246
275
|
security: OperationSecurity;
|
|
247
276
|
}): PlaygroundModel => ({
|
|
@@ -256,5 +285,8 @@ export const operationModel = (args: {
|
|
|
256
285
|
method: args.method.toUpperCase(),
|
|
257
286
|
params: modelParams(args.parameters, args.schemas),
|
|
258
287
|
path: args.path,
|
|
259
|
-
|
|
288
|
+
// Variables resolve to their defaults: the samples and Send need a real URL.
|
|
289
|
+
servers: args.servers.map((server) =>
|
|
290
|
+
withServerDefaults(server.url ?? "", server.variables)
|
|
291
|
+
),
|
|
260
292
|
});
|
|
@@ -18,23 +18,47 @@ class BlumePanelTabs extends HTMLElement {
|
|
|
18
18
|
|
|
19
19
|
const activate = (key: string): void => {
|
|
20
20
|
for (const tab of tabs) {
|
|
21
|
-
tab.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const selected = tab.dataset.panelTab === key;
|
|
22
|
+
tab.setAttribute("aria-selected", selected ? "true" : "false");
|
|
23
|
+
// Roving tabindex: Tab reaches the selected tab only, the arrow keys
|
|
24
|
+
// move between the rest.
|
|
25
|
+
tab.tabIndex = selected ? 0 : -1;
|
|
25
26
|
}
|
|
26
27
|
for (const panel of panels) {
|
|
27
28
|
panel.classList.toggle("hidden", panel.dataset.panel !== key);
|
|
28
29
|
}
|
|
29
30
|
};
|
|
30
31
|
|
|
31
|
-
for (const tab of tabs) {
|
|
32
|
+
for (const [index, tab] of tabs.entries()) {
|
|
32
33
|
tab.addEventListener("click", () => {
|
|
33
34
|
const key = tab.dataset.panelTab;
|
|
34
35
|
if (key) {
|
|
35
36
|
activate(key);
|
|
36
37
|
}
|
|
37
38
|
});
|
|
39
|
+
// The WAI-ARIA tabs keyboard pattern, matching `<Tabs>`: arrows move and
|
|
40
|
+
// wrap, Home and End jump to the ends, and focus follows selection.
|
|
41
|
+
tab.addEventListener("keydown", (event) => {
|
|
42
|
+
const last = tabs.length - 1;
|
|
43
|
+
let next: number | undefined;
|
|
44
|
+
if (event.key === "ArrowRight") {
|
|
45
|
+
next = index === last ? 0 : index + 1;
|
|
46
|
+
} else if (event.key === "ArrowLeft") {
|
|
47
|
+
next = index === 0 ? last : index - 1;
|
|
48
|
+
} else if (event.key === "Home") {
|
|
49
|
+
next = 0;
|
|
50
|
+
} else if (event.key === "End") {
|
|
51
|
+
next = last;
|
|
52
|
+
}
|
|
53
|
+
const target = next === undefined ? undefined : tabs[next];
|
|
54
|
+
const key = target?.dataset.panelTab;
|
|
55
|
+
if (!(target && key)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
activate(key);
|
|
60
|
+
target.focus();
|
|
61
|
+
});
|
|
38
62
|
}
|
|
39
63
|
|
|
40
64
|
if (copy) {
|
|
@@ -155,6 +155,36 @@ const prettyBody = (text: string): string => {
|
|
|
155
155
|
}
|
|
156
156
|
};
|
|
157
157
|
|
|
158
|
+
/*
|
|
159
|
+
* Remembered credentials are a convenience, never a requirement. With storage
|
|
160
|
+
* blocked (Safari's "Block All Cookies", a sandboxed iframe) even reading the
|
|
161
|
+
* `localStorage` global throws a SecurityError, which would take the whole
|
|
162
|
+
* panel down during init; each access is guarded so the form simply forgets.
|
|
163
|
+
*/
|
|
164
|
+
const readStored = (key: string): string | null => {
|
|
165
|
+
try {
|
|
166
|
+
return localStorage.getItem(key);
|
|
167
|
+
} catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const writeStored = (key: string, value: string): void => {
|
|
173
|
+
try {
|
|
174
|
+
localStorage.setItem(key, value);
|
|
175
|
+
} catch {
|
|
176
|
+
// Blocked or full storage: the credentials stay in the form only.
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const removeStored = (key: string): void => {
|
|
181
|
+
try {
|
|
182
|
+
localStorage.removeItem(key);
|
|
183
|
+
} catch {
|
|
184
|
+
// Blocked storage never held the entry in the first place.
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
158
188
|
/** A one-line text element for the response/error regions. */
|
|
159
189
|
const line = (className: string, text: string): HTMLElement => {
|
|
160
190
|
const el = document.createElement("div");
|
|
@@ -316,7 +346,7 @@ export const initPlayground = (root: HTMLElement): void => {
|
|
|
316
346
|
|
|
317
347
|
/** Restore remembered credentials into the inputs and re-check the box. */
|
|
318
348
|
const restoreAuth = (): void => {
|
|
319
|
-
const stored =
|
|
349
|
+
const stored = readStored(storageKey);
|
|
320
350
|
if (!stored) {
|
|
321
351
|
return;
|
|
322
352
|
}
|
|
@@ -355,7 +385,7 @@ export const initPlayground = (root: HTMLElement): void => {
|
|
|
355
385
|
}
|
|
356
386
|
} catch {
|
|
357
387
|
// A corrupt entry (older format, manual edit) must not break init.
|
|
358
|
-
|
|
388
|
+
removeStored(storageKey);
|
|
359
389
|
}
|
|
360
390
|
};
|
|
361
391
|
|
|
@@ -374,12 +404,12 @@ export const initPlayground = (root: HTMLElement): void => {
|
|
|
374
404
|
)
|
|
375
405
|
);
|
|
376
406
|
const table = document.createElement("table");
|
|
377
|
-
table.className = "w-full text-
|
|
407
|
+
table.className = "w-full text-start text-xs";
|
|
378
408
|
for (const [name, value] of res.headers) {
|
|
379
409
|
const row = document.createElement("tr");
|
|
380
410
|
const header = document.createElement("th");
|
|
381
411
|
header.setAttribute("scope", "row");
|
|
382
|
-
header.className = "
|
|
412
|
+
header.className = "pe-3 align-top font-medium text-muted-foreground";
|
|
383
413
|
header.textContent = name;
|
|
384
414
|
const cell = document.createElement("td");
|
|
385
415
|
cell.className = "break-all font-mono text-foreground";
|
|
@@ -548,9 +578,9 @@ export const initPlayground = (root: HTMLElement): void => {
|
|
|
548
578
|
}
|
|
549
579
|
if (remember && target === remember) {
|
|
550
580
|
if (remember.checked) {
|
|
551
|
-
|
|
581
|
+
writeStored(storageKey, JSON.stringify(collectAuth()));
|
|
552
582
|
} else {
|
|
553
|
-
|
|
583
|
+
removeStored(storageKey);
|
|
554
584
|
}
|
|
555
585
|
} else if (
|
|
556
586
|
remember?.checked &&
|
|
@@ -558,7 +588,7 @@ export const initPlayground = (root: HTMLElement): void => {
|
|
|
558
588
|
target.dataset.authUsername !== undefined ||
|
|
559
589
|
target.dataset.authPassword !== undefined)
|
|
560
590
|
) {
|
|
561
|
-
|
|
591
|
+
writeStored(storageKey, JSON.stringify(collectAuth()));
|
|
562
592
|
}
|
|
563
593
|
syncSamples();
|
|
564
594
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveSchema } from "./helpers.ts";
|
|
1
|
+
import { isNullable, resolveSchema } from "./helpers.ts";
|
|
2
2
|
import type { SchemaLike, SpecValue } from "./helpers.ts";
|
|
3
3
|
import type { ValidationSchema } from "./request.ts";
|
|
4
4
|
|
|
@@ -50,6 +50,14 @@ export const inputValue = (value: SpecValue): string => {
|
|
|
50
50
|
/** Recursion limit for pruned validation schemas — deep enough for real specs. */
|
|
51
51
|
const MAX_SCHEMA_DEPTH = 6;
|
|
52
52
|
|
|
53
|
+
/** Whether a property is `readOnly`, on the property or the schema it refs. */
|
|
54
|
+
const isReadOnly = (
|
|
55
|
+
property: SchemaLike | undefined,
|
|
56
|
+
schemas: Record<string, SchemaLike>
|
|
57
|
+
): boolean =>
|
|
58
|
+
property?.readOnly === true ||
|
|
59
|
+
resolveSchema(schemas, property).readOnly === true;
|
|
60
|
+
|
|
53
61
|
/**
|
|
54
62
|
* Prune a spec schema into the tiny subset `validate-json.ts` understands:
|
|
55
63
|
* `$ref`s resolved inline, cycles cut (the visited set is copied per branch so
|
|
@@ -74,15 +82,26 @@ const pruneSchema = (
|
|
|
74
82
|
}
|
|
75
83
|
const resolved = resolveSchema(schemas, schema);
|
|
76
84
|
const out: ValidationSchema = {};
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
85
|
+
// Only a single declared type is checked: a 3.1 type array like
|
|
86
|
+
// `["string", "integer"]` accepts either, which one `type` can't say.
|
|
87
|
+
const types = declaredTypes(resolved.type);
|
|
88
|
+
if (types.length === 1) {
|
|
89
|
+
[out.type] = types;
|
|
90
|
+
}
|
|
91
|
+
if (isNullable(resolved)) {
|
|
92
|
+
out.nullable = true;
|
|
80
93
|
}
|
|
81
94
|
if (resolved.enum) {
|
|
82
95
|
out.enum = resolved.enum;
|
|
83
96
|
}
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
// A `readOnly` property's `required` binds responses only: the server
|
|
98
|
+
// generates it, so a request body — which the prefilled example already
|
|
99
|
+
// leaves it out of — must not be told it is missing.
|
|
100
|
+
const required = (resolved.required ?? []).filter(
|
|
101
|
+
(name) => !isReadOnly(resolved.properties?.[name], schemas)
|
|
102
|
+
);
|
|
103
|
+
if (required.length > 0) {
|
|
104
|
+
out.required = required;
|
|
86
105
|
}
|
|
87
106
|
if (resolved.properties) {
|
|
88
107
|
const properties: Record<string, ValidationSchema> = {};
|
|
@@ -37,6 +37,8 @@ export interface PlaygroundBodyField {
|
|
|
37
37
|
/** A pruned, cycle-free JSON-schema subset `validate-json.ts` understands. */
|
|
38
38
|
export interface ValidationSchema {
|
|
39
39
|
type?: string;
|
|
40
|
+
/** `null` is also accepted: 3.0 `nullable`, or `"null"` in a 3.1 type array. */
|
|
41
|
+
nullable?: boolean;
|
|
40
42
|
properties?: Record<string, ValidationSchema>;
|
|
41
43
|
required?: string[];
|
|
42
44
|
items?: ValidationSchema;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import {
|
|
2
|
+
objectProperties,
|
|
3
|
+
refName,
|
|
4
|
+
resolveSchema,
|
|
5
|
+
typeLabel,
|
|
6
|
+
} from "./helpers.ts";
|
|
7
|
+
import type { SchemaLike, SpecValue } from "./helpers.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The expansion plan behind the schema tables (`SchemaTable.astro` and
|
|
11
|
+
* `SchemaProperty.astro`). Every nested object is server-rendered in full
|
|
12
|
+
* inside a collapsed `<details>`, so the plan is the page's weight: expanding
|
|
13
|
+
* each named schema wherever it appears — stopping only at a model nested in
|
|
14
|
+
* itself — grows exponentially with cross-references (twelve schemas that
|
|
15
|
+
* each reference four others render tens of thousands of nested tables for
|
|
16
|
+
* one request body).
|
|
17
|
+
*
|
|
18
|
+
* So a named schema expands wherever it appears in the first
|
|
19
|
+
* {@link REPEAT_DEPTH} named levels, and deeper than that only where it
|
|
20
|
+
* appears first in the tree, breadth-first; a later mention shows its name
|
|
21
|
+
* alone. Beyond the first levels each named schema expands at most once, so
|
|
22
|
+
* the tree stays proportional to the spec instead of to the number of paths
|
|
23
|
+
* through it, while the shallow nesting typical specs use — `billing` and
|
|
24
|
+
* `shipping` both an `Address` — renders exactly as before.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Named-schema nesting depth (the root being 0) up to which a named schema
|
|
29
|
+
* expands at every mention, even one already expanded elsewhere in the tree.
|
|
30
|
+
*/
|
|
31
|
+
export const REPEAT_DEPTH = 2;
|
|
32
|
+
|
|
33
|
+
/** A place in the tree a node is planned into; filled in breadth-first. */
|
|
34
|
+
export interface SchemaSlot {
|
|
35
|
+
node: SchemaNode;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** One property row of an object table. */
|
|
39
|
+
export interface SchemaRow {
|
|
40
|
+
name: string;
|
|
41
|
+
required: boolean;
|
|
42
|
+
schema: SchemaLike;
|
|
43
|
+
/** The row's disclosure contents; absent when the row has nothing to show. */
|
|
44
|
+
children?: SchemaSlot;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** What one schema table renders. */
|
|
48
|
+
export type SchemaNode =
|
|
49
|
+
/** A named schema nested inside itself. */
|
|
50
|
+
| { kind: "circular"; name: string }
|
|
51
|
+
/** A named schema expanded elsewhere in this tree: its name only. */
|
|
52
|
+
| { kind: "named"; name: string }
|
|
53
|
+
| { kind: "array"; itemsLabel: string; items?: SchemaSlot }
|
|
54
|
+
| {
|
|
55
|
+
kind: "branches";
|
|
56
|
+
label: "One of" | "Any of";
|
|
57
|
+
branches: { label: string; slot: SchemaSlot }[];
|
|
58
|
+
}
|
|
59
|
+
| { kind: "properties"; rows: SchemaRow[] }
|
|
60
|
+
| { kind: "type"; label: string };
|
|
61
|
+
|
|
62
|
+
const isString = (value: SpecValue): value is string =>
|
|
63
|
+
typeof value === "string";
|
|
64
|
+
|
|
65
|
+
const typesOf = (schema: SchemaLike): (string | undefined)[] =>
|
|
66
|
+
Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
67
|
+
|
|
68
|
+
/** Whether a schema has nested fields a row can disclose. */
|
|
69
|
+
const hasNestedFields = (candidate: SchemaLike): boolean =>
|
|
70
|
+
Boolean(
|
|
71
|
+
candidate.properties ||
|
|
72
|
+
candidate.allOf ||
|
|
73
|
+
candidate.oneOf ||
|
|
74
|
+
candidate.anyOf ||
|
|
75
|
+
isString(candidate.$ref)
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
/** A named schema waiting for its breadth-first turn. */
|
|
79
|
+
interface PendingRef {
|
|
80
|
+
ancestors: string[];
|
|
81
|
+
name: string;
|
|
82
|
+
schema: SchemaLike;
|
|
83
|
+
slot: SchemaSlot;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Plan the table tree for one schema (a request body, a response, a payload). */
|
|
87
|
+
export const schemaTree = (
|
|
88
|
+
root: SchemaLike,
|
|
89
|
+
schemas: Record<string, SchemaLike>
|
|
90
|
+
): SchemaNode => {
|
|
91
|
+
const queue: PendingRef[] = [];
|
|
92
|
+
const expanded = new Set<string>();
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* A table for `schema`, where `ancestors` are the named schemas already
|
|
96
|
+
* open above it. A `$ref` waits in the queue, so every mention at one depth
|
|
97
|
+
* is planned before any deeper one; `resolved` plans a dequeued schema's
|
|
98
|
+
* own body instead.
|
|
99
|
+
*/
|
|
100
|
+
const table = (
|
|
101
|
+
schema: SchemaLike,
|
|
102
|
+
ancestors: string[],
|
|
103
|
+
resolved = false
|
|
104
|
+
): SchemaSlot => {
|
|
105
|
+
if (!resolved && isString(schema.$ref)) {
|
|
106
|
+
const name = refName(schema.$ref);
|
|
107
|
+
if (ancestors.includes(name)) {
|
|
108
|
+
return { node: { kind: "circular", name } };
|
|
109
|
+
}
|
|
110
|
+
const slot: SchemaSlot = { node: { kind: "named", name } };
|
|
111
|
+
queue.push({ ancestors, name, schema, slot });
|
|
112
|
+
return slot;
|
|
113
|
+
}
|
|
114
|
+
if (typesOf(schema).includes("array")) {
|
|
115
|
+
// Items stay unresolved, so a self-referential item `$ref` is still
|
|
116
|
+
// recognized as the circle it is.
|
|
117
|
+
const { items } = schema;
|
|
118
|
+
return {
|
|
119
|
+
node: items
|
|
120
|
+
? {
|
|
121
|
+
items: table(items, ancestors),
|
|
122
|
+
itemsLabel: typeLabel(items),
|
|
123
|
+
kind: "array",
|
|
124
|
+
}
|
|
125
|
+
: { itemsLabel: typeLabel({}), kind: "array" },
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const branches = schema.oneOf ?? schema.anyOf;
|
|
129
|
+
if (branches) {
|
|
130
|
+
return {
|
|
131
|
+
node: {
|
|
132
|
+
branches: branches.map((branch, index) => ({
|
|
133
|
+
label: typeLabel(branch) || `Option ${index + 1}`,
|
|
134
|
+
slot: table(branch, ancestors),
|
|
135
|
+
})),
|
|
136
|
+
kind: "branches",
|
|
137
|
+
label: schema.oneOf ? "One of" : "Any of",
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
// A row discloses nested structure — never a model inside itself.
|
|
142
|
+
const rowChildren = (property: SchemaLike): SchemaSlot | undefined => {
|
|
143
|
+
if (
|
|
144
|
+
isString(property.$ref) &&
|
|
145
|
+
ancestors.includes(refName(property.$ref))
|
|
146
|
+
) {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
const target = resolveSchema(schemas, property);
|
|
150
|
+
const items = typesOf(target).includes("array")
|
|
151
|
+
? resolveSchema(schemas, target.items)
|
|
152
|
+
: null;
|
|
153
|
+
return hasNestedFields(target) || (items && hasNestedFields(items))
|
|
154
|
+
? table(property, ancestors)
|
|
155
|
+
: undefined;
|
|
156
|
+
};
|
|
157
|
+
const { properties, required } = objectProperties(schema, schemas);
|
|
158
|
+
if (properties.length > 0) {
|
|
159
|
+
return {
|
|
160
|
+
node: {
|
|
161
|
+
kind: "properties",
|
|
162
|
+
rows: properties.map(([name, property]) => ({
|
|
163
|
+
children: rowChildren(property),
|
|
164
|
+
name,
|
|
165
|
+
required: required.has(name),
|
|
166
|
+
schema: property,
|
|
167
|
+
})),
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
return { node: { kind: "type", label: typeLabel(schema) } };
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const tree = table(root, []);
|
|
175
|
+
// The queue grows while it drains, in depth order: every mention at one
|
|
176
|
+
// named depth is queued before the first one at the next.
|
|
177
|
+
for (const pending of queue) {
|
|
178
|
+
const depth = pending.ancestors.length;
|
|
179
|
+
if (depth > REPEAT_DEPTH && expanded.has(pending.name)) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
expanded.add(pending.name);
|
|
183
|
+
pending.slot.node = table(
|
|
184
|
+
resolveSchema(schemas, pending.schema),
|
|
185
|
+
[...pending.ancestors, pending.name],
|
|
186
|
+
true
|
|
187
|
+
).node;
|
|
188
|
+
}
|
|
189
|
+
return tree.node;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Whether a row gets a disclosure: it has nested structure, and that structure
|
|
194
|
+
* isn't just the name of a schema expanded elsewhere (directly, or as the
|
|
195
|
+
* items of an array).
|
|
196
|
+
*/
|
|
197
|
+
export const rowExpands = (row: SchemaRow): boolean => {
|
|
198
|
+
const node = row.children?.node;
|
|
199
|
+
if (!node || node.kind === "named") {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
return !(node.kind === "array" && node.items?.node.kind === "named");
|
|
203
|
+
};
|
|
@@ -22,26 +22,42 @@ const headerLines = (
|
|
|
22
22
|
): string[] =>
|
|
23
23
|
Object.entries(headers).map(([key, value]) => format(key, value));
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* A single-quoted POSIX shell word. Nothing expands inside single quotes — no
|
|
27
|
+
* `$`, backtick, `!`, or `\` — so a value reaches curl byte for byte; a
|
|
28
|
+
* literal `'` closes the quote, adds an escaped one, and reopens it.
|
|
29
|
+
*/
|
|
30
|
+
const shellQuote = (value: string): string =>
|
|
31
|
+
`'${value.replaceAll("'", String.raw`'\''`)}'`;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A double-quoted string literal for the JavaScript and Python samples. JSON's
|
|
35
|
+
* string escapes are a subset of both languages' — a quote in a header value
|
|
36
|
+
* (`If-Match: "33a64df5"`) or a backslash becomes an escape rather than
|
|
37
|
+
* ending the literal early.
|
|
38
|
+
*/
|
|
39
|
+
const stringLiteral = (value: string): string => JSON.stringify(value);
|
|
40
|
+
|
|
25
41
|
const curlSnippet = (sample: RequestSample): string => {
|
|
26
42
|
const lines = [
|
|
27
|
-
`curl -X ${sample.method}
|
|
28
|
-
...headerLines(
|
|
43
|
+
`curl -X ${sample.method} ${shellQuote(sample.url)}`,
|
|
44
|
+
...headerLines(
|
|
45
|
+
sample.headers,
|
|
46
|
+
(key, value) => ` -H ${shellQuote(`${key}: ${value}`)}`
|
|
47
|
+
),
|
|
29
48
|
];
|
|
30
49
|
if (sample.body) {
|
|
31
|
-
|
|
32
|
-
// single-quoted string, so an example like "it's" doesn't break the shell.
|
|
33
|
-
const escapedBody = sample.body.replaceAll("'", String.raw`'\''`);
|
|
34
|
-
lines.push(` -d '${escapedBody}'`);
|
|
50
|
+
lines.push(` -d ${shellQuote(sample.body)}`);
|
|
35
51
|
}
|
|
36
52
|
return lines.join(" \\\n");
|
|
37
53
|
};
|
|
38
54
|
|
|
39
55
|
const fetchSnippet = (sample: RequestSample): string => {
|
|
40
|
-
const options = [` method:
|
|
56
|
+
const options = [` method: ${stringLiteral(sample.method)}`];
|
|
41
57
|
if (Object.keys(sample.headers).length > 0) {
|
|
42
58
|
const headers = headerLines(
|
|
43
59
|
sample.headers,
|
|
44
|
-
(key, value) => `
|
|
60
|
+
(key, value) => ` ${stringLiteral(key)}: ${stringLiteral(value)}`
|
|
45
61
|
).join(",\n");
|
|
46
62
|
options.push(` headers: {\n${headers}\n }`);
|
|
47
63
|
}
|
|
@@ -53,28 +69,27 @@ const fetchSnippet = (sample: RequestSample): string => {
|
|
|
53
69
|
// and an id past 2^53 loses digits through a JS number. The string
|
|
54
70
|
// literal also stays syntactically valid while the editor holds mid-edit
|
|
55
71
|
// text that isn't JSON yet.
|
|
56
|
-
options.push(` body: ${
|
|
72
|
+
options.push(` body: ${stringLiteral(sample.body)}`);
|
|
57
73
|
}
|
|
58
|
-
return `const response = await fetch(
|
|
74
|
+
return `const response = await fetch(${stringLiteral(sample.url)}, {\n${options.join(
|
|
59
75
|
",\n"
|
|
60
76
|
)}\n});`;
|
|
61
77
|
};
|
|
62
78
|
|
|
63
79
|
const pythonSnippet = (sample: RequestSample): string => {
|
|
64
|
-
const args = [`
|
|
80
|
+
const args = [` ${stringLiteral(sample.url)}`];
|
|
65
81
|
if (Object.keys(sample.headers).length > 0) {
|
|
66
82
|
const headers = headerLines(
|
|
67
83
|
sample.headers,
|
|
68
|
-
(key, value) => `
|
|
84
|
+
(key, value) => ` ${stringLiteral(key)}: ${stringLiteral(value)}`
|
|
69
85
|
).join(",\n");
|
|
70
86
|
args.push(` headers={\n${headers}\n }`);
|
|
71
87
|
}
|
|
72
88
|
if (sample.body) {
|
|
73
89
|
// Same rule as the fetch snippet: the raw text travels as a string via
|
|
74
|
-
// `data=`
|
|
75
|
-
// valid) rather than a `json=` dict — a Python literal re-serializes
|
|
90
|
+
// `data=` rather than a `json=` dict — a Python literal re-serializes
|
|
76
91
|
// `1e400` as `Infinity` and would otherwise diverge from the live send.
|
|
77
|
-
args.push(` data=${
|
|
92
|
+
args.push(` data=${stringLiteral(sample.body)}`);
|
|
78
93
|
}
|
|
79
94
|
return `import requests\n\nresponse = requests.${sample.method.toLowerCase()}(\n${args.join(
|
|
80
95
|
",\n"
|
package/src/core/base-path.ts
CHANGED
|
@@ -88,6 +88,21 @@ export const withBasePath = (basePath: string, route: string): string => {
|
|
|
88
88
|
return route === "/" ? basePath : `${basePath}${route}`;
|
|
89
89
|
};
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Mount a route Blume generates from content under `basePath`,
|
|
93
|
+
* unconditionally. {@link withBasePath} leaves a route that already starts
|
|
94
|
+
* with the base alone, which is right for a link an author based by hand but
|
|
95
|
+
* wrong for a content route: with `basePath: "/docs"`, `docs/guide.md` routes
|
|
96
|
+
* to `/docs/guide` before the base and publishes at `/docs/docs/guide`, not on
|
|
97
|
+
* top of the root `guide.md`.
|
|
98
|
+
*/
|
|
99
|
+
export const mountBasePath = (basePath: string, route: string): string => {
|
|
100
|
+
if (!basePath) {
|
|
101
|
+
return route;
|
|
102
|
+
}
|
|
103
|
+
return route === "/" ? basePath : `${basePath}${route}`;
|
|
104
|
+
};
|
|
105
|
+
|
|
91
106
|
/**
|
|
92
107
|
* {@link withBasePath} for the composed `deployment.base` + `basePath` stack
|
|
93
108
|
* (`/base` + `/docs` serves pages at `/base/docs/x`). The hand-written-base
|
package/src/core/config-input.ts
CHANGED
|
@@ -596,14 +596,14 @@ export interface LlmsTxtConfig {
|
|
|
596
596
|
/**
|
|
597
597
|
* Markdown placed after the title and summary in `llms.txt`, before the
|
|
598
598
|
* page sections — the llms.txt spec's "details" block. Use it to tell
|
|
599
|
-
* agents when to reach for the product and how to call it (
|
|
600
|
-
*
|
|
601
|
-
* dropped.
|
|
599
|
+
* agents when to reach for the product and how to call it (the install
|
|
600
|
+
* command, the package name). The spec allows any Markdown there but
|
|
601
|
+
* headings. Blank values are dropped.
|
|
602
602
|
*
|
|
603
603
|
* ```ts
|
|
604
604
|
* agents: {
|
|
605
605
|
* llmsTxt: {
|
|
606
|
-
* details: "
|
|
606
|
+
* details: "Use Acme when…",
|
|
607
607
|
* },
|
|
608
608
|
* }
|
|
609
609
|
* ```
|