blume 2.0.0 → 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/AGENTS.md +1 -1
- package/CHANGELOG.md +110 -0
- package/README.md +2 -2
- package/dist/cli/{chunk-f2972sbt.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-pat2zzwc.js → chunk-3yce002v.js} +21 -8
- package/dist/cli/{chunk-pat2zzwc.js.map → chunk-3yce002v.js.map} +4 -4
- package/dist/cli/{chunk-d1tadaw7.js → chunk-4e9b9ra6.js} +17 -7
- package/dist/cli/chunk-4e9b9ra6.js.map +10 -0
- package/dist/cli/{chunk-zg2gtj10.js → chunk-5r8g91qn.js} +352 -676
- package/dist/cli/chunk-5r8g91qn.js.map +34 -0
- package/dist/cli/{chunk-11j0384y.js → chunk-6dtt0zfn.js} +14 -14
- package/dist/cli/{chunk-11j0384y.js.map → chunk-6dtt0zfn.js.map} +3 -3
- package/dist/cli/{chunk-bw22s759.js → chunk-6k4ftwze.js} +38 -19
- package/dist/cli/{chunk-bw22s759.js.map → chunk-6k4ftwze.js.map} +4 -4
- package/dist/cli/{chunk-sqn5t4q0.js → chunk-7mbqtmgb.js} +16 -7
- package/dist/cli/chunk-7mbqtmgb.js.map +10 -0
- package/dist/cli/{chunk-79njf86q.js → chunk-7vtckvaw.js} +21 -19
- package/dist/cli/chunk-7vtckvaw.js.map +11 -0
- package/dist/cli/{chunk-fh5hj5jt.js → chunk-8g8ytmgx.js} +17 -18
- package/dist/cli/{chunk-fh5hj5jt.js.map → chunk-8g8ytmgx.js.map} +2 -2
- package/dist/cli/{chunk-1w8dp3qb.js → chunk-91ws1n6j.js} +18 -15
- package/dist/cli/chunk-91ws1n6j.js.map +10 -0
- package/dist/cli/{chunk-7ez8ny0t.js → chunk-bbnwccaz.js} +2 -2
- package/dist/cli/{chunk-5a2z0198.js → chunk-bfwp9vp6.js} +18 -10
- package/dist/cli/chunk-bfwp9vp6.js.map +10 -0
- package/dist/cli/{chunk-ernrthtr.js → chunk-d1v5rhy0.js} +14 -15
- package/dist/cli/{chunk-ernrthtr.js.map → chunk-d1v5rhy0.js.map} +2 -2
- package/dist/cli/{chunk-a9kptbw5.js → chunk-ddndchfr.js} +21 -6
- package/dist/cli/chunk-ddndchfr.js.map +14 -0
- package/dist/cli/{chunk-zxccj738.js → chunk-esh98wmb.js} +1 -1
- package/dist/cli/{chunk-88cpgt6h.js → chunk-fsmrqk8a.js} +1 -1
- package/dist/cli/{chunk-b5aj94ah.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-41za066z.js → chunk-h2ez8dzb.js} +4 -4
- package/dist/cli/{chunk-by2290sx.js → chunk-h7k3nq3v.js} +2 -2
- package/dist/cli/{chunk-j8mw0za6.js → chunk-hqp2ajnh.js} +252 -123
- package/dist/cli/chunk-hqp2ajnh.js.map +35 -0
- package/dist/cli/{chunk-mnqj32sj.js → chunk-hr8ne106.js} +119 -50
- package/dist/cli/chunk-hr8ne106.js.map +13 -0
- package/dist/cli/{chunk-mwt1k8n7.js → chunk-j85scx15.js} +74 -30
- package/dist/cli/chunk-j85scx15.js.map +10 -0
- package/dist/cli/{chunk-z01ze5c1.js → chunk-k7pj68a8.js} +63 -22
- package/dist/cli/chunk-k7pj68a8.js.map +11 -0
- package/dist/cli/{chunk-2q1dwty4.js → chunk-mqc662a6.js} +8 -8
- package/dist/cli/{chunk-2q1dwty4.js.map → chunk-mqc662a6.js.map} +4 -4
- package/dist/cli/{chunk-y3e45rc8.js → chunk-n1yg3tj3.js} +4 -4
- package/dist/cli/{chunk-bctazmbk.js → chunk-nfcyttvj.js} +17 -6
- package/dist/cli/chunk-nfcyttvj.js.map +10 -0
- package/dist/cli/{chunk-6k8vp3ta.js → chunk-pbg5a4s3.js} +60 -28
- package/dist/cli/chunk-pbg5a4s3.js.map +19 -0
- package/dist/cli/{chunk-d80hr03s.js → chunk-ppzjqwx2.js} +24 -17
- package/dist/cli/{chunk-d80hr03s.js.map → chunk-ppzjqwx2.js.map} +4 -4
- package/dist/cli/{chunk-beat36xx.js → chunk-qkb5a8sa.js} +25 -10
- package/dist/cli/chunk-qkb5a8sa.js.map +10 -0
- package/dist/cli/{chunk-bnbmcwfb.js → chunk-sqw4ekg1.js} +5 -5
- package/dist/cli/{chunk-bnbmcwfb.js.map → chunk-sqw4ekg1.js.map} +3 -3
- package/dist/cli/{chunk-xaz13gwg.js → chunk-v6ya5kcb.js} +3268 -1150
- package/dist/cli/chunk-v6ya5kcb.js.map +189 -0
- package/dist/cli/{chunk-tzne8qfq.js → chunk-w4bxdvsa.js} +18 -15
- package/dist/cli/chunk-w4bxdvsa.js.map +10 -0
- package/dist/cli/{chunk-f7t03s3g.js → chunk-wdrt2k2v.js} +2 -2
- package/dist/cli/{chunk-z1f5arsg.js → chunk-xh43dwgw.js} +170 -55
- package/dist/cli/chunk-xh43dwgw.js.map +36 -0
- package/dist/cli/{chunk-pnnvybbk.js → chunk-zp79m0ts.js} +5 -5
- package/dist/cli/{chunk-pnnvybbk.js.map → chunk-zp79m0ts.js.map} +2 -2
- package/dist/cli/index.js +160 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-readability.d.ts +1 -1
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api/paths.d.ts +1 -1
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +14 -7
- package/dist/types/ai/ask.d.ts +43 -43
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/index.d.ts +3 -3
- package/dist/types/ai/openapi-components.d.ts +1 -1
- package/dist/types/ai/relative-links.d.ts +9 -4
- package/dist/types/ai/serializers.d.ts +1 -1
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/ai/visibility.d.ts +1 -1
- 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 +21 -21
- package/dist/types/core/config.d.ts +5 -5
- package/dist/types/core/data.d.ts +3 -3
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/i18n-ui.d.ts +37 -8
- 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 +57 -18
- 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/core/unrecognized-keys.d.ts +1 -1
- 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/documents.d.ts +1 -1
- package/dist/types/search/orama-index.d.ts +1 -1
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +21 -12
- package/docs/03-upgrading.mdx +22 -9
- package/docs/04-migrating.mdx +4 -4
- package/docs/08-faq.mdx +12 -5
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +5 -3
- package/docs/advanced/skills.mdx +1 -1
- package/docs/cli/audit.mdx +5 -5
- package/docs/cli/doctor.mdx +4 -4
- package/docs/cli/evals.mdx +9 -9
- package/docs/cli/index.mdx +6 -3
- package/docs/cli/translate.mdx +8 -8
- package/docs/configuration/analytics.mdx +23 -2
- package/docs/configuration/{ask-ai.mdx → assistant.mdx} +20 -20
- package/docs/configuration/customization.mdx +5 -4
- package/docs/configuration/index.mdx +7 -5
- package/docs/configuration/meta.ts +1 -1
- package/docs/configuration/search.mdx +2 -2
- package/docs/content/components.mdx +1 -1
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +3 -3
- package/docs/content/index.mdx +4 -2
- package/docs/content/islands.mdx +1 -1
- 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 +22 -8
- package/docs/discoverability/index.mdx +3 -3
- 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/index.mdx +2 -2
- 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/SKILL.md +5 -5
- 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-readability.ts +4 -4
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/api/paths.ts +1 -1
- package/src/ai/api/spec.ts +15 -2
- package/src/ai/api-catalog.ts +7 -1
- package/src/ai/ask-context.ts +21 -9
- package/src/ai/ask-data.ts +28 -14
- package/src/ai/ask.ts +84 -71
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/cors.ts +3 -3
- package/src/ai/index.ts +16 -16
- 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/openapi-components.ts +1 -1
- package/src/ai/relative-links.ts +78 -10
- package/src/ai/serializers.ts +1 -1
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/visibility.ts +46 -15
- 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 +90 -45
- package/src/astro/module-types.ts +1 -1
- package/src/astro/runtime-deps.ts +6 -6
- package/src/astro/templates.ts +87 -49
- 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/blume-modules.d.ts +2 -2
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +8 -1
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/doctor.ts +7 -5
- package/src/cli/commands/eval.ts +4 -10
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/migrate.ts +2 -2
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +12 -9
- package/src/cli/commands/upgrade.ts +13 -2
- 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/required-secrets.ts +3 -3
- 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 +36 -9
- package/src/components/islands/{AskAI.astro → Assistant.astro} +10 -10
- package/src/components/islands/{ask-ai.tsx → assistant.tsx} +39 -25
- package/src/components/islands/hooks.ts +21 -14
- package/src/components/islands/webmcp.ts +12 -8
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Header.astro +32 -19
- 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 +28 -14
- package/src/components/layout/Pagination.astro +7 -7
- package/src/components/layout/ReferenceLayout.astro +5 -2
- package/src/components/layout/RootLayout.astro +27 -14
- package/src/components/layout/Search.astro +18 -14
- package/src/components/layout/analytics-client.ts +3 -1
- package/src/components/layout/drawer-inert.ts +1 -1
- 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/description.ts +2 -2
- 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/code-fences.ts +1 -1
- package/src/core/config-input.ts +23 -23
- package/src/core/config.ts +21 -7
- package/src/core/data.ts +3 -3
- package/src/core/diagnostics.ts +217 -30
- package/src/core/graph.ts +120 -11
- package/src/core/i18n-ui.ts +74 -11
- 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/request-body.ts +1 -1
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +95 -34
- package/src/core/server-features.ts +2 -2
- 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 +17 -5
- package/src/core/ui-packs/bg.ts +17 -5
- package/src/core/ui-packs/bn.ts +17 -5
- package/src/core/ui-packs/ca.ts +17 -5
- package/src/core/ui-packs/cs.ts +17 -5
- package/src/core/ui-packs/da.ts +17 -5
- package/src/core/ui-packs/de.ts +17 -5
- package/src/core/ui-packs/el.ts +17 -5
- package/src/core/ui-packs/es.ts +17 -5
- package/src/core/ui-packs/fa.ts +17 -5
- package/src/core/ui-packs/fi.ts +17 -5
- package/src/core/ui-packs/fr.ts +17 -5
- package/src/core/ui-packs/he.ts +17 -5
- package/src/core/ui-packs/hi.ts +17 -5
- package/src/core/ui-packs/hr.ts +17 -5
- package/src/core/ui-packs/hu.ts +17 -5
- package/src/core/ui-packs/id.ts +17 -5
- package/src/core/ui-packs/it.ts +17 -5
- package/src/core/ui-packs/ja.ts +17 -5
- package/src/core/ui-packs/ko.ts +17 -5
- package/src/core/ui-packs/nl.ts +17 -5
- package/src/core/ui-packs/no.ts +17 -5
- package/src/core/ui-packs/pl.ts +17 -5
- package/src/core/ui-packs/pt-br.ts +17 -5
- package/src/core/ui-packs/pt.ts +17 -5
- package/src/core/ui-packs/ro.ts +17 -5
- package/src/core/ui-packs/ru.ts +17 -5
- package/src/core/ui-packs/sk.ts +17 -5
- package/src/core/ui-packs/sr.ts +17 -5
- package/src/core/ui-packs/sv.ts +17 -5
- package/src/core/ui-packs/th.ts +17 -5
- package/src/core/ui-packs/tr.ts +17 -5
- package/src/core/ui-packs/uk.ts +17 -5
- package/src/core/ui-packs/vi.ts +17 -5
- package/src/core/ui-packs/zh-tw.ts +17 -5
- package/src/core/ui-packs/zh.ts +17 -5
- package/src/core/unrecognized-keys.ts +1 -1
- 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 +135 -37
- package/src/search/documents.ts +24 -3
- package/src/search/orama-index.ts +1 -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/report.ts +1 -1
- 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 +37 -5
- package/dist/cli/chunk-1w8dp3qb.js.map +0 -10
- package/dist/cli/chunk-5a2z0198.js.map +0 -10
- package/dist/cli/chunk-6k8vp3ta.js.map +0 -19
- package/dist/cli/chunk-79njf86q.js.map +0 -11
- package/dist/cli/chunk-a9kptbw5.js.map +0 -14
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-bctazmbk.js.map +0 -10
- package/dist/cli/chunk-beat36xx.js.map +0 -10
- package/dist/cli/chunk-d1tadaw7.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-j8mw0za6.js.map +0 -35
- package/dist/cli/chunk-mnqj32sj.js.map +0 -12
- package/dist/cli/chunk-mwt1k8n7.js.map +0 -10
- package/dist/cli/chunk-nk3ts2xk.js +0 -51
- package/dist/cli/chunk-nk3ts2xk.js.map +0 -10
- package/dist/cli/chunk-sqn5t4q0.js.map +0 -10
- package/dist/cli/chunk-tzne8qfq.js.map +0 -10
- package/dist/cli/chunk-xaz13gwg.js.map +0 -182
- package/dist/cli/chunk-z01ze5c1.js.map +0 -10
- package/dist/cli/chunk-z1f5arsg.js.map +0 -36
- package/dist/cli/chunk-zg2gtj10.js.map +0 -35
- /package/dist/cli/{chunk-f2972sbt.js.map → chunk-00gs3wqs.js.map} +0 -0
- /package/dist/cli/{chunk-7ez8ny0t.js.map → chunk-bbnwccaz.js.map} +0 -0
- /package/dist/cli/{chunk-zxccj738.js.map → chunk-esh98wmb.js.map} +0 -0
- /package/dist/cli/{chunk-88cpgt6h.js.map → chunk-fsmrqk8a.js.map} +0 -0
- /package/dist/cli/{chunk-b5aj94ah.js.map → chunk-g698a744.js.map} +0 -0
- /package/dist/cli/{chunk-41za066z.js.map → chunk-h2ez8dzb.js.map} +0 -0
- /package/dist/cli/{chunk-by2290sx.js.map → chunk-h7k3nq3v.js.map} +0 -0
- /package/dist/cli/{chunk-y3e45rc8.js.map → chunk-n1yg3tj3.js.map} +0 -0
- /package/dist/cli/{chunk-f7t03s3g.js.map → chunk-wdrt2k2v.js.map} +0 -0
|
@@ -152,17 +152,31 @@ export const resolveSchema = (
|
|
|
152
152
|
return schema;
|
|
153
153
|
};
|
|
154
154
|
|
|
155
|
-
const
|
|
155
|
+
const declaredTypeList = (type: string | string[] | undefined): string[] => {
|
|
156
156
|
if (!type) {
|
|
157
157
|
return [];
|
|
158
158
|
}
|
|
159
|
-
return
|
|
159
|
+
return Array.isArray(type) ? type : [type];
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const nonNullTypes = (type: string | string[] | undefined): string[] =>
|
|
163
|
+
declaredTypeList(type).filter((t) => t !== "null");
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Whether a schema admits only `null`: `{ type: "null" }`, the branch Scalar's
|
|
167
|
+
* upgrade pairs with a 3.0 `nullable: true` `$ref` (`anyOf: [$ref, { type:
|
|
168
|
+
* "null" }]`).
|
|
169
|
+
*/
|
|
170
|
+
const isNullType = (schema: SchemaLike): boolean => {
|
|
171
|
+
const types = declaredTypeList(schema.type);
|
|
172
|
+
return types.length > 0 && types.every((type) => type === "null");
|
|
160
173
|
};
|
|
161
174
|
|
|
162
175
|
/**
|
|
163
176
|
* A short, human-readable type label for a schema row. `$ref`s label by name
|
|
164
177
|
* (`Pet`, `Pet[]`) without resolving — which also means circular refs through
|
|
165
|
-
* array items can't recurse forever.
|
|
178
|
+
* array items can't recurse forever. A `null` member stays out of a union's
|
|
179
|
+
* label: rows mark it with {@link isNullable}, as they do `type: [T, "null"]`.
|
|
166
180
|
*/
|
|
167
181
|
export const typeLabel = (schema: SchemaLike): string => {
|
|
168
182
|
if (isString(schema.$ref)) {
|
|
@@ -170,24 +184,42 @@ export const typeLabel = (schema: SchemaLike): string => {
|
|
|
170
184
|
}
|
|
171
185
|
if (schema.oneOf || schema.anyOf) {
|
|
172
186
|
const branches = schema.oneOf ?? schema.anyOf ?? [];
|
|
173
|
-
const
|
|
187
|
+
const members = branches.filter((branch) => !isNullType(branch));
|
|
188
|
+
if (members.length === 0 && branches.length > 0) {
|
|
189
|
+
return "null";
|
|
190
|
+
}
|
|
191
|
+
const labels = members.map((branch) => typeLabel(branch));
|
|
174
192
|
return [...new Set(labels)].join(" | ") || "any";
|
|
175
193
|
}
|
|
176
194
|
if (schema.allOf) {
|
|
177
195
|
return "object";
|
|
178
196
|
}
|
|
179
197
|
const types = nonNullTypes(schema.type);
|
|
198
|
+
const arrayLabel = (): string => `${typeLabel(schema.items ?? {})}[]`;
|
|
199
|
+
if (types.length > 1) {
|
|
200
|
+
// A 3.1 type array names every type the value may take, not just the first.
|
|
201
|
+
return types
|
|
202
|
+
.map((type) => (type === "array" ? arrayLabel() : type))
|
|
203
|
+
.join(" | ");
|
|
204
|
+
}
|
|
180
205
|
if (types.includes("array")) {
|
|
181
|
-
return
|
|
206
|
+
return arrayLabel();
|
|
207
|
+
}
|
|
208
|
+
if (types.length === 0 && isNullType(schema)) {
|
|
209
|
+
return "null";
|
|
182
210
|
}
|
|
183
211
|
const base = types[0] ?? (schema.properties ? "object" : "any");
|
|
184
212
|
return schema.format ? `${base}<${schema.format}>` : base;
|
|
185
213
|
};
|
|
186
214
|
|
|
187
|
-
/**
|
|
215
|
+
/**
|
|
216
|
+
* Whether this schema is nullable: 3.0 `nullable`, a 3.1 `"null"` in `type`,
|
|
217
|
+
* or a `{ type: "null" }` member of a `oneOf`/`anyOf` union.
|
|
218
|
+
*/
|
|
188
219
|
export const isNullable = (schema: SchemaLike): boolean =>
|
|
189
220
|
schema.nullable === true ||
|
|
190
|
-
(Array.isArray(schema.type) && schema.type.includes("null"))
|
|
221
|
+
(Array.isArray(schema.type) && schema.type.includes("null")) ||
|
|
222
|
+
[...(schema.oneOf ?? []), ...(schema.anyOf ?? [])].some(isNullType);
|
|
191
223
|
|
|
192
224
|
/** Human-readable validation constraints for a schema, in display order. */
|
|
193
225
|
export const constraints = (schema: SchemaLike): string[] => {
|
|
@@ -263,23 +295,26 @@ export const objectProperties = (
|
|
|
263
295
|
* Build a representative example value for a schema via openapi-sampler
|
|
264
296
|
* (Redoc's generator): declared `example`/`const`/`default`/`enum` values
|
|
265
297
|
* win, formats produce realistic placeholders (`email`, `uuid`, `date-time`),
|
|
266
|
-
* `
|
|
267
|
-
*
|
|
268
|
-
*
|
|
298
|
+
* and circular `$ref` chains — which keeping refs intact allows — terminate
|
|
299
|
+
* safely. A request sample skips `readOnly` fields (a server-generated field
|
|
300
|
+
* has no place in one); a response sample skips `writeOnly` fields (a
|
|
301
|
+
* password the client sends never comes back) and keeps the `readOnly` ones.
|
|
269
302
|
*/
|
|
270
303
|
export const exampleValue = (
|
|
271
304
|
schema: SchemaLike | undefined,
|
|
272
|
-
schemas: Record<string, SchemaLike
|
|
305
|
+
schemas: Record<string, SchemaLike>,
|
|
306
|
+
direction: "request" | "response" = "request"
|
|
273
307
|
): SpecValue => {
|
|
274
308
|
if (!schema) {
|
|
275
309
|
return null;
|
|
276
310
|
}
|
|
311
|
+
const response = direction === "response";
|
|
277
312
|
try {
|
|
278
313
|
// SAFETY: SchemaLike structurally covers the JSONSchema7 fields the
|
|
279
314
|
// sampler reads, and the sampler only ever assembles JSON values.
|
|
280
315
|
return sample(
|
|
281
316
|
schema as Parameters<typeof sample>[0],
|
|
282
|
-
{ quiet: true, skipReadOnly:
|
|
317
|
+
{ quiet: true, skipReadOnly: !response, skipWriteOnly: response },
|
|
283
318
|
{ components: { schemas } }
|
|
284
319
|
) as SpecValue;
|
|
285
320
|
} catch {
|
|
@@ -289,5 +324,48 @@ export const exampleValue = (
|
|
|
289
324
|
}
|
|
290
325
|
};
|
|
291
326
|
|
|
327
|
+
/** Where an author can declare an example: a parameter or a media type. */
|
|
328
|
+
export interface ExampleCarrier {
|
|
329
|
+
example?: SpecValue;
|
|
330
|
+
examples?: SpecValue;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const isRecord = (value: SpecValue): value is Record<string, SpecValue> =>
|
|
334
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* The example a parameter or media type declares: its `example`, else the
|
|
338
|
+
* first inline `value` in its `examples` map. Scalar's upgrade moves every
|
|
339
|
+
* OpenAPI 3.0 and Swagger 2.0 `example` into `examples.default.value`, and
|
|
340
|
+
* 3.1 authors write that map directly, so reading `example` alone would drop
|
|
341
|
+
* them all. `undefined` when nothing is declared.
|
|
342
|
+
*/
|
|
343
|
+
export const declaredExample = (carrier: ExampleCarrier): SpecValue => {
|
|
344
|
+
if (carrier.example !== undefined) {
|
|
345
|
+
return carrier.example;
|
|
346
|
+
}
|
|
347
|
+
const { examples } = carrier;
|
|
348
|
+
if (!isRecord(examples)) {
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
for (const entry of Object.values(examples)) {
|
|
352
|
+
if (isRecord(entry) && entry.value !== undefined) {
|
|
353
|
+
return entry.value;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return undefined;
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* A response media type's example for the Response panel: the declared one,
|
|
361
|
+
* else a sample built for the response direction (`readOnly` kept,
|
|
362
|
+
* `writeOnly` skipped).
|
|
363
|
+
*/
|
|
364
|
+
export const responseExample = (
|
|
365
|
+
media: ExampleCarrier & { schema?: SchemaLike },
|
|
366
|
+
schemas: Record<string, SchemaLike>
|
|
367
|
+
): SpecValue =>
|
|
368
|
+
declaredExample(media) ?? exampleValue(media.schema, schemas, "response");
|
|
369
|
+
|
|
292
370
|
/** Pretty-print a JSON value for an example/code block. */
|
|
293
371
|
export const toJson = <T>(value: T): string => JSON.stringify(value, null, 2);
|
|
@@ -199,6 +199,14 @@ export const initComposer = (root: HTMLElement): void => {
|
|
|
199
199
|
|
|
200
200
|
const client = createWsClient({ onFrame: renderFrame, onState: renderState });
|
|
201
201
|
|
|
202
|
+
// A ClientRouter navigation swaps this panel out of the document without
|
|
203
|
+
// unloading the page, so a live socket would stay open behind the next page
|
|
204
|
+
// — and coming back and connecting again would open a second one. Every
|
|
205
|
+
// swap replaces the panel, so the first one closes the socket for good.
|
|
206
|
+
document.addEventListener("astro:before-swap", () => client.disconnect(), {
|
|
207
|
+
once: true,
|
|
208
|
+
});
|
|
209
|
+
|
|
202
210
|
connectButton?.addEventListener("click", () => {
|
|
203
211
|
if (validatePayload().length > 0) {
|
|
204
212
|
return;
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
AsyncApiAction,
|
|
3
3
|
AsyncApiServerObject,
|
|
4
4
|
} from "../../openapi/asyncapi.ts";
|
|
5
|
+
import { withServerDefaults } from "../../openapi/model.ts";
|
|
5
6
|
import type { AsyncApiMessageLike, NamedMessage } from "./async.ts";
|
|
6
7
|
import { payloadSchema } from "./async.ts";
|
|
7
8
|
import { exampleValue, toJson } from "./helpers.ts";
|
|
@@ -78,9 +79,18 @@ const messagePayload = (
|
|
|
78
79
|
/**
|
|
79
80
|
* A server's base URL for the picker. Falls back to the bare host when the
|
|
80
81
|
* spec omits `protocol` — a label is a label, and the snippet builders read
|
|
81
|
-
* the server object itself rather than this string.
|
|
82
|
+
* the server object itself rather than this string. Server variables in the
|
|
83
|
+
* host and pathname (`{env}.events.example.com`) resolve to their declared
|
|
84
|
+
* defaults, in the label and in the object the samples and connect URL read.
|
|
82
85
|
*/
|
|
83
|
-
const serverOption = (
|
|
86
|
+
const serverOption = (spec: AsyncApiServerObject): MessageServerOption => {
|
|
87
|
+
const server = { ...spec };
|
|
88
|
+
if (spec.host !== undefined) {
|
|
89
|
+
server.host = withServerDefaults(spec.host, spec.variables);
|
|
90
|
+
}
|
|
91
|
+
if (spec.pathname !== undefined) {
|
|
92
|
+
server.pathname = withServerDefaults(spec.pathname, spec.variables);
|
|
93
|
+
}
|
|
84
94
|
const host = `${server.host ?? ""}${server.pathname ?? ""}`;
|
|
85
95
|
return {
|
|
86
96
|
label: server.protocol ? `${server.protocol}://${host}` : host,
|
|
@@ -40,7 +40,10 @@ export interface MessagePayload {
|
|
|
40
40
|
export interface MessageServerOption {
|
|
41
41
|
/** `protocol://host+pathname` — what the reader picks between. */
|
|
42
42
|
label: string;
|
|
43
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* The spec server with its host/pathname variables at their defaults; the
|
|
45
|
+
* snippet builders read host/pathname/protocol.
|
|
46
|
+
*/
|
|
44
47
|
server: AsyncApiServerObject;
|
|
45
48
|
}
|
|
46
49
|
|
|
@@ -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;
|