blume 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +147 -0
- package/dist/cli/{chunk-qwsrynx5.js → chunk-1d7ve1dm.js} +38 -19
- package/dist/cli/{chunk-qwsrynx5.js.map → chunk-1d7ve1dm.js.map} +4 -4
- package/dist/cli/{chunk-s6jhgk0q.js → chunk-2eytanqx.js} +2 -2
- package/dist/cli/{chunk-kdp5q7ke.js → chunk-2hsdwb9n.js} +18 -19
- package/dist/cli/{chunk-kdp5q7ke.js.map → chunk-2hsdwb9n.js.map} +2 -2
- package/dist/cli/{chunk-hdpx1tax.js → chunk-2z928egk.js} +5 -5
- package/dist/cli/{chunk-jwyddg7y.js → chunk-35d4wj9f.js} +30 -24
- package/dist/cli/chunk-35d4wj9f.js.map +15 -0
- package/dist/cli/{chunk-ah61y8py.js → chunk-364znk6q.js} +2 -2
- package/dist/cli/{chunk-jts8mvcz.js → chunk-3em5wd2y.js} +25 -6
- package/dist/cli/{chunk-jts8mvcz.js.map → chunk-3em5wd2y.js.map} +3 -3
- package/dist/cli/{chunk-s1p84fyh.js → chunk-5f86nr5m.js} +63 -22
- package/dist/cli/chunk-5f86nr5m.js.map +11 -0
- package/dist/cli/{chunk-2hn4b8z7.js → chunk-5m5nmvyq.js} +170 -76
- package/dist/cli/chunk-5m5nmvyq.js.map +13 -0
- package/dist/cli/{chunk-epjnccmv.js → chunk-5xvm6tfj.js} +18 -15
- package/dist/cli/chunk-5xvm6tfj.js.map +10 -0
- package/dist/cli/{chunk-fz5wtpmh.js → chunk-6dsbexzp.js} +18 -15
- package/dist/cli/chunk-6dsbexzp.js.map +10 -0
- package/dist/cli/{chunk-vtk4a6dg.js → chunk-8ktnccpt.js} +1 -1
- package/dist/cli/{chunk-6hsn950k.js → chunk-9t7a85s3.js} +178 -48
- package/dist/cli/chunk-9t7a85s3.js.map +10 -0
- package/dist/cli/{chunk-fxypxtvm.js → chunk-a58773jm.js} +2 -2
- package/dist/cli/{chunk-mb2919y2.js → chunk-acanzt5p.js} +17 -6
- package/dist/cli/chunk-acanzt5p.js.map +10 -0
- package/dist/cli/{chunk-27g6wdth.js → chunk-akbpwfxc.js} +90 -26
- package/dist/cli/chunk-akbpwfxc.js.map +10 -0
- package/dist/cli/{chunk-wm7js3j9.js → chunk-b07cmahc.js} +2 -2
- package/dist/cli/{chunk-wgm7m9qk.js → chunk-c8chx29p.js} +179 -51
- package/dist/cli/chunk-c8chx29p.js.map +36 -0
- package/dist/cli/{chunk-qs4q5p4e.js → chunk-crgn1q09.js} +32 -14
- package/dist/cli/chunk-crgn1q09.js.map +10 -0
- package/dist/cli/chunk-e04dxsz1.js +39 -0
- package/dist/cli/chunk-e04dxsz1.js.map +10 -0
- package/dist/cli/{chunk-yt5n7ppj.js → chunk-ey84smr6.js} +17 -7
- package/dist/cli/chunk-ey84smr6.js.map +10 -0
- package/dist/cli/{chunk-f2z5v128.js → chunk-g4hq16wv.js} +14 -15
- package/dist/cli/{chunk-f2z5v128.js.map → chunk-g4hq16wv.js.map} +2 -2
- package/dist/cli/{chunk-fa25z98p.js → chunk-ga0pf4aj.js} +9 -8
- package/dist/cli/chunk-ga0pf4aj.js.map +11 -0
- package/dist/cli/{chunk-kpf8rrjc.js → chunk-hm3vjy5s.js} +109 -58
- package/dist/cli/chunk-hm3vjy5s.js.map +19 -0
- package/dist/cli/{chunk-fs23ddbb.js → chunk-j85vccga.js} +625 -750
- package/dist/cli/chunk-j85vccga.js.map +36 -0
- package/dist/cli/{chunk-ch6g3ar0.js → chunk-p3v96n38.js} +6 -6
- package/dist/cli/{chunk-ch6g3ar0.js.map → chunk-p3v96n38.js.map} +3 -3
- package/dist/cli/{chunk-q5163e60.js → chunk-p73c0m7w.js} +21 -19
- package/dist/cli/chunk-p73c0m7w.js.map +11 -0
- package/dist/cli/{chunk-dh8cwk36.js → chunk-pehfxfta.js} +24 -9
- package/dist/cli/chunk-pehfxfta.js.map +10 -0
- package/dist/cli/{chunk-qkqwkpte.js → chunk-pv29h0wf.js} +3688 -1313
- package/dist/cli/chunk-pv29h0wf.js.map +190 -0
- package/dist/cli/{chunk-6vm74dry.js → chunk-q58y5e6a.js} +10 -10
- package/dist/cli/{chunk-6vm74dry.js.map → chunk-q58y5e6a.js.map} +3 -3
- package/dist/cli/{chunk-zxcczpyx.js → chunk-r20tn01b.js} +1 -1
- package/dist/cli/{chunk-m3vmjgmq.js → chunk-r9rcc4w7.js} +16 -8
- package/dist/cli/chunk-r9rcc4w7.js.map +10 -0
- package/dist/cli/{chunk-5shv93fd.js → chunk-tkacnehg.js} +2 -2
- package/dist/cli/{chunk-zxh4d9vy.js → chunk-tzmab476.js} +4 -4
- package/dist/cli/{chunk-yw7dm696.js → chunk-vg9r4eb9.js} +24 -11
- package/dist/cli/chunk-vg9r4eb9.js.map +14 -0
- package/dist/cli/{chunk-79jhk4py.js → chunk-wrr3j9w9.js} +260 -132
- package/dist/cli/chunk-wrr3j9w9.js.map +35 -0
- package/dist/cli/{chunk-6crbhc3x.js → chunk-yfyb25rh.js} +54 -27
- package/dist/cli/chunk-yfyb25rh.js.map +14 -0
- package/dist/cli/index.js +162 -35
- package/dist/cli/index.js.map +4 -4
- package/dist/types/ai/agent-surface.d.ts +32 -0
- package/dist/types/ai/api-catalog.d.ts +7 -1
- package/dist/types/ai/ask-context.d.ts +7 -0
- package/dist/types/ai/component-markdown.d.ts +4 -4
- package/dist/types/ai/link-headers.d.ts +8 -1
- package/dist/types/ai/openapi-components.d.ts +5 -2
- package/dist/types/ai/relative-links.d.ts +11 -4
- package/dist/types/ai/skills.d.ts +4 -1
- package/dist/types/ai/static-expression.d.ts +28 -0
- package/dist/types/ai/tar.d.ts +1 -3
- package/dist/types/analytics/databuddy.d.ts +43 -0
- package/dist/types/analytics/index.d.ts +4 -0
- package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
- package/dist/types/analytics/schema.d.ts +28 -0
- package/dist/types/astro/integration.d.ts +3 -2
- package/dist/types/cli/env.d.ts +5 -0
- package/dist/types/cli/init/scaffold.d.ts +19 -3
- package/dist/types/cli/init/starter-spec.d.ts +11 -0
- package/dist/types/core/base-path.d.ts +24 -1
- package/dist/types/core/config-input.d.ts +13 -11
- package/dist/types/core/config.d.ts +2 -2
- package/dist/types/core/directive-diagnostics.d.ts +12 -0
- package/dist/types/core/graph.d.ts +2 -0
- package/dist/types/core/heading-markers.d.ts +5 -7
- package/dist/types/core/i18n-ui.d.ts +31 -0
- package/dist/types/core/i18n.d.ts +9 -1
- package/dist/types/core/last-modified.d.ts +10 -0
- package/dist/types/core/links.d.ts +3 -1
- package/dist/types/core/load-module.d.ts +10 -0
- package/dist/types/core/locale-links.d.ts +12 -2
- package/dist/types/core/meta.d.ts +13 -1
- package/dist/types/core/nav-diagnostics.d.ts +10 -0
- package/dist/types/core/navigation.d.ts +38 -0
- package/dist/types/core/ordering-prefix.d.ts +4 -0
- package/dist/types/core/safe-links.d.ts +3 -1
- package/dist/types/core/schema.d.ts +59 -13
- package/dist/types/core/sources/github-releases.d.ts +5 -0
- package/dist/types/core/sources/lower.d.ts +38 -13
- package/dist/types/core/sources/normalize.d.ts +23 -2
- package/dist/types/core/sources/remote.d.ts +11 -1
- package/dist/types/core/sources/resolve.d.ts +12 -0
- package/dist/types/core/sources/types.d.ts +31 -0
- package/dist/types/core/sources/watch.d.ts +12 -5
- package/dist/types/core/standard-schema.d.ts +5 -0
- package/dist/types/core/types.d.ts +9 -0
- package/dist/types/deploy/adapters/node.d.ts +5 -2
- package/dist/types/deploy/adapters/types.d.ts +7 -0
- package/dist/types/deploy/artifacts.d.ts +6 -4
- package/dist/types/deploy/cloudflare-negotiation.d.ts +3 -2
- package/dist/types/deploy/headers.d.ts +36 -7
- package/dist/types/deploy/node-headers.d.ts +43 -8
- package/dist/types/deploy/platforms/netlify.d.ts +27 -2
- package/dist/types/deploy/platforms/node.d.ts +6 -5
- package/dist/types/deploy/platforms/types.d.ts +15 -0
- package/dist/types/deploy/platforms/vercel.d.ts +3 -2
- package/dist/types/deploy/redirects.d.ts +31 -15
- package/dist/types/deploy/vercel-negotiation.d.ts +3 -2
- package/dist/types/markdown/directives.d.ts +62 -0
- package/dist/types/markdown/features.d.ts +21 -0
- package/dist/types/markdown/mdast.d.ts +63 -0
- package/dist/types/openapi/asyncapi.d.ts +4 -2
- package/dist/types/openapi/model.d.ts +20 -6
- package/dist/types/search/sync/algolia.d.ts +3 -1
- package/docs/01-quickstart.mdx +3 -2
- package/docs/02-deployment.mdx +20 -9
- package/docs/08-faq.mdx +10 -3
- package/docs/advanced/changelog.mdx +1 -1
- package/docs/advanced/custom-pages.mdx +7 -5
- package/docs/cli/audit.mdx +19 -3
- package/docs/cli/doctor.mdx +2 -2
- package/docs/cli/evals.mdx +4 -4
- package/docs/cli/index.mdx +4 -1
- package/docs/cli/translate.mdx +4 -4
- package/docs/cli/version.mdx +1 -1
- package/docs/configuration/analytics.mdx +42 -2
- package/docs/configuration/assistant.mdx +1 -1
- package/docs/configuration/customization.mdx +6 -3
- package/docs/configuration/index.mdx +5 -3
- package/docs/configuration/search.mdx +2 -2
- package/docs/content/components.mdx +2 -2
- package/docs/content/frontmatter.mdx +5 -1
- package/docs/content/i18n.mdx +3 -1
- package/docs/content/index.mdx +8 -4
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +7 -3
- package/docs/content/navigation.mdx +29 -4
- package/docs/content/sources.mdx +18 -16
- package/docs/content/syntax.mdx +14 -0
- package/docs/content/versioning.mdx +2 -1
- package/docs/discoverability/agent-discovery.mdx +22 -8
- package/docs/discoverability/index.mdx +4 -3
- package/docs/discoverability/llms-txt.mdx +2 -5
- package/docs/discoverability/markdown.mdx +6 -4
- package/docs/discoverability/mcp.mdx +4 -0
- package/docs/discoverability/metadata.mdx +3 -2
- package/docs/discoverability/open-graph.mdx +8 -4
- package/docs/discoverability/rss.mdx +4 -2
- package/docs/references/asyncapi.mdx +2 -2
- package/docs/references/graphql.mdx +2 -2
- package/docs/references/openapi.mdx +6 -4
- package/package.json +1 -1
- package/skills/blume-migrate/SKILL.md +6 -6
- package/skills/blume-migrate/references/docusaurus.md +6 -6
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +3 -3
- package/skills/blume-migrate/references/monorepo.md +1 -1
- package/skills/blume-migrate/references/nextra.md +2 -2
- package/skills/blume-migrate/references/starlight.md +5 -5
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +9 -4
- package/skills/blume-update-docs/references/audit-checklist.md +1 -1
- package/src/ai/agent-readability.ts +2 -2
- package/src/ai/agent-surface.ts +56 -0
- package/src/ai/ai-catalog.ts +6 -2
- package/src/ai/api/handlers.ts +2 -2
- package/src/ai/api/spec.ts +17 -4
- package/src/ai/api-catalog.ts +13 -3
- package/src/ai/ask-context.ts +14 -2
- package/src/ai/ask-data.ts +26 -12
- package/src/ai/changelog-markdown.ts +2 -2
- package/src/ai/component-markdown.ts +43 -37
- package/src/ai/link-headers.ts +22 -8
- package/src/ai/llms.ts +22 -10
- package/src/ai/markdown.ts +23 -11
- package/src/ai/mcp/discovery.ts +2 -2
- package/src/ai/mcp/query.ts +2 -2
- package/src/ai/mcp/server.ts +80 -9
- package/src/ai/openapi-components.ts +22 -6
- package/src/ai/relative-links.ts +99 -15
- package/src/ai/serializers.ts +2 -1
- package/src/ai/skills.ts +14 -1
- package/src/ai/static-expression.ts +416 -0
- package/src/ai/tar.ts +139 -12
- package/src/ai/visibility.ts +45 -14
- package/src/analytics/databuddy.ts +67 -0
- package/src/analytics/head.ts +8 -0
- package/src/analytics/index.ts +7 -0
- package/src/analytics/one-dollar-stats.ts +86 -0
- package/src/analytics/posthog.ts +21 -3
- package/src/analytics/schema.ts +4 -0
- package/src/astro/generate.ts +72 -28
- package/src/astro/include-hmr.ts +31 -12
- package/src/astro/include-refresh.ts +19 -8
- package/src/astro/integration.ts +108 -14
- package/src/astro/runtime-modules.ts +28 -13
- package/src/astro/templates.ts +139 -57
- package/src/audit/catalog.ts +2 -2
- package/src/audit/checks/assets.ts +25 -5
- package/src/audit/checks/content.ts +20 -2
- package/src/audit/checks/i18n.ts +46 -8
- package/src/audit/checks/indexability.ts +39 -19
- package/src/audit/checks/links.ts +22 -1
- package/src/audit/checks/llms.ts +6 -3
- package/src/audit/checks/network.ts +3 -1
- package/src/audit/checks/og-image.ts +10 -0
- package/src/audit/checks/robots.ts +6 -1
- package/src/audit/checks/sitemap.ts +56 -31
- package/src/audit/checks/social.ts +21 -2
- package/src/audit/crawl.ts +88 -15
- package/src/audit/graph.ts +3 -1
- package/src/audit/report.ts +54 -17
- package/src/audit/run.ts +13 -9
- package/src/audit/snapshot.ts +5 -0
- package/src/audit/types.ts +18 -0
- package/src/audit/url.ts +37 -6
- package/src/cli/args.ts +32 -0
- package/src/cli/build-failure.ts +50 -0
- package/src/cli/commands/audit.ts +11 -1
- package/src/cli/commands/build.ts +19 -5
- package/src/cli/commands/check.ts +2 -0
- package/src/cli/commands/doctor.ts +3 -1
- package/src/cli/commands/eval.ts +20 -18
- package/src/cli/commands/init.ts +15 -5
- package/src/cli/commands/preview.ts +15 -0
- package/src/cli/commands/sync.ts +2 -0
- package/src/cli/commands/translate.ts +18 -18
- package/src/cli/commands/upgrade.ts +11 -0
- package/src/cli/commands/validate.ts +3 -1
- package/src/cli/dev-lock.ts +157 -37
- package/src/cli/eject-scripts.ts +32 -7
- package/src/cli/env.ts +12 -1
- package/src/cli/init/scaffold.ts +117 -11
- package/src/cli/init/starter-spec.ts +235 -0
- package/src/cli/report-format.ts +11 -6
- package/src/components/colors.ts +19 -0
- package/src/components/content/AccordionItem.astro +26 -22
- package/src/components/content/Badge.astro +7 -12
- package/src/components/content/Card.astro +2 -2
- package/src/components/content/Component.astro +11 -5
- package/src/components/content/Expandable.astro +5 -1
- package/src/components/content/Frame.astro +2 -7
- package/src/components/content/GithubInfo.astro +12 -2
- package/src/components/content/Prompt.astro +2 -7
- package/src/components/content/Tab.astro +0 -1
- package/src/components/content/Tabs.astro +58 -5
- package/src/components/content/Tile.astro +1 -1
- package/src/components/content/Tooltip.astro +69 -7
- package/src/components/content/Tree.astro +7 -2
- package/src/components/content/TypeTable.astro +10 -5
- package/src/components/content/Update.astro +8 -2
- package/src/components/content/auto-type-table.ts +4 -1
- package/src/components/content/badge-color.ts +20 -0
- package/src/components/content/base-href.ts +14 -22
- package/src/components/content/inline-markdown.ts +27 -7
- package/src/components/copy-feedback.ts +35 -8
- package/src/components/islands/assistant.tsx +37 -6
- package/src/components/islands/base-path.ts +47 -10
- package/src/components/islands/hooks.ts +42 -21
- package/src/components/islands/webmcp.ts +16 -10
- package/src/components/layout/Banner.astro +23 -4
- package/src/components/layout/Breadcrumbs.astro +5 -2
- package/src/components/layout/DiscoveryLinks.astro +9 -5
- package/src/components/layout/Header.astro +23 -10
- package/src/components/layout/LanguageSwitcher.astro +2 -2
- package/src/components/layout/Logo.astro +5 -0
- package/src/components/layout/NavSelector.astro +8 -3
- package/src/components/layout/NavTabMenu.astro +133 -0
- package/src/components/layout/NavTree.astro +31 -12
- package/src/components/layout/NavTreeCache.astro +5 -2
- package/src/components/layout/NavTreeScript.astro +45 -5
- package/src/components/layout/PageActions.astro +4 -3
- package/src/components/layout/PageLayout.astro +28 -13
- package/src/components/layout/Pagination.astro +3 -3
- package/src/components/layout/ReferenceLayout.astro +4 -1
- package/src/components/layout/RootLayout.astro +25 -12
- package/src/components/layout/Search.astro +38 -14
- package/src/components/layout/VersionBanner.astro +2 -2
- package/src/components/layout/analytics-client.ts +14 -0
- package/src/components/layout/toc-active.ts +41 -0
- package/src/components/layout/toc-element.ts +8 -14
- package/src/components/openapi/ApiTagOperations.astro +2 -2
- package/src/components/openapi/AsyncApiOperation.astro +7 -4
- package/src/components/openapi/GraphqlChip.astro +2 -2
- package/src/components/openapi/GraphqlType.astro +11 -3
- package/src/components/openapi/MessageComposer.astro +1 -1
- package/src/components/openapi/Operation.astro +23 -5
- package/src/components/openapi/PanelTabs.astro +4 -1
- package/src/components/openapi/Playground.astro +8 -2
- package/src/components/openapi/RequestPanel.astro +13 -6
- package/src/components/openapi/SchemaProperty.astro +11 -33
- package/src/components/openapi/SchemaTable.astro +34 -52
- package/src/components/openapi/async.ts +38 -6
- package/src/components/openapi/helpers.ts +100 -12
- package/src/components/openapi/message-composer.ts +14 -1
- package/src/components/openapi/message-model.ts +12 -2
- package/src/components/openapi/message.ts +21 -3
- package/src/components/openapi/operation-model.ts +119 -17
- package/src/components/openapi/panel.ts +31 -5
- package/src/components/openapi/param-style.ts +181 -0
- package/src/components/openapi/playground-client.ts +110 -23
- package/src/components/openapi/playground-schema.ts +25 -6
- package/src/components/openapi/request.ts +192 -26
- package/src/components/openapi/schema-tree.ts +209 -0
- package/src/components/openapi/snippets.ts +113 -19
- package/src/components/openapi/validate-json.ts +1 -1
- package/src/components/openapi/ws-client.ts +18 -2
- package/src/core/base-path.ts +69 -8
- package/src/core/config-input.ts +13 -11
- package/src/core/config.ts +18 -4
- package/src/core/diagnostics.ts +219 -30
- package/src/core/directive-diagnostics.ts +99 -0
- package/src/core/frontmatter.ts +21 -18
- package/src/core/graph.ts +120 -11
- package/src/core/heading-markers.ts +5 -18
- package/src/core/i18n-ui.ts +39 -2
- package/src/core/i18n.ts +44 -5
- package/src/core/last-modified.ts +25 -3
- package/src/core/links.ts +7 -4
- package/src/core/load-module.ts +20 -0
- package/src/core/locale-links.ts +22 -18
- package/src/core/manifest.ts +3 -2
- package/src/core/meta.ts +89 -12
- package/src/core/nav-diagnostics.ts +56 -1
- package/src/core/navigation.ts +272 -83
- package/src/core/ordering-prefix.ts +27 -0
- package/src/core/project-graph.ts +50 -6
- package/src/core/safe-href.ts +53 -1
- package/src/core/safe-links.ts +11 -2
- package/src/core/schema.ts +94 -18
- package/src/core/sources/assets.ts +83 -41
- package/src/core/sources/contentful-rich-text.ts +28 -20
- package/src/core/sources/contentful.ts +25 -12
- package/src/core/sources/filesystem.ts +25 -3
- package/src/core/sources/github-releases.ts +131 -11
- package/src/core/sources/lexical.ts +30 -20
- package/src/core/sources/lower.ts +276 -56
- package/src/core/sources/mdx-remote.ts +52 -16
- package/src/core/sources/normalize.ts +456 -119
- package/src/core/sources/notion.ts +77 -34
- package/src/core/sources/obsidian.ts +40 -9
- package/src/core/sources/payload.ts +1 -0
- package/src/core/sources/portable-text.ts +85 -49
- package/src/core/sources/remote.ts +18 -2
- package/src/core/sources/resolve.ts +52 -33
- package/src/core/sources/sanity.ts +1 -0
- package/src/core/sources/strapi-blocks.ts +28 -19
- package/src/core/sources/strapi.ts +1 -0
- package/src/core/sources/types.ts +31 -0
- package/src/core/sources/watch.ts +20 -7
- package/src/core/standard-schema.ts +10 -6
- package/src/core/types.ts +9 -0
- package/src/core/ui-packs/ar.ts +13 -0
- package/src/core/ui-packs/bg.ts +13 -0
- package/src/core/ui-packs/bn.ts +13 -0
- package/src/core/ui-packs/ca.ts +13 -0
- package/src/core/ui-packs/cs.ts +13 -0
- package/src/core/ui-packs/da.ts +13 -0
- package/src/core/ui-packs/de.ts +13 -0
- package/src/core/ui-packs/el.ts +13 -0
- package/src/core/ui-packs/es.ts +13 -0
- package/src/core/ui-packs/fa.ts +13 -0
- package/src/core/ui-packs/fi.ts +13 -0
- package/src/core/ui-packs/fr.ts +13 -0
- package/src/core/ui-packs/he.ts +13 -0
- package/src/core/ui-packs/hi.ts +13 -0
- package/src/core/ui-packs/hr.ts +13 -0
- package/src/core/ui-packs/hu.ts +13 -0
- package/src/core/ui-packs/id.ts +13 -0
- package/src/core/ui-packs/it.ts +13 -0
- package/src/core/ui-packs/ja.ts +13 -0
- package/src/core/ui-packs/ko.ts +13 -0
- package/src/core/ui-packs/nl.ts +13 -0
- package/src/core/ui-packs/no.ts +13 -0
- package/src/core/ui-packs/pl.ts +13 -0
- package/src/core/ui-packs/pt-br.ts +13 -0
- package/src/core/ui-packs/pt.ts +13 -0
- package/src/core/ui-packs/ro.ts +13 -0
- package/src/core/ui-packs/ru.ts +13 -0
- package/src/core/ui-packs/sk.ts +13 -0
- package/src/core/ui-packs/sr.ts +13 -0
- package/src/core/ui-packs/sv.ts +13 -0
- package/src/core/ui-packs/th.ts +13 -0
- package/src/core/ui-packs/tr.ts +13 -0
- package/src/core/ui-packs/uk.ts +13 -0
- package/src/core/ui-packs/vi.ts +13 -0
- package/src/core/ui-packs/zh-tw.ts +13 -0
- package/src/core/ui-packs/zh.ts +13 -0
- package/src/core/version-cut.ts +69 -17
- package/src/core/versions.ts +4 -1
- package/src/deploy/adapters/node.ts +5 -2
- package/src/deploy/adapters/registry.ts +2 -1
- package/src/deploy/adapters/types.ts +13 -1
- package/src/deploy/artifacts.ts +52 -11
- package/src/deploy/cloudflare-negotiation.ts +27 -16
- package/src/deploy/headers.ts +75 -55
- package/src/deploy/node-headers.ts +148 -27
- package/src/deploy/platforms/cloudflare.ts +13 -3
- package/src/deploy/platforms/netlify.ts +83 -5
- package/src/deploy/platforms/node.ts +8 -5
- package/src/deploy/platforms/static.ts +2 -0
- package/src/deploy/platforms/types.ts +15 -0
- package/src/deploy/platforms/vercel.ts +10 -3
- package/src/deploy/redirects.ts +68 -21
- package/src/deploy/robots.ts +2 -2
- package/src/deploy/rss.ts +4 -3
- package/src/deploy/sitemap.ts +7 -5
- package/src/deploy/vercel-negotiation.ts +35 -3
- package/src/eval/agents.ts +10 -2
- package/src/eval/run.ts +25 -0
- package/src/markdown/base-links.ts +74 -29
- package/src/markdown/directives.ts +242 -36
- package/src/markdown/features.ts +17 -0
- package/src/markdown/index.ts +13 -9
- package/src/markdown/mdast.ts +5 -2
- package/src/markdown/relative-links.ts +15 -27
- package/src/markdown/route-snapshot.ts +37 -0
- package/src/og/card.ts +149 -9
- package/src/og/derive.ts +156 -5
- package/src/og/index.ts +1 -0
- package/src/openapi/asyncapi.ts +4 -2
- package/src/openapi/graphql-build.ts +28 -2
- package/src/openapi/model.ts +99 -27
- package/src/openapi/proxy.ts +63 -10
- package/src/openapi/render-mdx.ts +51 -3
- package/src/registry/eject.ts +297 -43
- package/src/search/adapters/version-scope.ts +30 -0
- package/src/search/documents.ts +89 -27
- package/src/search/popular.ts +2 -1
- package/src/search/sync/algolia.ts +36 -2
- package/src/seo/jsonld.ts +7 -3
- package/src/sources/registry.ts +5 -0
- package/src/theme/entry.ts +11 -4
- package/src/translate/agents.ts +6 -1
- package/src/translate/ledger.ts +26 -3
- package/src/translate/meta.ts +76 -24
- package/src/translate/run.ts +14 -8
- package/src/translate/validate.ts +14 -2
- package/src/translate/work-list.ts +91 -19
- package/src/upgrade/upgrade.ts +36 -4
- package/dist/cli/chunk-27g6wdth.js.map +0 -10
- package/dist/cli/chunk-2hn4b8z7.js.map +0 -12
- package/dist/cli/chunk-6crbhc3x.js.map +0 -14
- package/dist/cli/chunk-6hsn950k.js.map +0 -10
- package/dist/cli/chunk-79jhk4py.js.map +0 -35
- package/dist/cli/chunk-82bbrxdn.js +0 -51
- package/dist/cli/chunk-82bbrxdn.js.map +0 -10
- package/dist/cli/chunk-abh8yjkn.js +0 -31
- package/dist/cli/chunk-abh8yjkn.js.map +0 -10
- package/dist/cli/chunk-ce574jw2.js +0 -23
- package/dist/cli/chunk-ce574jw2.js.map +0 -10
- package/dist/cli/chunk-dh8cwk36.js.map +0 -10
- package/dist/cli/chunk-epjnccmv.js.map +0 -10
- package/dist/cli/chunk-fa25z98p.js.map +0 -11
- package/dist/cli/chunk-fs23ddbb.js.map +0 -35
- package/dist/cli/chunk-fz5wtpmh.js.map +0 -10
- package/dist/cli/chunk-jwyddg7y.js.map +0 -15
- package/dist/cli/chunk-kpf8rrjc.js.map +0 -19
- package/dist/cli/chunk-m3vmjgmq.js.map +0 -10
- package/dist/cli/chunk-mb2919y2.js.map +0 -10
- package/dist/cli/chunk-q5163e60.js.map +0 -11
- package/dist/cli/chunk-qkqwkpte.js.map +0 -182
- package/dist/cli/chunk-qs4q5p4e.js.map +0 -10
- package/dist/cli/chunk-s1p84fyh.js.map +0 -10
- package/dist/cli/chunk-wgm7m9qk.js.map +0 -36
- package/dist/cli/chunk-yt5n7ppj.js.map +0 -10
- package/dist/cli/chunk-yw7dm696.js.map +0 -14
- /package/dist/cli/{chunk-s6jhgk0q.js.map → chunk-2eytanqx.js.map} +0 -0
- /package/dist/cli/{chunk-hdpx1tax.js.map → chunk-2z928egk.js.map} +0 -0
- /package/dist/cli/{chunk-ah61y8py.js.map → chunk-364znk6q.js.map} +0 -0
- /package/dist/cli/{chunk-vtk4a6dg.js.map → chunk-8ktnccpt.js.map} +0 -0
- /package/dist/cli/{chunk-fxypxtvm.js.map → chunk-a58773jm.js.map} +0 -0
- /package/dist/cli/{chunk-wm7js3j9.js.map → chunk-b07cmahc.js.map} +0 -0
- /package/dist/cli/{chunk-zxcczpyx.js.map → chunk-r20tn01b.js.map} +0 -0
- /package/dist/cli/{chunk-5shv93fd.js.map → chunk-tkacnehg.js.map} +0 -0
- /package/dist/cli/{chunk-zxh4d9vy.js.map → chunk-tzmab476.js.map} +0 -0
package/src/cli/init/scaffold.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
|
|
4
|
+
import { loadAll } from "js-yaml";
|
|
4
5
|
import { detect } from "package-manager-detector/detect";
|
|
5
6
|
import { basename, dirname, isAbsolute, join, relative } from "pathe";
|
|
7
|
+
import picomatch from "picomatch";
|
|
8
|
+
import { z } from "zod";
|
|
6
9
|
|
|
7
10
|
import { blumePackageJson, toPackageName } from "../../core/package-json.ts";
|
|
8
11
|
import { contentful } from "../../sources/contentful.ts";
|
|
@@ -14,6 +17,7 @@ import { payload } from "../../sources/payload.ts";
|
|
|
14
17
|
import type { AnySourceAdapter } from "../../sources/registry.ts";
|
|
15
18
|
import { sanity } from "../../sources/sanity.ts";
|
|
16
19
|
import { strapi } from "../../sources/strapi.ts";
|
|
20
|
+
import { STARTER_OPENAPI_JSON } from "./starter-spec.ts";
|
|
17
21
|
|
|
18
22
|
export const TEMPLATES = ["docs", "api", "sdk", "changelog"] as const;
|
|
19
23
|
export type Template = (typeof TEMPLATES)[number];
|
|
@@ -64,6 +68,11 @@ interface Starter {
|
|
|
64
68
|
/** Import lines the fragment needs, placed after the `defineConfig` import. */
|
|
65
69
|
configImports: string[];
|
|
66
70
|
files: (contentDir: string) => { content: string; path: string }[];
|
|
71
|
+
/**
|
|
72
|
+
* Files the config itself reads (the `api` starter's spec), written beside
|
|
73
|
+
* it whichever content sources are selected.
|
|
74
|
+
*/
|
|
75
|
+
projectFiles?: { content: string; path: string }[];
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
const page = (title: string, description: string, body: string): string =>
|
|
@@ -77,8 +86,8 @@ export const STARTERS = {
|
|
|
77
86
|
route: "/api",
|
|
78
87
|
sources: [
|
|
79
88
|
{
|
|
80
|
-
label: "
|
|
81
|
-
spec: "
|
|
89
|
+
label: "Pet Store",
|
|
90
|
+
spec: "./openapi.json",
|
|
82
91
|
},
|
|
83
92
|
],
|
|
84
93
|
}),
|
|
@@ -89,11 +98,12 @@ export const STARTERS = {
|
|
|
89
98
|
content: page(
|
|
90
99
|
"API Reference",
|
|
91
100
|
"Reference documentation for the API, generated from its OpenAPI spec, with every endpoint, its parameters, request bodies, and responses.",
|
|
92
|
-
"
|
|
101
|
+
"The example spec in `openapi.json` renders at [`/api`](/api). Replace it with your own, or point `openapi()` at your spec in `blume.config.ts`."
|
|
93
102
|
),
|
|
94
103
|
path: join(dir, "index.mdx"),
|
|
95
104
|
},
|
|
96
105
|
],
|
|
106
|
+
projectFiles: [{ content: STARTER_OPENAPI_JSON, path: "openapi.json" }],
|
|
97
107
|
},
|
|
98
108
|
changelog: {
|
|
99
109
|
configExtra: `
|
|
@@ -173,6 +183,20 @@ export const commandsFor = (pm: PackageManager) => ({
|
|
|
173
183
|
install: `${pm} install`,
|
|
174
184
|
});
|
|
175
185
|
|
|
186
|
+
// A path every shell (POSIX, cmd, PowerShell) takes as one bare word.
|
|
187
|
+
const SHELL_SAFE_PATH = /^[\w./:-]+$/u;
|
|
188
|
+
// What a double-quoted POSIX word still interprets.
|
|
189
|
+
const DOUBLE_QUOTE_SPECIAL = /["$\\`]/gu;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* The `cd` into the new project, quoting a directory a shell would split or
|
|
193
|
+
* expand: `blume init "my docs"` prints `cd "my docs"`, not `cd my docs`.
|
|
194
|
+
*/
|
|
195
|
+
export const cdCommand = (directory: string): string =>
|
|
196
|
+
SHELL_SAFE_PATH.test(directory)
|
|
197
|
+
? `cd ${directory}`
|
|
198
|
+
: `cd "${directory.replaceAll(DOUBLE_QUOTE_SPECIAL, String.raw`\$&`)}"`;
|
|
199
|
+
|
|
176
200
|
const isPackageManager = (value: string): value is PackageManager =>
|
|
177
201
|
PACKAGE_MANAGERS.some((pm) => pm === value);
|
|
178
202
|
|
|
@@ -525,6 +549,70 @@ const readText = (path: string): string => {
|
|
|
525
549
|
const pnpmWorkspaceRoot = (root: string): string | null =>
|
|
526
550
|
nearestAncestor(root, (dir) => existsSync(join(dir, "pnpm-workspace.yaml")));
|
|
527
551
|
|
|
552
|
+
/** The slice of `pnpm-workspace.yaml` the membership check reads. */
|
|
553
|
+
const pnpmWorkspaceSchema = z.looseObject({
|
|
554
|
+
packages: z.array(z.string()).default([]),
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
// A glob's leading `./` and trailing `/`, which pnpm ignores.
|
|
558
|
+
const GLOB_EDGES = /^\.\/|\/+$/gu;
|
|
559
|
+
|
|
560
|
+
/** Whether any of `globs` matches the workspace-relative path `at`. */
|
|
561
|
+
const matchesAny = (globs: string[], at: string): boolean =>
|
|
562
|
+
globs.length > 0 && picomatch(globs)(at);
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Whether the pnpm workspace at `workspace` lists `root` as one of its
|
|
566
|
+
* packages: the workspace root itself, or a folder its `packages` globs match
|
|
567
|
+
* and no `!` glob excludes. pnpm installs only those, so an install run in any
|
|
568
|
+
* other folder beneath it succeeds without installing that folder's
|
|
569
|
+
* dependencies. A workspace file that doesn't parse counts as listing it, so
|
|
570
|
+
* `init` never claims what it can't tell.
|
|
571
|
+
*/
|
|
572
|
+
const listsPackage = (workspace: string, root: string): boolean => {
|
|
573
|
+
const at = relative(workspace, root);
|
|
574
|
+
if (at === "") {
|
|
575
|
+
return true;
|
|
576
|
+
}
|
|
577
|
+
let parsed: ReturnType<typeof pnpmWorkspaceSchema.safeParse>;
|
|
578
|
+
try {
|
|
579
|
+
// `loadAll`, not `load`: js-yaml 5 throws on a file with no document (empty,
|
|
580
|
+
// or comments only), which pnpm reads as a workspace of the root alone.
|
|
581
|
+
const [document] = loadAll(
|
|
582
|
+
readText(join(workspace, "pnpm-workspace.yaml"))
|
|
583
|
+
);
|
|
584
|
+
parsed = pnpmWorkspaceSchema.safeParse(document ?? {});
|
|
585
|
+
} catch {
|
|
586
|
+
return true;
|
|
587
|
+
}
|
|
588
|
+
if (!parsed.success) {
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
const globs = parsed.data.packages;
|
|
592
|
+
const pattern = (glob: string): string => glob.replaceAll(GLOB_EDGES, "");
|
|
593
|
+
const included = globs.filter((glob) => !glob.startsWith("!")).map(pattern);
|
|
594
|
+
const excluded = globs
|
|
595
|
+
.filter((glob) => glob.startsWith("!"))
|
|
596
|
+
.map((glob) => pattern(glob.slice(1)));
|
|
597
|
+
return matchesAny(included, at) && !matchesAny(excluded, at);
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Whether `init` installs with pnpm into a folder that sits inside a pnpm
|
|
602
|
+
* workspace without being one of its packages. pnpm would install that
|
|
603
|
+
* workspace's own packages from there and exit 0, leaving `blume` uninstalled.
|
|
604
|
+
*/
|
|
605
|
+
export const outsidePnpmWorkspace = (
|
|
606
|
+
root: string,
|
|
607
|
+
answers: InitAnswers
|
|
608
|
+
): boolean => {
|
|
609
|
+
if (answers.packageManager !== "pnpm") {
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
const workspace = pnpmWorkspaceRoot(root);
|
|
613
|
+
return workspace !== null && !listsPackage(workspace, root);
|
|
614
|
+
};
|
|
615
|
+
|
|
528
616
|
/**
|
|
529
617
|
* The Yarn project enclosing `root`: a directory holding a lockfile, a
|
|
530
618
|
* `.yarnrc.yml`, or a `package.json` that declares workspaces.
|
|
@@ -585,10 +673,13 @@ const packageManagerConfigFor = (
|
|
|
585
673
|
return [];
|
|
586
674
|
};
|
|
587
675
|
|
|
676
|
+
const ESBUILD_APPROVAL = " allowBuilds:\n esbuild: true";
|
|
677
|
+
|
|
588
678
|
/**
|
|
589
|
-
* What the project still needs from a workspace it
|
|
590
|
-
* that workspace's config alone:
|
|
591
|
-
* (pnpm
|
|
679
|
+
* What the project still needs from a workspace it sits in, when `init` left
|
|
680
|
+
* that workspace's config alone: a place in a pnpm workspace's `packages`
|
|
681
|
+
* (pnpm skips a folder it doesn't list), pnpm's approval for esbuild's build
|
|
682
|
+
* script (pnpm 10 and later fail the install without it), or Yarn Berry's
|
|
592
683
|
* `node_modules` linker. Undefined when the workspace already has it, or the
|
|
593
684
|
* project doesn't sit in one.
|
|
594
685
|
*/
|
|
@@ -599,11 +690,21 @@ export const workspaceNote = (
|
|
|
599
690
|
): string | undefined => {
|
|
600
691
|
if (answers.packageManager === "pnpm") {
|
|
601
692
|
const workspace = pnpmWorkspaceRoot(root);
|
|
602
|
-
|
|
603
|
-
|
|
693
|
+
if (!workspace) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
const file = join(workspace, "pnpm-workspace.yaml");
|
|
697
|
+
const approved = readText(file).includes("esbuild");
|
|
698
|
+
if (!listsPackage(workspace, root)) {
|
|
699
|
+
const entry = ` packages:\n - ${relative(workspace, root)}`;
|
|
700
|
+
return approved
|
|
701
|
+
? `This folder sits inside the pnpm workspace at ${file}, which doesn't list it under packages, so pnpm won't install it. Add it there before installing:\n\n${entry}`
|
|
702
|
+
: `This folder sits inside the pnpm workspace at ${file}, which doesn't list it under packages, so pnpm won't install it. Add it there before installing, and approve esbuild's build script, or pnpm 10 and later stop the install:\n\n${entry}\n${ESBUILD_APPROVAL}`;
|
|
703
|
+
}
|
|
704
|
+
if (approved) {
|
|
604
705
|
return;
|
|
605
706
|
}
|
|
606
|
-
return `This project joins the pnpm workspace at ${file}. Approve esbuild's build script there before installing, or pnpm 10 and later stop the install:\n\n
|
|
707
|
+
return `This project joins the pnpm workspace at ${file}. Approve esbuild's build script there before installing, or pnpm 10 and later stop the install:\n\n${ESBUILD_APPROVAL}`;
|
|
607
708
|
}
|
|
608
709
|
if (answers.packageManager !== "yarn" || yarnMajor(env.userAgent) === 1) {
|
|
609
710
|
return;
|
|
@@ -622,6 +723,7 @@ export const buildPlan = (
|
|
|
622
723
|
answers: InitAnswers,
|
|
623
724
|
env: PlanEnvironment = {}
|
|
624
725
|
): ScaffoldFile[] => {
|
|
726
|
+
const starter: Starter = STARTERS[answers.template];
|
|
625
727
|
const files: ScaffoldFile[] = [
|
|
626
728
|
{
|
|
627
729
|
content: blumePackageJson(
|
|
@@ -632,11 +734,15 @@ export const buildPlan = (
|
|
|
632
734
|
},
|
|
633
735
|
...packageManagerConfigFor(root, answers, env),
|
|
634
736
|
{ content: buildConfig(answers), path: join(root, "blume.config.ts") },
|
|
737
|
+
...(starter.projectFiles ?? []).map((file) => ({
|
|
738
|
+
...file,
|
|
739
|
+
path: join(root, file.path),
|
|
740
|
+
})),
|
|
635
741
|
];
|
|
636
742
|
// Seed pages only make sense when a local filesystem source will read them.
|
|
637
743
|
if (answers.sources.length === 0 || answers.sources.includes("filesystem")) {
|
|
638
744
|
files.push(
|
|
639
|
-
...
|
|
745
|
+
...starter
|
|
640
746
|
.files(answers.contentDir)
|
|
641
747
|
.map((file) => ({ ...file, path: join(root, file.path) }))
|
|
642
748
|
);
|
|
@@ -771,7 +877,7 @@ export const nextSteps = (
|
|
|
771
877
|
const commands = commandsFor(answers.packageManager);
|
|
772
878
|
const lines: string[] = [];
|
|
773
879
|
if (answers.directory !== ".") {
|
|
774
|
-
lines.push(
|
|
880
|
+
lines.push(cdCommand(answers.directory));
|
|
775
881
|
}
|
|
776
882
|
if (needsInstall) {
|
|
777
883
|
lines.push(commands.install);
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OpenAPI document the `api` starter writes beside `blume.config.ts`, so a
|
|
3
|
+
* new project's first build reads a local file instead of depending on a
|
|
4
|
+
* third-party server. Small, but it exercises what a real reference renders:
|
|
5
|
+
* path and query parameters, request bodies, shared schemas, error responses,
|
|
6
|
+
* and bearer auth. Each operation's description is sized so its page's meta
|
|
7
|
+
* description, with the endpoint sentence Blume appends, fits the range
|
|
8
|
+
* `blume audit` checks.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const petId = {
|
|
12
|
+
description: "The pet's ID.",
|
|
13
|
+
in: "path",
|
|
14
|
+
name: "petId",
|
|
15
|
+
required: true,
|
|
16
|
+
schema: { type: "string" },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const errorResponse = (description: string) => ({
|
|
20
|
+
content: {
|
|
21
|
+
"application/json": { schema: { $ref: "#/components/schemas/Error" } },
|
|
22
|
+
},
|
|
23
|
+
description,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const petResponse = (description: string) => ({
|
|
27
|
+
content: {
|
|
28
|
+
"application/json": { schema: { $ref: "#/components/schemas/Pet" } },
|
|
29
|
+
},
|
|
30
|
+
description,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Built from entries rather than a literal so the written file keeps the
|
|
34
|
+
// conventional section order (`openapi`, `info`, …) instead of the sorted one.
|
|
35
|
+
const STARTER_SPEC = Object.fromEntries([
|
|
36
|
+
["openapi", "3.1.0"],
|
|
37
|
+
[
|
|
38
|
+
"info",
|
|
39
|
+
{
|
|
40
|
+
description:
|
|
41
|
+
"A small example API for a pet store: list, create, read, update, and delete pets. Replace openapi.json with your own spec to document your API.",
|
|
42
|
+
title: "Pet Store API",
|
|
43
|
+
version: "1.0.0",
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
["servers", [{ url: "https://api.example.com/v1" }]],
|
|
47
|
+
["security", [{ bearerAuth: [] }]],
|
|
48
|
+
[
|
|
49
|
+
"tags",
|
|
50
|
+
[
|
|
51
|
+
{
|
|
52
|
+
description:
|
|
53
|
+
"Every pet in the store, with its name, species, and status.",
|
|
54
|
+
name: "Pets",
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
],
|
|
58
|
+
[
|
|
59
|
+
"paths",
|
|
60
|
+
{
|
|
61
|
+
"/pets": {
|
|
62
|
+
get: {
|
|
63
|
+
description:
|
|
64
|
+
"Returns the pets in the store, newest first, filtered by status and paged with a cursor.",
|
|
65
|
+
operationId: "listPets",
|
|
66
|
+
parameters: [
|
|
67
|
+
{
|
|
68
|
+
description: "Only return pets with this status.",
|
|
69
|
+
in: "query",
|
|
70
|
+
name: "status",
|
|
71
|
+
schema: { $ref: "#/components/schemas/Status" },
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
description: "The most pets to return.",
|
|
75
|
+
in: "query",
|
|
76
|
+
name: "limit",
|
|
77
|
+
schema: {
|
|
78
|
+
default: 20,
|
|
79
|
+
maximum: 100,
|
|
80
|
+
minimum: 1,
|
|
81
|
+
type: "integer",
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
description: "The `nextCursor` from the previous page.",
|
|
86
|
+
in: "query",
|
|
87
|
+
name: "cursor",
|
|
88
|
+
schema: { type: "string" },
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
responses: {
|
|
92
|
+
"200": {
|
|
93
|
+
content: {
|
|
94
|
+
"application/json": {
|
|
95
|
+
schema: { $ref: "#/components/schemas/PetList" },
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
description: "A page of pets.",
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
summary: "List pets",
|
|
102
|
+
tags: ["Pets"],
|
|
103
|
+
},
|
|
104
|
+
post: {
|
|
105
|
+
description:
|
|
106
|
+
"Adds a pet to the store and returns it with its new ID and an available status.",
|
|
107
|
+
operationId: "createPet",
|
|
108
|
+
requestBody: {
|
|
109
|
+
content: {
|
|
110
|
+
"application/json": {
|
|
111
|
+
schema: { $ref: "#/components/schemas/NewPet" },
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
required: true,
|
|
115
|
+
},
|
|
116
|
+
responses: {
|
|
117
|
+
"201": petResponse("The new pet."),
|
|
118
|
+
"422": errorResponse("The pet's fields are invalid."),
|
|
119
|
+
},
|
|
120
|
+
summary: "Create a pet",
|
|
121
|
+
tags: ["Pets"],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
"/pets/{petId}": {
|
|
125
|
+
delete: {
|
|
126
|
+
description:
|
|
127
|
+
"Removes a pet from the store for good, or returns a 404 error when no pet has that ID.",
|
|
128
|
+
operationId: "deletePet",
|
|
129
|
+
parameters: [petId],
|
|
130
|
+
responses: {
|
|
131
|
+
"204": { description: "The pet was deleted." },
|
|
132
|
+
"404": errorResponse("No pet has that ID."),
|
|
133
|
+
},
|
|
134
|
+
summary: "Delete a pet",
|
|
135
|
+
tags: ["Pets"],
|
|
136
|
+
},
|
|
137
|
+
get: {
|
|
138
|
+
description:
|
|
139
|
+
"Returns a single pet by its ID, or a 404 error when no pet has that ID.",
|
|
140
|
+
operationId: "getPet",
|
|
141
|
+
parameters: [petId],
|
|
142
|
+
responses: {
|
|
143
|
+
"200": petResponse("The pet."),
|
|
144
|
+
"404": errorResponse("No pet has that ID."),
|
|
145
|
+
},
|
|
146
|
+
summary: "Get a pet",
|
|
147
|
+
tags: ["Pets"],
|
|
148
|
+
},
|
|
149
|
+
patch: {
|
|
150
|
+
description:
|
|
151
|
+
"Changes the fields you send on an existing pet and leaves the rest as they were.",
|
|
152
|
+
operationId: "updatePet",
|
|
153
|
+
parameters: [petId],
|
|
154
|
+
requestBody: {
|
|
155
|
+
content: {
|
|
156
|
+
"application/json": {
|
|
157
|
+
schema: { $ref: "#/components/schemas/PetUpdate" },
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
required: true,
|
|
161
|
+
},
|
|
162
|
+
responses: {
|
|
163
|
+
"200": petResponse("The updated pet."),
|
|
164
|
+
"404": errorResponse("No pet has that ID."),
|
|
165
|
+
},
|
|
166
|
+
summary: "Update a pet",
|
|
167
|
+
tags: ["Pets"],
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
[
|
|
173
|
+
"components",
|
|
174
|
+
{
|
|
175
|
+
schemas: {
|
|
176
|
+
Error: {
|
|
177
|
+
properties: {
|
|
178
|
+
code: { example: "not_found", type: "string" },
|
|
179
|
+
message: { example: "No pet has that ID.", type: "string" },
|
|
180
|
+
},
|
|
181
|
+
required: ["code", "message"],
|
|
182
|
+
type: "object",
|
|
183
|
+
},
|
|
184
|
+
NewPet: {
|
|
185
|
+
properties: {
|
|
186
|
+
name: { example: "Mochi", type: "string" },
|
|
187
|
+
species: { $ref: "#/components/schemas/Species" },
|
|
188
|
+
},
|
|
189
|
+
required: ["name", "species"],
|
|
190
|
+
type: "object",
|
|
191
|
+
},
|
|
192
|
+
Pet: {
|
|
193
|
+
properties: {
|
|
194
|
+
createdAt: { format: "date-time", type: "string" },
|
|
195
|
+
id: { example: "pet_01h2x", type: "string" },
|
|
196
|
+
name: { example: "Mochi", type: "string" },
|
|
197
|
+
species: { $ref: "#/components/schemas/Species" },
|
|
198
|
+
status: { $ref: "#/components/schemas/Status" },
|
|
199
|
+
},
|
|
200
|
+
required: ["id", "name", "species", "status", "createdAt"],
|
|
201
|
+
type: "object",
|
|
202
|
+
},
|
|
203
|
+
PetList: {
|
|
204
|
+
properties: {
|
|
205
|
+
data: {
|
|
206
|
+
items: { $ref: "#/components/schemas/Pet" },
|
|
207
|
+
type: "array",
|
|
208
|
+
},
|
|
209
|
+
nextCursor: {
|
|
210
|
+
description: "Pass as `cursor` to fetch the next page.",
|
|
211
|
+
type: ["string", "null"],
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
required: ["data", "nextCursor"],
|
|
215
|
+
type: "object",
|
|
216
|
+
},
|
|
217
|
+
PetUpdate: {
|
|
218
|
+
properties: {
|
|
219
|
+
name: { type: "string" },
|
|
220
|
+
status: { $ref: "#/components/schemas/Status" },
|
|
221
|
+
},
|
|
222
|
+
type: "object",
|
|
223
|
+
},
|
|
224
|
+
Species: { enum: ["cat", "dog", "bird", "rabbit"], type: "string" },
|
|
225
|
+
Status: { enum: ["available", "pending", "adopted"], type: "string" },
|
|
226
|
+
},
|
|
227
|
+
securitySchemes: {
|
|
228
|
+
bearerAuth: { scheme: "bearer", type: "http" },
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
]);
|
|
233
|
+
|
|
234
|
+
/** The starter spec as the `openapi.json` text `init` writes. */
|
|
235
|
+
export const STARTER_OPENAPI_JSON = `${JSON.stringify(STARTER_SPEC, null, 2)}\n`;
|
package/src/cli/report-format.ts
CHANGED
|
@@ -11,12 +11,17 @@ export const seconds = (ms: number): string => `${(ms / 1000).toFixed(1)}s`;
|
|
|
11
11
|
export const money = (cost: number | undefined): string =>
|
|
12
12
|
cost === undefined ? "" : `$${cost.toFixed(2)}`;
|
|
13
13
|
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Milliseconds as `12.3s` under a minute, `4m 12s` from there up. Rounding
|
|
16
|
+
* happens before the split, so a value just under a boundary carries over
|
|
17
|
+
* (`59_990` → `1m 0s`, `119_700` → `2m 0s`) instead of printing `60.0s` or
|
|
18
|
+
* `1m 60s`.
|
|
19
|
+
*/
|
|
15
20
|
export const duration = (ms: number): string => {
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
const tenths = Math.round(ms / 100);
|
|
22
|
+
if (tenths < 600) {
|
|
23
|
+
return `${(tenths / 10).toFixed(1)}s`;
|
|
18
24
|
}
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
return `${minutes}m ${rest}s`;
|
|
25
|
+
const total = Math.round(ms / 1000);
|
|
26
|
+
return `${Math.floor(total / 60)}m ${total % 60}s`;
|
|
22
27
|
};
|
package/src/components/colors.ts
CHANGED
|
@@ -49,6 +49,25 @@ export const STROKE = {
|
|
|
49
49
|
yellow: "border-yellow-500/40 text-yellow-800 dark:text-yellow-300",
|
|
50
50
|
} satisfies Record<Hue, string>;
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* The theme accent's label color: the accent mixed halfway toward the
|
|
54
|
+
* foreground. The accent is whatever the site configures (a preset, any CSS
|
|
55
|
+
* color, or the neutral black/white default), so no fixed shade can promise
|
|
56
|
+
* the contrast rule above, and the raw accent as text misses it (every preset
|
|
57
|
+
* sits under 3.5:1 over its tint in light mode). Pulling it toward the
|
|
58
|
+
* foreground darkens it in light mode and lightens it in dark, since the
|
|
59
|
+
* foreground contrasts with the page by construction: every preset clears
|
|
60
|
+
* 7:1 over its 15% tint in both modes.
|
|
61
|
+
*/
|
|
62
|
+
const ACCENT_LABEL =
|
|
63
|
+
"text-[color-mix(in_oklab,var(--blume-accent)_50%,var(--blume-foreground))]";
|
|
64
|
+
|
|
65
|
+
/** `TINT` for the theme accent (`<Badge variant="accent">`). */
|
|
66
|
+
export const ACCENT_TINT = `bg-accent/15 ${ACCENT_LABEL}`;
|
|
67
|
+
|
|
68
|
+
/** `STROKE` for the theme accent. */
|
|
69
|
+
export const ACCENT_STROKE = `border-accent/40 ${ACCENT_LABEL}`;
|
|
70
|
+
|
|
52
71
|
/** The neutral fallback every table falls through to. */
|
|
53
72
|
export const MUTED = "bg-muted text-muted-foreground";
|
|
54
73
|
|
|
@@ -97,29 +97,33 @@ const accordionId = id ?? componentSlug(title);
|
|
|
97
97
|
});
|
|
98
98
|
};
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
100
|
+
// Only the reader opening an item points the hash at it, so this keys on
|
|
101
|
+
// the summary's click (pointer, Enter, or Space) rather than `toggle`: a
|
|
102
|
+
// `defaultOpen` item a client-router swap inserts fires `toggle` too, and
|
|
103
|
+
// that must not overwrite the hash the reader arrived with.
|
|
104
|
+
document.addEventListener("click", (event) => {
|
|
105
|
+
const summary =
|
|
106
|
+
event.target instanceof Element ? event.target.closest("summary") : null;
|
|
107
|
+
const accordion = summary?.parentElement;
|
|
108
|
+
if (
|
|
109
|
+
event.defaultPrevented ||
|
|
110
|
+
!(accordion instanceof HTMLDetailsElement) ||
|
|
111
|
+
!accordion.matches("[data-blume-accordion]") ||
|
|
112
|
+
// Open now means this click closes it.
|
|
113
|
+
accordion.open ||
|
|
114
|
+
!accordion.id
|
|
115
|
+
) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
112
118
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
true
|
|
122
|
-
);
|
|
119
|
+
// Keep the entry's state: the client router ignores a popstate whose
|
|
120
|
+
// state is null, so Back to this page would change only the URL.
|
|
121
|
+
history.replaceState(
|
|
122
|
+
history.state,
|
|
123
|
+
"",
|
|
124
|
+
`#${encodeURIComponent(accordion.id)}`
|
|
125
|
+
);
|
|
126
|
+
});
|
|
123
127
|
|
|
124
128
|
const init = () => {
|
|
125
129
|
dedupeAccordionIds();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { STROKE, TINT } from "../colors.ts";
|
|
2
|
+
import { ACCENT_STROKE, ACCENT_TINT, STROKE, TINT } from "../colors.ts";
|
|
3
3
|
import Icon from "../Icon.astro";
|
|
4
|
+
import { badgeColorName } from "./badge-color.ts";
|
|
4
5
|
|
|
5
6
|
type BadgeVariant = "default" | "accent" | "success" | "warning" | "danger";
|
|
6
7
|
type BadgeSize = "xs" | "sm" | "md" | "lg";
|
|
@@ -34,21 +35,14 @@ const {
|
|
|
34
35
|
|
|
35
36
|
const activeStroke = stroke === true || stroke === "true";
|
|
36
37
|
const isDisabled = disabled === true || disabled === "true";
|
|
37
|
-
const colorName =
|
|
38
|
-
color ??
|
|
39
|
-
{
|
|
40
|
-
accent: "blue",
|
|
41
|
-
danger: "red",
|
|
42
|
-
default: "gray",
|
|
43
|
-
success: "green",
|
|
44
|
-
warning: "orange",
|
|
45
|
-
}[variant];
|
|
38
|
+
const colorName = badgeColorName(variant, color);
|
|
46
39
|
const customColor = colorName.startsWith("#") ? colorName : null;
|
|
47
40
|
|
|
48
|
-
// The hue rows come from the shared table (see colors.ts for
|
|
49
|
-
// rule); the neutral and surface rows are Badge's own.
|
|
41
|
+
// The hue and theme-accent rows come from the shared table (see colors.ts for
|
|
42
|
+
// the contrast rule); the neutral and surface rows are Badge's own.
|
|
50
43
|
const filledColorClass: Record<string, string> = {
|
|
51
44
|
...TINT,
|
|
45
|
+
accent: ACCENT_TINT,
|
|
52
46
|
gray: "bg-muted text-muted-foreground",
|
|
53
47
|
surface: "bg-background text-muted-foreground ring-1 ring-border",
|
|
54
48
|
"surface-destructive":
|
|
@@ -60,6 +54,7 @@ const filledColorClass: Record<string, string> = {
|
|
|
60
54
|
|
|
61
55
|
const strokeColorClass: Record<string, string> = {
|
|
62
56
|
...STROKE,
|
|
57
|
+
accent: ACCENT_STROKE,
|
|
63
58
|
gray: "border-border text-muted-foreground",
|
|
64
59
|
surface: "border-border text-muted-foreground",
|
|
65
60
|
"surface-destructive": "border-red-500/40 text-red-700 dark:text-red-300",
|
|
@@ -80,7 +80,7 @@ const variantClass = {
|
|
|
80
80
|
<p class="mt-0! mb-1.5! flex items-center gap-1.5 font-medium text-foreground">
|
|
81
81
|
{title}
|
|
82
82
|
{showArrow && (
|
|
83
|
-
<Icon class="text-muted-foreground" name="arrow-right" size={14} />
|
|
83
|
+
<Icon class="text-muted-foreground rtl:-scale-x-100" name="arrow-right" size={14} />
|
|
84
84
|
)}
|
|
85
85
|
</p>
|
|
86
86
|
)
|
|
@@ -92,7 +92,7 @@ const variantClass = {
|
|
|
92
92
|
cta && (
|
|
93
93
|
<p class="mt-4! mb-0! flex items-center gap-1.5 font-medium text-accent text-sm">
|
|
94
94
|
{cta}
|
|
95
|
-
{showArrow && <Icon name="arrow-right" size={14} />}
|
|
95
|
+
{showArrow && <Icon class="rtl:-scale-x-100" name="arrow-right" size={14} />}
|
|
96
96
|
</p>
|
|
97
97
|
)
|
|
98
98
|
}
|
|
@@ -13,7 +13,8 @@ import data from "blume:data";
|
|
|
13
13
|
import { CODE_PADDING_BLOCK_REM } from "../../theme/code-block-padding.ts";
|
|
14
14
|
|
|
15
15
|
import { highlightCode } from "../../markdown/index.ts";
|
|
16
|
-
import {
|
|
16
|
+
import { withMountedBase } from "../islands/base-path.ts";
|
|
17
|
+
import { contentStrings } from "./content-strings.ts";
|
|
17
18
|
import { EXAMPLE_PANE_MIN_PX } from "./example-pane.ts";
|
|
18
19
|
import Tab from "./Tab.astro";
|
|
19
20
|
import Tabs from "./Tabs.astro";
|
|
@@ -26,6 +27,7 @@ interface Props {
|
|
|
26
27
|
|
|
27
28
|
const { path } = Astro.props;
|
|
28
29
|
const entry = examples[path];
|
|
30
|
+
const { content: strings } = contentStrings(data, Astro.currentLocale);
|
|
29
31
|
|
|
30
32
|
// The live preview renders in its own generated route, embedded as an iframe:
|
|
31
33
|
// the frame boundary is what keeps the docs CSS (prose typography, component
|
|
@@ -33,7 +35,7 @@ const entry = examples[path];
|
|
|
33
35
|
// by their own design system (e.g. shadcn, via the configured `examples.css`).
|
|
34
36
|
// The frame syncs its theme with this document before first paint.
|
|
35
37
|
const previewSrc = entry
|
|
36
|
-
?
|
|
38
|
+
? withMountedBase(
|
|
37
39
|
`${examplesBase}/${path.split("/").map(encodeURIComponent).join("/")}`
|
|
38
40
|
)
|
|
39
41
|
: undefined;
|
|
@@ -103,17 +105,21 @@ const paneClass =
|
|
|
103
105
|
<Tab
|
|
104
106
|
class={`overflow-hidden p-0! ${paneClass}`}
|
|
105
107
|
style={paneStyle}
|
|
106
|
-
title=
|
|
108
|
+
title={strings.preview}
|
|
107
109
|
>
|
|
108
110
|
<iframe
|
|
109
111
|
class="h-full w-full"
|
|
110
112
|
data-blume-example-frame
|
|
111
113
|
loading="lazy"
|
|
112
114
|
src={previewSrc}
|
|
113
|
-
title={
|
|
115
|
+
title={`${strings.preview}: ${path}`}
|
|
114
116
|
/>
|
|
115
117
|
</Tab>
|
|
116
|
-
<Tab
|
|
118
|
+
<Tab
|
|
119
|
+
class={`overflow-hidden ${paneClass}`}
|
|
120
|
+
style={paneStyle}
|
|
121
|
+
title={strings.code}
|
|
122
|
+
>
|
|
117
123
|
<Fragment set:html={codeHtml} />
|
|
118
124
|
</Tab>
|
|
119
125
|
</Tabs>
|