blume 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +113 -0
- package/README.md +1 -1
- package/dist/cli/{chunk-6k4ftwze.js → chunk-0gz36akr.js} +18 -2
- package/dist/cli/{chunk-6k4ftwze.js.map → chunk-0gz36akr.js.map} +3 -3
- package/dist/cli/{chunk-zp79m0ts.js → chunk-1n228xqb.js} +2 -2
- package/dist/cli/{chunk-ddndchfr.js → chunk-2f3ndkpw.js} +57 -29
- package/dist/cli/chunk-2f3ndkpw.js.map +14 -0
- package/dist/cli/{chunk-fsmrqk8a.js → chunk-2f7n4qzt.js} +8 -2
- package/dist/cli/{chunk-fsmrqk8a.js.map → chunk-2f7n4qzt.js.map} +3 -3
- package/dist/cli/{chunk-ppzjqwx2.js → chunk-2n4ps1b3.js} +17 -18
- package/dist/cli/{chunk-ppzjqwx2.js.map → chunk-2n4ps1b3.js.map} +3 -3
- package/dist/cli/{chunk-5r8g91qn.js → chunk-43zcf4gz.js} +398 -159
- package/dist/cli/chunk-43zcf4gz.js.map +36 -0
- package/dist/cli/chunk-4ejxbzee.js +39 -0
- package/dist/cli/chunk-4ejxbzee.js.map +10 -0
- package/dist/cli/{chunk-hr8ne106.js → chunk-4h8z9vv5.js} +296 -77
- package/dist/cli/chunk-4h8z9vv5.js.map +16 -0
- package/dist/cli/{chunk-k7pj68a8.js → chunk-5cg2rzgf.js} +18 -16
- package/dist/cli/{chunk-k7pj68a8.js.map → chunk-5cg2rzgf.js.map} +2 -2
- package/dist/cli/{chunk-h2ez8dzb.js → chunk-5ffywsmb.js} +4 -4
- package/dist/cli/{chunk-g698a744.js → chunk-5wj2qwn2.js} +5 -5
- package/dist/cli/chunk-6bm0xpgd.js +18 -0
- package/dist/cli/chunk-6bm0xpgd.js.map +10 -0
- package/dist/cli/{chunk-3yce002v.js → chunk-713mngdq.js} +15 -8
- package/dist/cli/chunk-713mngdq.js.map +14 -0
- package/dist/cli/{chunk-91ws1n6j.js → chunk-9geymqns.js} +17 -15
- package/dist/cli/{chunk-91ws1n6j.js.map → chunk-9geymqns.js.map} +2 -2
- package/dist/cli/{chunk-6dtt0zfn.js → chunk-9xr4dgee.js} +27 -18
- package/dist/cli/chunk-9xr4dgee.js.map +10 -0
- package/dist/cli/{chunk-sqw4ekg1.js → chunk-amrb6hgh.js} +2 -2
- package/dist/cli/chunk-cm89scdv.js +443 -0
- package/dist/cli/chunk-cm89scdv.js.map +11 -0
- package/dist/cli/{chunk-wdrt2k2v.js → chunk-cmtcnh9f.js} +90 -26
- package/dist/cli/chunk-cmtcnh9f.js.map +10 -0
- package/dist/cli/chunk-cy5bm0j0.js +104 -0
- package/dist/cli/chunk-cy5bm0j0.js.map +11 -0
- package/dist/cli/{chunk-7mbqtmgb.js → chunk-e7vvk5ya.js} +21 -12
- package/dist/cli/chunk-e7vvk5ya.js.map +10 -0
- package/dist/cli/{chunk-qkb5a8sa.js → chunk-g2z9x01v.js} +6 -98
- package/dist/cli/chunk-g2z9x01v.js.map +10 -0
- package/dist/cli/{chunk-273ygyr4.js → chunk-ga0pf4aj.js} +7 -7
- package/dist/cli/{chunk-273ygyr4.js.map → chunk-ga0pf4aj.js.map} +3 -3
- package/dist/cli/{chunk-h7k3nq3v.js → chunk-gp84za0h.js} +2 -2
- package/dist/cli/{chunk-hqp2ajnh.js → chunk-h2a48yhd.js} +195 -73
- package/dist/cli/chunk-h2a48yhd.js.map +36 -0
- package/dist/cli/{chunk-pbg5a4s3.js → chunk-jnwj5kjj.js} +71 -47
- package/dist/cli/chunk-jnwj5kjj.js.map +19 -0
- package/dist/cli/chunk-kwrg63tm.js +31 -0
- package/dist/cli/chunk-kwrg63tm.js.map +10 -0
- package/dist/cli/{chunk-8g8ytmgx.js → chunk-nd1821sk.js} +21 -19
- package/dist/cli/{chunk-8g8ytmgx.js.map → chunk-nd1821sk.js.map} +2 -2
- package/dist/cli/{chunk-w4bxdvsa.js → chunk-ntv4qrt7.js} +17 -15
- package/dist/cli/{chunk-w4bxdvsa.js.map → chunk-ntv4qrt7.js.map} +2 -2
- package/dist/cli/{chunk-bfwp9vp6.js → chunk-p804f3pe.js} +7 -7
- package/dist/cli/{chunk-4e9b9ra6.js → chunk-py62fewh.js} +6 -6
- package/dist/cli/{chunk-4e9b9ra6.js.map → chunk-py62fewh.js.map} +1 -1
- package/dist/cli/chunk-q3wxxq39.js +126 -0
- package/dist/cli/chunk-q3wxxq39.js.map +11 -0
- package/dist/cli/{chunk-j85scx15.js → chunk-rekqz4qg.js} +142 -46
- package/dist/cli/chunk-rekqz4qg.js.map +10 -0
- package/dist/cli/{chunk-00gs3wqs.js → chunk-ta27feev.js} +1 -1
- package/dist/cli/{chunk-v6ya5kcb.js → chunk-xkz5xbtv.js} +4031 -1132
- package/dist/cli/chunk-xkz5xbtv.js.map +213 -0
- package/dist/cli/{chunk-bbnwccaz.js → chunk-y4ykbark.js} +2 -2
- package/dist/cli/{chunk-n1yg3tj3.js → chunk-y5h4r2y0.js} +6 -6
- package/dist/cli/{chunk-n1yg3tj3.js.map → chunk-y5h4r2y0.js.map} +3 -3
- package/dist/cli/{chunk-nfcyttvj.js → chunk-yj17vs39.js} +9 -9
- package/dist/cli/{chunk-nfcyttvj.js.map → chunk-yj17vs39.js.map} +1 -1
- package/dist/cli/{chunk-7vtckvaw.js → chunk-yxmk4pec.js} +16 -14
- package/dist/cli/{chunk-7vtckvaw.js.map → chunk-yxmk4pec.js.map} +2 -2
- package/dist/cli/{chunk-gs7r695n.js → chunk-zccbjcj0.js} +22 -8
- package/dist/cli/{chunk-gs7r695n.js.map → chunk-zccbjcj0.js.map} +3 -3
- package/dist/cli/{chunk-xh43dwgw.js → chunk-zf748avv.js} +415 -225
- package/dist/cli/chunk-zf748avv.js.map +37 -0
- package/dist/cli/{chunk-d1v5rhy0.js → chunk-zhvd6adm.js} +16 -14
- package/dist/cli/{chunk-d1v5rhy0.js.map → chunk-zhvd6adm.js.map} +2 -2
- package/dist/cli/index.js +28 -20
- package/dist/cli/index.js.map +5 -5
- package/dist/types/ai/agent-surface.d.ts +8 -7
- package/dist/types/ai/ai-catalog.d.ts +7 -0
- package/dist/types/ai/ask-context.d.ts +22 -0
- package/dist/types/ai/ask.d.ts +271 -58
- package/dist/types/ai/index.d.ts +2 -2
- package/dist/types/ai/link-headers.d.ts +8 -1
- package/dist/types/ai/openapi-components.d.ts +5 -2
- package/dist/types/ai/relative-links.d.ts +9 -7
- package/dist/types/ai/site-skill.d.ts +26 -0
- package/dist/types/ai/skills.d.ts +20 -1
- package/dist/types/ai/tar.d.ts +1 -3
- package/dist/types/analytics/index.d.ts +2 -0
- package/dist/types/analytics/one-dollar-stats.d.ts +48 -0
- package/dist/types/analytics/schema.d.ts +14 -0
- package/dist/types/astro/integration.d.ts +11 -2
- package/dist/types/captcha/hcaptcha.d.ts +27 -0
- package/dist/types/captcha/index.d.ts +28 -0
- package/dist/types/captcha/schema.d.ts +29 -0
- package/dist/types/captcha/turnstile.d.ts +28 -0
- package/dist/types/components/content/api-field.d.ts +59 -0
- package/dist/types/components/content/api-page.d.ts +95 -0
- package/dist/types/components/layout/nav-utils.d.ts +26 -0
- package/dist/types/components/openapi/helpers.d.ts +137 -0
- package/dist/types/components/openapi/security.d.ts +85 -0
- package/dist/types/consent/ethyca.d.ts +48 -0
- package/dist/types/consent/index.d.ts +37 -0
- package/dist/types/consent/native.d.ts +28 -0
- package/dist/types/consent/osano.d.ts +42 -0
- package/dist/types/consent/schema.d.ts +110 -0
- package/dist/types/core/base-path.d.ts +21 -7
- package/dist/types/core/config-input.d.ts +196 -27
- package/dist/types/core/data.d.ts +49 -4
- package/dist/types/core/directive-diagnostics.d.ts +12 -0
- package/dist/types/core/footer.d.ts +8 -0
- package/dist/types/core/heading-markers.d.ts +5 -7
- package/dist/types/core/i18n-ui.d.ts +86 -0
- package/dist/types/core/i18n.d.ts +2 -0
- package/dist/types/core/includes.d.ts +8 -2
- package/dist/types/core/last-modified.d.ts +10 -0
- package/dist/types/core/localizable.d.ts +7 -0
- package/dist/types/core/meta.d.ts +8 -0
- package/dist/types/core/page-modes.d.ts +29 -0
- package/dist/types/core/redirect-patterns.d.ts +144 -0
- package/dist/types/core/related.d.ts +40 -0
- package/dist/types/core/schema.d.ts +558 -56
- package/dist/types/core/sources/lower.d.ts +29 -16
- package/dist/types/core/sources/normalize.d.ts +13 -1
- package/dist/types/core/sources/read.d.ts +5 -0
- package/dist/types/core/sources/watch.d.ts +12 -5
- package/dist/types/core/standard-schema.d.ts +5 -0
- package/dist/types/core/types.d.ts +1 -1
- package/dist/types/core/variables.d.ts +42 -0
- package/dist/types/deploy/artifacts.d.ts +6 -4
- package/dist/types/deploy/headers.d.ts +5 -0
- package/dist/types/deploy/node-headers.d.ts +13 -2
- package/dist/types/deploy/platforms/cloudflare.d.ts +5 -0
- package/dist/types/deploy/platforms/netlify.d.ts +7 -0
- package/dist/types/deploy/platforms/types.d.ts +8 -0
- package/dist/types/deploy/platforms/vercel.d.ts +6 -0
- package/dist/types/deploy/redirects.d.ts +61 -22
- package/dist/types/deploy/vercel-negotiation.d.ts +9 -0
- package/dist/types/markdown/code-title.d.ts +17 -0
- package/dist/types/markdown/directives.d.ts +62 -0
- package/dist/types/markdown/features.d.ts +24 -2
- package/dist/types/markdown/mdast.d.ts +63 -0
- package/dist/types/narration/build.d.ts +70 -0
- package/dist/types/narration/provider.d.ts +26 -0
- package/dist/types/narration/script.d.ts +154 -0
- package/dist/types/openapi/asyncapi.d.ts +4 -2
- package/dist/types/openapi/model.d.ts +12 -6
- package/dist/types/openapi/overlay.d.ts +54 -0
- package/dist/types/openapi/parse.d.ts +13 -0
- package/dist/types/openapi/references.d.ts +14 -4
- package/dist/types/ratelimit/cloudflare.d.ts +39 -0
- package/dist/types/ratelimit/index.d.ts +27 -0
- package/dist/types/ratelimit/memory.d.ts +36 -0
- package/dist/types/ratelimit/schema.d.ts +111 -0
- package/dist/types/ratelimit/upstash.d.ts +21 -0
- package/dist/types/ratelimit/wrangler.d.ts +23 -0
- package/dist/types/reference/asyncapi.d.ts +10 -10
- package/dist/types/reference/graphql.d.ts +13 -10
- package/dist/types/reference/openapi.d.ts +33 -12
- package/dist/types/reference/options.d.ts +45 -5
- package/dist/types/reference/scalar.d.ts +13 -0
- package/dist/types/reference/schema.d.ts +60 -36
- package/dist/types/search/documents.d.ts +12 -1
- package/dist/types/search/orama-index.d.ts +4 -0
- package/dist/types/seo/metatags.d.ts +20 -0
- package/docs/02-deployment.mdx +44 -6
- package/docs/03-upgrading.mdx +4 -4
- package/docs/04-migrating.mdx +1 -1
- package/docs/08-faq.mdx +1 -1
- package/docs/advanced/changelog.mdx +2 -2
- package/docs/advanced/custom-pages.mdx +3 -3
- package/docs/advanced/skills.mdx +14 -0
- package/docs/cli/audit.mdx +38 -2
- package/docs/cli/evals.mdx +3 -3
- package/docs/cli/index.mdx +1 -0
- package/docs/cli/translate.mdx +3 -3
- package/docs/cli/version.mdx +1 -1
- package/docs/configuration/analytics.mdx +22 -1
- package/docs/configuration/assistant.mdx +188 -36
- package/docs/configuration/consent.mdx +100 -0
- package/docs/configuration/customization.mdx +6 -4
- package/docs/configuration/index.mdx +63 -5
- package/docs/configuration/meta.ts +3 -0
- package/docs/configuration/narration.mdx +119 -0
- package/docs/configuration/rate-limiting.mdx +69 -0
- package/docs/configuration/search.mdx +30 -2
- package/docs/configuration/theming.mdx +3 -1
- package/docs/content/components.mdx +107 -1
- package/docs/content/frontmatter.mdx +77 -1
- package/docs/content/i18n.mdx +40 -3
- package/docs/content/includes.mdx +16 -0
- package/docs/content/index.mdx +4 -2
- package/docs/content/islands.mdx +1 -1
- package/docs/content/meta.mdx +4 -1
- package/docs/content/meta.ts +1 -0
- package/docs/content/navigation.mdx +28 -6
- package/docs/content/sources/contentful.mdx +32 -0
- package/docs/content/sources/custom.mdx +39 -0
- package/docs/content/sources/github-releases.mdx +31 -0
- package/docs/content/sources/index.mdx +91 -0
- package/docs/content/sources/meta.ts +16 -0
- package/docs/content/sources/notion.mdx +32 -0
- package/docs/content/sources/obsidian.mdx +37 -0
- package/docs/content/sources/payload.mdx +30 -0
- package/docs/content/sources/remote-mdx.mdx +40 -0
- package/docs/content/sources/sanity.mdx +29 -0
- package/docs/content/sources/strapi.mdx +31 -0
- package/docs/content/syntax.mdx +81 -2
- package/docs/content/variables.mdx +41 -0
- package/docs/content/versioning.mdx +1 -1
- package/docs/discoverability/agent-discovery.mdx +30 -3
- package/docs/discoverability/index.mdx +3 -2
- package/docs/discoverability/llms-txt.mdx +1 -1
- package/docs/discoverability/markdown.mdx +2 -2
- package/docs/discoverability/metadata.mdx +17 -0
- package/docs/discoverability/open-graph.mdx +5 -3
- package/docs/discoverability/rss.mdx +1 -1
- package/docs/references/api-pages.mdx +74 -0
- package/docs/references/asyncapi.mdx +2 -2
- package/docs/references/graphql.mdx +3 -3
- package/docs/references/meta.ts +1 -1
- package/docs/references/openapi.mdx +106 -5
- package/docs/references/scalar.mdx +3 -1
- package/package.json +36 -1
- package/skills/blume/SKILL.md +3 -0
- package/skills/blume-migrate/SKILL.md +5 -5
- package/skills/blume-migrate/references/docusaurus.md +3 -3
- package/skills/blume-migrate/references/fumadocs.md +1 -1
- package/skills/blume-migrate/references/mintlify.md +37 -19
- package/skills/blume-migrate/references/nextra.md +3 -3
- package/skills/blume-migrate/references/starlight.md +2 -1
- package/skills/blume-migrate/scripts/mintlify-codemod.mjs +67 -16
- package/skills/blume-write-skill/SKILL.md +82 -0
- package/src/ai/agent-readability.ts +4 -3
- package/src/ai/agent-surface.ts +9 -7
- package/src/ai/ai-catalog.ts +12 -5
- package/src/ai/api/handlers.ts +2 -2
- package/src/ai/api/spec.ts +2 -2
- package/src/ai/api-catalog.ts +6 -2
- package/src/ai/ask-context.ts +73 -20
- package/src/ai/ask-data.ts +6 -0
- package/src/ai/ask-tools.ts +142 -0
- package/src/ai/ask.ts +354 -76
- package/src/ai/changelog-markdown.ts +2 -2
- package/src/ai/component-markdown.ts +75 -0
- package/src/ai/cors.ts +2 -0
- package/src/ai/index.ts +12 -0
- package/src/ai/link-headers.ts +14 -5
- package/src/ai/llms.ts +24 -9
- package/src/ai/markdown.ts +2 -1
- package/src/ai/mcp/data.ts +6 -0
- package/src/ai/mcp/discovery.ts +2 -2
- package/src/ai/mcp/query.ts +2 -2
- package/src/ai/mcp/server.ts +2 -2
- package/src/ai/openapi-components.ts +31 -9
- package/src/ai/relative-links.ts +42 -26
- package/src/ai/serializers.ts +2 -1
- package/src/ai/site-skill.ts +274 -0
- package/src/ai/skills.ts +49 -3
- package/src/ai/tar.ts +139 -12
- package/src/ai/write-skill.ts +97 -0
- package/src/analytics/head.ts +4 -0
- package/src/analytics/index.ts +5 -0
- package/src/analytics/one-dollar-stats.ts +86 -0
- package/src/analytics/schema.ts +2 -0
- package/src/astro/generate.ts +133 -19
- package/src/astro/include-hmr.ts +31 -12
- package/src/astro/include-refresh.ts +19 -8
- package/src/astro/index.ts +1 -0
- package/src/astro/integration.ts +143 -14
- package/src/astro/module-types.ts +6 -0
- package/src/astro/runtime-modules.ts +28 -13
- package/src/astro/templates.ts +364 -67
- package/src/astro/variables.ts +31 -0
- package/src/audit/catalog.ts +19 -0
- package/src/audit/checks/contrast.ts +183 -0
- package/src/audit/checks/i18n.ts +2 -3
- package/src/audit/checks/indexability.ts +2 -3
- package/src/audit/checks/links.ts +13 -13
- package/src/audit/checks/sitemap.ts +2 -3
- package/src/audit/graph.ts +3 -1
- package/src/audit/redirects.ts +46 -15
- package/src/audit/run.ts +14 -9
- package/src/audit/snapshot.ts +5 -0
- package/src/audit/types.ts +2 -1
- package/src/blume-modules.d.ts +7 -0
- package/src/captcha/client.ts +152 -0
- package/src/captcha/hcaptcha.ts +36 -0
- package/src/captcha/index.ts +28 -0
- package/src/captcha/schema.ts +32 -0
- package/src/captcha/turnstile.ts +38 -0
- package/src/captcha/verify.ts +71 -0
- package/src/cli/args.ts +32 -0
- package/src/cli/command-meta.ts +5 -0
- package/src/cli/commands/audit.ts +4 -1
- package/src/cli/commands/doctor.ts +25 -17
- package/src/cli/commands/eval.ts +19 -11
- package/src/cli/commands/skill.ts +96 -0
- package/src/cli/commands/translate.ts +9 -12
- package/src/cli/commands/validate.ts +3 -1
- package/src/cli/dev-lock.ts +157 -37
- package/src/cli/index.ts +5 -0
- package/src/cli/report-format.ts +11 -6
- package/src/cli/required-secrets.ts +71 -29
- package/src/components/BlumePage.astro +2 -0
- package/src/components/colors.ts +19 -0
- package/src/components/content/ApiEndpoint.astro +18 -0
- package/src/components/content/ApiField.astro +79 -0
- package/src/components/content/ApiPlayground.astro +62 -0
- package/src/components/content/ApiRail.astro +19 -0
- package/src/components/content/Badge.astro +5 -3
- package/src/components/content/Color.astro +1 -0
- package/src/components/content/Component.astro +2 -2
- package/src/components/content/FileTree.astro +1 -0
- package/src/components/content/GithubInfo.astro +1 -0
- package/src/components/content/Panel.astro +1 -0
- package/src/components/content/ParamField.astro +25 -0
- package/src/components/content/RequestExample.astro +17 -0
- package/src/components/content/ResponseExample.astro +17 -0
- package/src/components/content/ResponseField.astro +32 -0
- package/src/components/content/Step.astro +1 -0
- package/src/components/content/Tab.astro +0 -1
- package/src/components/content/Tabs.astro +4 -0
- package/src/components/content/Tile.astro +1 -0
- package/src/components/content/Tooltip.astro +1 -0
- package/src/components/content/Tree.astro +1 -0
- package/src/components/content/TypeTable.astro +4 -1
- package/src/components/content/View.astro +21 -0
- package/src/components/content/ViewSwitcher.astro +168 -0
- package/src/components/content/api-field.ts +100 -0
- package/src/components/content/api-page.ts +224 -0
- package/src/components/content/badge-color.ts +5 -2
- package/src/components/content/base-href.ts +13 -36
- package/src/components/content/view-switcher.ts +71 -0
- package/src/components/index.ts +2 -0
- package/src/components/islands/Assistant.astro +10 -1
- package/src/components/islands/assistant.tsx +125 -18
- package/src/components/islands/base-path.ts +47 -10
- package/src/components/islands/code-question.ts +62 -0
- package/src/components/islands/hooks.ts +145 -40
- package/src/components/islands/support-link.ts +68 -0
- package/src/components/islands/webmcp.ts +4 -2
- package/src/components/layout/Analytics.astro +11 -2
- package/src/components/layout/Banner.astro +14 -10
- package/src/components/layout/Breadcrumbs.astro +11 -4
- package/src/components/layout/ConsentBanner.astro +62 -0
- package/src/components/layout/ConsentHead.astro +38 -0
- package/src/components/layout/Directory.astro +94 -0
- package/src/components/layout/DiscoveryLinks.astro +9 -5
- package/src/components/layout/DrawerSwitchers.astro +51 -0
- package/src/components/layout/Empty.astro +2 -2
- package/src/components/layout/Header.astro +124 -82
- package/src/components/layout/LanguageSwitcher.astro +50 -17
- package/src/components/layout/NarrationPlayer.astro +1085 -0
- package/src/components/layout/NavSelector.astro +35 -9
- package/src/components/layout/NavTabMenu.astro +3 -3
- package/src/components/layout/NavTree.astro +16 -6
- package/src/components/layout/PageActions.astro +4 -3
- package/src/components/layout/PageFeedback.astro +54 -49
- package/src/components/layout/PageLayout.astro +78 -9
- package/src/components/layout/Pagination.astro +3 -3
- package/src/components/layout/ReferenceLayout.astro +17 -6
- package/src/components/layout/RelatedPages.astro +42 -0
- package/src/components/layout/RootLayout.astro +313 -50
- package/src/components/layout/Search.astro +64 -30
- package/src/components/layout/SiteFooter.astro +124 -0
- package/src/components/layout/SiteMetatags.astro +16 -0
- package/src/components/layout/VersionBanner.astro +2 -2
- package/src/components/layout/analytics-client.ts +12 -0
- package/src/components/layout/consent/native.ts +79 -0
- package/src/components/layout/consent/types.ts +37 -0
- package/src/components/layout/footer-links.ts +53 -0
- package/src/components/layout/footer-socials.ts +87 -0
- package/src/components/layout/locale-redirect.ts +107 -0
- package/src/components/layout/nav-utils.ts +83 -0
- package/src/components/layout/page-feedback.ts +96 -0
- package/src/components/layout/search/analytics.ts +98 -0
- package/src/components/layout/search/flexsearch.ts +17 -5
- package/src/components/layout/search/orama-cloud.ts +26 -14
- package/src/components/layout/search/types.ts +20 -0
- package/src/components/layout/search/typesense.ts +5 -1
- package/src/components/layout/toc-active.ts +41 -0
- package/src/components/layout/toc-element.ts +8 -14
- package/src/components/openapi/ApiTagOperations.astro +2 -2
- package/src/components/openapi/AsyncApiOperation.astro +7 -4
- package/src/components/openapi/GraphqlChip.astro +2 -2
- package/src/components/openapi/Operation.astro +163 -13
- package/src/components/openapi/Playground.astro +4 -4
- package/src/components/openapi/RequestBody.astro +6 -4
- package/src/components/openapi/RequestPanel.astro +63 -8
- package/src/components/openapi/Responses.astro +6 -4
- package/src/components/openapi/SchemaTable.astro +7 -0
- package/src/components/openapi/async-snippets.ts +4 -4
- package/src/components/openapi/async.ts +38 -6
- package/src/components/openapi/code-samples.ts +97 -0
- package/src/components/openapi/helpers.ts +19 -9
- package/src/components/openapi/message-composer.ts +6 -1
- package/src/components/openapi/message.ts +17 -2
- package/src/components/openapi/operation-model.ts +81 -11
- package/src/components/openapi/panel.ts +4 -2
- package/src/components/openapi/param-style.ts +181 -0
- package/src/components/openapi/playground-client.ts +73 -16
- package/src/components/openapi/request.ts +190 -26
- package/src/components/openapi/schema-tree.ts +30 -24
- package/src/components/openapi/security.ts +6 -3
- package/src/components/openapi/snippets.ts +953 -13
- package/src/components/openapi/ws-client.ts +18 -2
- package/src/components/props.ts +6 -0
- package/src/consent/client.ts +95 -0
- package/src/consent/clients.ts +19 -0
- package/src/consent/ethyca.ts +71 -0
- package/src/consent/head.ts +24 -0
- package/src/consent/index.ts +37 -0
- package/src/consent/init.ts +29 -0
- package/src/consent/native.ts +36 -0
- package/src/consent/osano.ts +59 -0
- package/src/consent/schema.ts +30 -0
- package/src/core/base-path.ts +62 -16
- package/src/core/builtin-tags.ts +5 -0
- package/src/core/client-address.ts +19 -0
- package/src/core/config-input.ts +203 -27
- package/src/core/data.ts +44 -4
- package/src/core/diagnostics.ts +5 -2
- package/src/core/directive-diagnostics.ts +99 -0
- package/src/core/footer.ts +26 -0
- package/src/core/frontmatter.ts +21 -18
- package/src/core/graph.ts +39 -36
- package/src/core/heading-markers.ts +5 -18
- package/src/core/i18n-ui.ts +82 -2
- package/src/core/i18n.ts +31 -3
- package/src/core/includes.ts +20 -3
- package/src/core/last-modified.ts +25 -3
- package/src/core/links.ts +16 -2
- package/src/core/locale-links.ts +5 -1
- package/src/core/localizable.ts +26 -0
- package/src/core/meta.ts +33 -19
- package/src/core/navigation.ts +71 -20
- package/src/core/page-modes.ts +56 -0
- package/src/core/project-graph.ts +138 -10
- package/src/core/redirect-patterns.ts +491 -0
- package/src/core/related.ts +131 -0
- package/src/core/schema.ts +342 -68
- package/src/core/sources/contentful-rich-text.ts +27 -20
- package/src/core/sources/filesystem.ts +20 -2
- package/src/core/sources/github-releases.ts +25 -6
- package/src/core/sources/lexical.ts +23 -18
- package/src/core/sources/lower.ts +201 -34
- package/src/core/sources/mdx-remote.ts +51 -16
- package/src/core/sources/normalize.ts +327 -91
- package/src/core/sources/notion.ts +52 -25
- package/src/core/sources/obsidian.ts +23 -6
- package/src/core/sources/portable-text.ts +38 -21
- package/src/core/sources/read.ts +8 -3
- package/src/core/sources/strapi-blocks.ts +20 -16
- package/src/core/sources/watch.ts +20 -7
- package/src/core/standard-schema.ts +10 -6
- package/src/core/types.ts +1 -1
- package/src/core/ui-packs/ar.ts +43 -0
- package/src/core/ui-packs/bg.ts +45 -0
- package/src/core/ui-packs/bn.ts +43 -0
- package/src/core/ui-packs/ca.ts +46 -0
- package/src/core/ui-packs/cs.ts +44 -0
- package/src/core/ui-packs/da.ts +45 -0
- package/src/core/ui-packs/de.ts +46 -0
- package/src/core/ui-packs/el.ts +45 -0
- package/src/core/ui-packs/es.ts +46 -0
- package/src/core/ui-packs/fa.ts +45 -0
- package/src/core/ui-packs/fi.ts +45 -0
- package/src/core/ui-packs/fr.ts +46 -0
- package/src/core/ui-packs/he.ts +43 -0
- package/src/core/ui-packs/hi.ts +44 -0
- package/src/core/ui-packs/hr.ts +45 -0
- package/src/core/ui-packs/hu.ts +44 -0
- package/src/core/ui-packs/id.ts +45 -0
- package/src/core/ui-packs/it.ts +45 -0
- package/src/core/ui-packs/ja.ts +45 -0
- package/src/core/ui-packs/ko.ts +44 -0
- package/src/core/ui-packs/nl.ts +46 -0
- package/src/core/ui-packs/no.ts +44 -0
- package/src/core/ui-packs/pl.ts +45 -0
- package/src/core/ui-packs/pt-br.ts +46 -0
- package/src/core/ui-packs/pt.ts +45 -0
- package/src/core/ui-packs/ro.ts +45 -0
- package/src/core/ui-packs/ru.ts +45 -0
- package/src/core/ui-packs/sk.ts +44 -0
- package/src/core/ui-packs/sr.ts +45 -0
- package/src/core/ui-packs/sv.ts +44 -0
- package/src/core/ui-packs/th.ts +43 -0
- package/src/core/ui-packs/tr.ts +45 -0
- package/src/core/ui-packs/uk.ts +45 -0
- package/src/core/ui-packs/vi.ts +45 -0
- package/src/core/ui-packs/zh-tw.ts +43 -0
- package/src/core/ui-packs/zh.ts +43 -0
- package/src/core/variables.ts +103 -0
- package/src/core/version-cut.ts +52 -15
- package/src/deploy/artifacts.ts +104 -14
- package/src/deploy/cloudflare-negotiation.ts +39 -17
- package/src/deploy/headers.ts +10 -5
- package/src/deploy/node-headers.ts +64 -10
- package/src/deploy/platforms/cloudflare.ts +44 -3
- package/src/deploy/platforms/netlify.ts +34 -1
- package/src/deploy/platforms/node.ts +1 -0
- package/src/deploy/platforms/static.ts +1 -0
- package/src/deploy/platforms/types.ts +8 -0
- package/src/deploy/platforms/vercel.ts +38 -2
- package/src/deploy/redirects.ts +139 -36
- package/src/deploy/robots.ts +2 -2
- package/src/deploy/rss.ts +4 -3
- package/src/deploy/sitemap.ts +7 -5
- package/src/deploy/vercel-negotiation.ts +36 -0
- package/src/markdown/api-rail.ts +259 -0
- package/src/markdown/base-links.ts +34 -36
- package/src/markdown/code-title.ts +35 -9
- package/src/markdown/directives.ts +242 -36
- package/src/markdown/features.ts +20 -2
- package/src/markdown/fence-meta.ts +2 -0
- package/src/markdown/include.ts +11 -1
- package/src/markdown/index.ts +35 -11
- package/src/markdown/math.ts +4 -4
- package/src/markdown/mdast.ts +5 -2
- package/src/markdown/relative-links.ts +12 -4
- package/src/markdown/variables.ts +56 -0
- package/src/markdown/views.ts +82 -0
- package/src/narration/build.ts +412 -0
- package/src/narration/player.ts +249 -0
- package/src/narration/provider.ts +29 -0
- package/src/narration/script.ts +592 -0
- package/src/og/card.ts +136 -11
- package/src/og/derive.ts +41 -31
- package/src/og/index.ts +1 -0
- package/src/openapi/asyncapi.ts +4 -2
- package/src/openapi/model.ts +77 -36
- package/src/openapi/overlay.ts +256 -0
- package/src/openapi/parse.ts +55 -2
- package/src/openapi/proxy.ts +63 -10
- package/src/openapi/references.ts +21 -5
- package/src/openapi/render-mdx.ts +46 -3
- package/src/openapi/scalar.ts +40 -6
- package/src/openapi/source.ts +1 -1
- package/src/ratelimit/cloudflare.ts +54 -0
- package/src/ratelimit/index.ts +30 -0
- package/src/ratelimit/memory.ts +45 -0
- package/src/ratelimit/runtime.ts +229 -0
- package/src/ratelimit/schema.ts +28 -0
- package/src/ratelimit/upstash.ts +30 -0
- package/src/ratelimit/wrangler.ts +70 -0
- package/src/reference/asyncapi.ts +2 -2
- package/src/reference/graphql.ts +5 -2
- package/src/reference/openapi.ts +21 -7
- package/src/reference/options.ts +51 -7
- package/src/reference/scalar.ts +33 -8
- package/src/registry/eject.ts +201 -28
- package/src/registry/registry.ts +7 -0
- package/src/search/adapters/version-scope.ts +30 -0
- package/src/search/documents.ts +93 -28
- package/src/search/orama-index.ts +28 -3
- package/src/search/pagefind-ranking.ts +39 -0
- package/src/search/popular.ts +2 -1
- package/src/search/sync/algolia.ts +15 -4
- package/src/search/sync/orama-cloud.ts +3 -0
- package/src/search/sync/typesense.ts +5 -0
- package/src/seo/jsonld.ts +7 -3
- package/src/seo/metatags.ts +67 -0
- package/src/theme/chrome-icons.ts +1 -0
- package/src/theme/color.ts +500 -0
- package/src/theme/entry.ts +56 -3
- package/src/theme/palette.ts +121 -45
- package/src/translate/meta.ts +68 -24
- package/src/translate/prompts.ts +1 -0
- package/src/translate/run.ts +3 -3
- package/src/translate/validate.ts +12 -3
- package/src/translate/work-list.ts +56 -17
- package/src/upgrade/upgrade.ts +4 -171
- package/dist/cli/chunk-3yce002v.js.map +0 -14
- package/dist/cli/chunk-5r8g91qn.js.map +0 -34
- package/dist/cli/chunk-6dtt0zfn.js.map +0 -10
- package/dist/cli/chunk-7mbqtmgb.js.map +0 -10
- package/dist/cli/chunk-ddndchfr.js.map +0 -14
- package/dist/cli/chunk-esh98wmb.js +0 -23
- package/dist/cli/chunk-esh98wmb.js.map +0 -10
- package/dist/cli/chunk-hqp2ajnh.js.map +0 -35
- package/dist/cli/chunk-hr8ne106.js.map +0 -13
- package/dist/cli/chunk-j85scx15.js.map +0 -10
- package/dist/cli/chunk-mqc662a6.js +0 -75
- package/dist/cli/chunk-mqc662a6.js.map +0 -11
- package/dist/cli/chunk-pbg5a4s3.js.map +0 -19
- package/dist/cli/chunk-qkb5a8sa.js.map +0 -10
- package/dist/cli/chunk-v6ya5kcb.js.map +0 -189
- package/dist/cli/chunk-wdrt2k2v.js.map +0 -10
- package/dist/cli/chunk-xh43dwgw.js.map +0 -36
- package/docs/content/sources.mdx +0 -338
- /package/dist/cli/{chunk-zp79m0ts.js.map → chunk-1n228xqb.js.map} +0 -0
- /package/dist/cli/{chunk-h2ez8dzb.js.map → chunk-5ffywsmb.js.map} +0 -0
- /package/dist/cli/{chunk-g698a744.js.map → chunk-5wj2qwn2.js.map} +0 -0
- /package/dist/cli/{chunk-sqw4ekg1.js.map → chunk-amrb6hgh.js.map} +0 -0
- /package/dist/cli/{chunk-h7k3nq3v.js.map → chunk-gp84za0h.js.map} +0 -0
- /package/dist/cli/{chunk-bfwp9vp6.js.map → chunk-p804f3pe.js.map} +0 -0
- /package/dist/cli/{chunk-00gs3wqs.js.map → chunk-ta27feev.js.map} +0 -0
- /package/dist/cli/{chunk-bbnwccaz.js.map → chunk-y4ykbark.js.map} +0 -0
package/src/og/card.ts
CHANGED
|
@@ -2,7 +2,13 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
|
|
3
3
|
import { render } from "takumi-js";
|
|
4
4
|
import type { RenderOptions } from "takumi-js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
collectCodepoints,
|
|
7
|
+
container,
|
|
8
|
+
googleFonts,
|
|
9
|
+
image,
|
|
10
|
+
text,
|
|
11
|
+
} from "takumi-js/helpers";
|
|
6
12
|
import type { FontSubset, GoogleFontFamily, Node } from "takumi-js/helpers";
|
|
7
13
|
|
|
8
14
|
import { svgDimensions } from "../core/svg-dimensions.ts";
|
|
@@ -42,6 +48,9 @@ export type OgFont =
|
|
|
42
48
|
}
|
|
43
49
|
| OgLocalFont;
|
|
44
50
|
|
|
51
|
+
/** An OG font fetched from Google Fonts (a bare family name or the object form). */
|
|
52
|
+
export type OgGoogleFont = Exclude<OgFont, OgLocalFont>;
|
|
53
|
+
|
|
45
54
|
/**
|
|
46
55
|
* Which loaded family each card role renders in. Takumi still falls back
|
|
47
56
|
* across every loaded font per glyph, so a family that misses a script
|
|
@@ -54,15 +63,16 @@ export interface OgFontFamilies {
|
|
|
54
63
|
title?: string;
|
|
55
64
|
}
|
|
56
65
|
|
|
57
|
-
// Named presets resolve from the theme's own OKLCH table
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
66
|
+
// Named presets resolve from the theme's own OKLCH table, in their light
|
|
67
|
+
// shade since the card is light — Takumi parses the full CSS color grammar,
|
|
68
|
+
// so the card renders exactly the accent the site shows (a separate
|
|
69
|
+
// hand-synced hex palette used to drift: the card's "blue" was Tailwind's,
|
|
70
|
+
// not Blume's). Anything else is handed to Takumi as-is, and a genuinely
|
|
71
|
+
// malformed value fails the build with a parse error naming it.
|
|
62
72
|
// `isAccentPreset` keeps a preset name like "constructor" from resolving up
|
|
63
73
|
// the prototype chain.
|
|
64
74
|
const resolveAccent = (accent: string): string =>
|
|
65
|
-
isAccentPreset(accent) ? ACCENTS[accent] : accent;
|
|
75
|
+
isAccentPreset(accent) ? ACCENTS[accent].light : accent;
|
|
66
76
|
|
|
67
77
|
export interface OgCardPalette {
|
|
68
78
|
accent?: string;
|
|
@@ -106,6 +116,12 @@ export interface OgCardOptions {
|
|
|
106
116
|
* from disk instead of Google Fonts.
|
|
107
117
|
*/
|
|
108
118
|
fonts?: OgFont[];
|
|
119
|
+
/**
|
|
120
|
+
* Script fallbacks, tried after `fonts` for glyphs nothing else draws. A
|
|
121
|
+
* card loads them only when its text needs one, so a Latin-only card never
|
|
122
|
+
* fetches them — see {@link fallbackSubsets}.
|
|
123
|
+
*/
|
|
124
|
+
fallbacks?: OgGoogleFont[];
|
|
109
125
|
/** Per-role families from the loaded fonts (title vs body text). */
|
|
110
126
|
families?: OgFontFamilies;
|
|
111
127
|
}
|
|
@@ -145,9 +161,7 @@ const fontSubsetCache = new Map<string, Promise<FontSubset[]>>();
|
|
|
145
161
|
* fetch failure rejects, failing the build with the cause rather than silently
|
|
146
162
|
* shipping tofu — the same fail-fast the OG accent relies on.
|
|
147
163
|
*/
|
|
148
|
-
const loadFonts = (
|
|
149
|
-
fonts: Exclude<OgFont, OgLocalFont>[]
|
|
150
|
-
): Promise<FontSubset[]> => {
|
|
164
|
+
const loadFonts = (fonts: OgGoogleFont[]): Promise<FontSubset[]> => {
|
|
151
165
|
const key = JSON.stringify(fonts);
|
|
152
166
|
let pending = fontSubsetCache.get(key);
|
|
153
167
|
if (!pending) {
|
|
@@ -160,6 +174,113 @@ const loadFonts = (
|
|
|
160
174
|
return pending;
|
|
161
175
|
};
|
|
162
176
|
|
|
177
|
+
/**
|
|
178
|
+
* The code points Takumi's built-in Geist draws: whitespace, printable ASCII,
|
|
179
|
+
* Latin-1 except `µ`, a few Latin extras French needs, and the typographic
|
|
180
|
+
* punctuation English copy leans on. Probed against the renderer, and
|
|
181
|
+
* `og-card.test.ts` renders every one, so a Takumi upgrade that drops a glyph
|
|
182
|
+
* fails there instead of shipping tofu.
|
|
183
|
+
*/
|
|
184
|
+
export const BUILT_IN_GLYPHS: [number, number][] = [
|
|
185
|
+
[0x09, 0x0d],
|
|
186
|
+
[0x20, 0x7e],
|
|
187
|
+
[0xa0, 0xb4],
|
|
188
|
+
[0xb6, 0xff],
|
|
189
|
+
[0x1_31, 0x1_31],
|
|
190
|
+
[0x1_52, 0x1_53],
|
|
191
|
+
[0x1_78, 0x1_78],
|
|
192
|
+
[0x20_00, 0x20_0f],
|
|
193
|
+
[0x20_13, 0x20_14],
|
|
194
|
+
[0x20_18, 0x20_1a],
|
|
195
|
+
[0x20_1c, 0x20_1e],
|
|
196
|
+
[0x20_20, 0x20_22],
|
|
197
|
+
[0x20_26, 0x20_26],
|
|
198
|
+
[0x20_28, 0x20_30],
|
|
199
|
+
[0x20_32, 0x20_33],
|
|
200
|
+
[0x20_39, 0x20_3a],
|
|
201
|
+
[0x20_44, 0x20_44],
|
|
202
|
+
[0x20_5f, 0x20_6f],
|
|
203
|
+
[0x20_ac, 0x20_ac],
|
|
204
|
+
[0x21_22, 0x21_22],
|
|
205
|
+
[0x21_91, 0x21_91],
|
|
206
|
+
[0x21_93, 0x21_93],
|
|
207
|
+
[0x22_12, 0x22_12],
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
/** Emoji render as Twemoji images, never from a font. */
|
|
211
|
+
const EMOJI = /\p{Emoji_Presentation}|\p{Emoji_Component}/u;
|
|
212
|
+
|
|
213
|
+
/** Whether a card draws `codePoint` without any loaded font. */
|
|
214
|
+
const drawnWithoutFonts = (codePoint: number): boolean =>
|
|
215
|
+
BUILT_IN_GLYPHS.some(([from, to]) => codePoint >= from && codePoint <= to) ||
|
|
216
|
+
EMOJI.test(String.fromCodePoint(codePoint));
|
|
217
|
+
|
|
218
|
+
/** Whether `subset` claims `codePoint` (a subset without ranges claims all). */
|
|
219
|
+
const subsetClaims = (subset: FontSubset, codePoint: number): boolean =>
|
|
220
|
+
subset.ranges.length === 0 ||
|
|
221
|
+
subset.ranges.some(([from, to]) => codePoint >= from && codePoint <= to);
|
|
222
|
+
|
|
223
|
+
/** `family`'s subsets that claim any of `codePoints`. */
|
|
224
|
+
const familySubsets = (
|
|
225
|
+
subsets: FontSubset[],
|
|
226
|
+
family: string,
|
|
227
|
+
codePoints: number[]
|
|
228
|
+
): FontSubset[] =>
|
|
229
|
+
subsets.filter(
|
|
230
|
+
(subset) =>
|
|
231
|
+
subset.subsetOf === family &&
|
|
232
|
+
codePoints.some((codePoint) => subsetClaims(subset, codePoint))
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* The scripts only the CJK families draw. Google slices those fonts by the
|
|
237
|
+
* glyphs each one really has, so the first family claiming such a character
|
|
238
|
+
* draws it. Other claims follow Google's shared subset definitions whatever
|
|
239
|
+
* the font holds — every family's `latin` claims `※`, Arabic's `symbols`
|
|
240
|
+
* claims `→` — so a claim there proves nothing.
|
|
241
|
+
*/
|
|
242
|
+
const CJK_SCRIPTS =
|
|
243
|
+
/[\p{Script=Bopomofo}\p{Script=Han}\p{Script=Hangul}\p{Script=Hiragana}\p{Script=Katakana}]/u;
|
|
244
|
+
|
|
245
|
+
/** Whether a claim on `codePoint` means the claiming family draws it. */
|
|
246
|
+
const claimIsExact = (codePoint: number): boolean =>
|
|
247
|
+
CJK_SCRIPTS.test(String.fromCodePoint(codePoint));
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* The fallback subsets a card's text needs. Nothing loads, and nothing is
|
|
251
|
+
* fetched, when the built-in font draws every glyph, so a Latin-only card
|
|
252
|
+
* builds offline. Otherwise only subsets claiming a glyph beyond the built-in
|
|
253
|
+
* font load (not every family's `latin`), and a CJK character stops at the
|
|
254
|
+
* first family that claims it: all four CJK families claim most Han, so left
|
|
255
|
+
* to `render` each would download its matching slices although only the
|
|
256
|
+
* first ever paints them.
|
|
257
|
+
*/
|
|
258
|
+
const fallbackSubsets = async (
|
|
259
|
+
fallbacks: OgGoogleFont[] | undefined,
|
|
260
|
+
node: Node
|
|
261
|
+
): Promise<FontSubset[]> => {
|
|
262
|
+
let missing = [...collectCodepoints(node)].filter(
|
|
263
|
+
(codePoint) => !drawnWithoutFonts(codePoint)
|
|
264
|
+
);
|
|
265
|
+
if (!fallbacks?.length || missing.length === 0) {
|
|
266
|
+
return [];
|
|
267
|
+
}
|
|
268
|
+
const subsets = await loadFonts(fallbacks);
|
|
269
|
+
const needed: FontSubset[] = [];
|
|
270
|
+
for (const family of new Set(subsets.map((subset) => subset.subsetOf))) {
|
|
271
|
+
const matching = familySubsets(subsets, family, missing);
|
|
272
|
+
needed.push(...matching);
|
|
273
|
+
missing = missing.filter(
|
|
274
|
+
(codePoint) =>
|
|
275
|
+
!(
|
|
276
|
+
claimIsExact(codePoint) &&
|
|
277
|
+
matching.some((subset) => subsetClaims(subset, codePoint))
|
|
278
|
+
)
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
return needed;
|
|
282
|
+
};
|
|
283
|
+
|
|
163
284
|
/**
|
|
164
285
|
* A lazy loader for a local font file, matching the shape `render` accepts
|
|
165
286
|
* alongside Google subsets. Keyed by path so the shared renderer reads and
|
|
@@ -422,7 +543,11 @@ export const renderOgImage = async (
|
|
|
422
543
|
const fontSubsets = googleFamilies.length
|
|
423
544
|
? await loadFonts(googleFamilies)
|
|
424
545
|
: [];
|
|
425
|
-
const cardFonts = [
|
|
546
|
+
const cardFonts = [
|
|
547
|
+
...fontSubsets,
|
|
548
|
+
...localFonts.map(localFontLoader),
|
|
549
|
+
...(await fallbackSubsets(options.fallbacks, node)),
|
|
550
|
+
];
|
|
426
551
|
|
|
427
552
|
return render(node, {
|
|
428
553
|
fonts: cardFonts.length ? cardFonts : undefined,
|
package/src/og/derive.ts
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Bridges `theme.fonts` into the OG card renderer. A site that explicitly
|
|
3
3
|
* picks its typefaces gets matching cards (and non-Latin coverage) without
|
|
4
4
|
* configuring `seo.og.fonts`; untouched defaults derive nothing, so plain
|
|
5
|
-
* sites keep Takumi's built-in font
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* sites keep Takumi's built-in font. Either way every card gets a Noto
|
|
6
|
+
* fallback stack for the scripts that font can't draw (Japanese, Hindi,
|
|
7
|
+
* Russian, …), which it fetches only when its text needs one.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { existsSync } from "node:fs";
|
|
@@ -19,9 +19,10 @@ import type {
|
|
|
19
19
|
import { GOOGLE_FONTS, isFontSlug, localeFontSubsets } from "../theme/fonts.ts";
|
|
20
20
|
import type { OgFont, OgFontFamilies, OgLocalFont } from "./card.ts";
|
|
21
21
|
|
|
22
|
-
/** Fonts
|
|
22
|
+
/** Fonts, script fallbacks, and per-role families for the OG endpoint. */
|
|
23
23
|
export interface DerivedOgFonts {
|
|
24
24
|
families?: OgFontFamilies;
|
|
25
|
+
fallbacks?: OgFallbackFont[];
|
|
25
26
|
fonts: OgFont[];
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -165,17 +166,17 @@ export const deriveOgFonts = (
|
|
|
165
166
|
/**
|
|
166
167
|
* The family Takumi renders a card in when no font is loaded: its embedded
|
|
167
168
|
* Geist, which covers Latin only. Naming it keeps a card's Latin text in that
|
|
168
|
-
* face once
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
169
|
+
* face once fallbacks are loaded, since Takumi otherwise tries loaded fonts
|
|
170
|
+
* first; a glyph Geist lacks still falls back to them. Were Takumi to rename
|
|
171
|
+
* it, the name would resolve to nothing and cards would fall back to the
|
|
172
|
+
* loaded fonts, never to tofu.
|
|
172
173
|
*/
|
|
173
174
|
const BUILT_IN_FAMILY = "Geist";
|
|
174
175
|
|
|
175
176
|
/**
|
|
176
177
|
* The Google Noto family that draws each language's script, keyed by BCP 47
|
|
177
178
|
* language subtag, for scripts beyond the Latin, Cyrillic, Greek, and
|
|
178
|
-
* Vietnamese that `Noto Sans` covers (see {@link
|
|
179
|
+
* Vietnamese that `Noto Sans` covers (see {@link localeFamily}). Keep keys
|
|
179
180
|
* alphabetical.
|
|
180
181
|
*/
|
|
181
182
|
const SCRIPT_FAMILIES = {
|
|
@@ -219,8 +220,8 @@ const isScriptLanguage = (
|
|
|
219
220
|
): language is keyof typeof SCRIPT_FAMILIES =>
|
|
220
221
|
Object.hasOwn(SCRIPT_FAMILIES, language);
|
|
221
222
|
|
|
222
|
-
/** A
|
|
223
|
-
export interface
|
|
223
|
+
/** A script fallback: a Google family at the weights the card renders. */
|
|
224
|
+
export interface OgFallbackFont {
|
|
224
225
|
name: string;
|
|
225
226
|
weight: number[];
|
|
226
227
|
}
|
|
@@ -246,16 +247,28 @@ const localeFamily = (locale: string): string | null => {
|
|
|
246
247
|
};
|
|
247
248
|
|
|
248
249
|
/**
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
* the same site pulls nothing extra.
|
|
250
|
+
* Every script's fallback, in the order a card tries them: `Noto Sans` for
|
|
251
|
+
* extended Latin, Cyrillic, Greek, and Vietnamese, then a family per script.
|
|
252
|
+
* The CJK families all draw Han ideographs, so the first one wins them —
|
|
253
|
+
* Japanese forms, unless a configured locale moves its own family ahead.
|
|
254
254
|
*/
|
|
255
|
-
|
|
255
|
+
const DEFAULT_FALLBACKS = [
|
|
256
|
+
"Noto Sans",
|
|
257
|
+
...new Set(Object.values(SCRIPT_FAMILIES)),
|
|
258
|
+
"Noto Sans TC",
|
|
259
|
+
];
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* The card's script fallbacks, at the card's weights: each configured
|
|
263
|
+
* locale's family first, so a Chinese site draws Han in Chinese forms, then
|
|
264
|
+
* every other script's, so a page in a language the site never configured
|
|
265
|
+
* still renders instead of tofu. Takumi's built-in font covers only basic
|
|
266
|
+
* Latin; the card fetches these only when its text needs a glyph beyond it,
|
|
267
|
+
* and then only the families and subsets that glyph needs.
|
|
268
|
+
*/
|
|
269
|
+
export const ogFallbackFonts = (locales: string[]): OgFallbackFont[] => {
|
|
256
270
|
const names = new Set<string>();
|
|
257
|
-
for (const
|
|
258
|
-
const family = localeFamily(locale);
|
|
271
|
+
for (const family of [...locales.map(localeFamily), ...DEFAULT_FALLBACKS]) {
|
|
259
272
|
if (family) {
|
|
260
273
|
names.add(family);
|
|
261
274
|
}
|
|
@@ -272,27 +285,24 @@ const ogFontName = (font: OgFont): string =>
|
|
|
272
285
|
isGoogleFamilyName(font) ? font : font.name;
|
|
273
286
|
|
|
274
287
|
/**
|
|
275
|
-
* `derived` plus the
|
|
288
|
+
* `derived` plus the script fallbacks it doesn't already load. A card that
|
|
276
289
|
* names no family is pinned to {@link BUILT_IN_FAMILY}, so its Latin text
|
|
277
290
|
* keeps the face it had before any fallback was loaded.
|
|
278
291
|
*/
|
|
279
|
-
const
|
|
292
|
+
const withFallbacks = (
|
|
280
293
|
derived: DerivedOgFonts,
|
|
281
294
|
locales: string[]
|
|
282
295
|
): DerivedOgFonts => {
|
|
283
296
|
const loaded = new Set(derived.fonts.map(ogFontName));
|
|
284
|
-
const fallbacks = localeOgFonts(locales).filter(
|
|
285
|
-
(font) => !loaded.has(ogFontName(font))
|
|
286
|
-
);
|
|
287
|
-
if (fallbacks.length === 0) {
|
|
288
|
-
return derived;
|
|
289
|
-
}
|
|
290
297
|
return {
|
|
298
|
+
fallbacks: ogFallbackFonts(locales).filter(
|
|
299
|
+
(font) => !loaded.has(font.name)
|
|
300
|
+
),
|
|
291
301
|
families: derived.families ?? {
|
|
292
302
|
body: BUILT_IN_FAMILY,
|
|
293
303
|
title: BUILT_IN_FAMILY,
|
|
294
304
|
},
|
|
295
|
-
fonts:
|
|
305
|
+
fonts: derived.fonts,
|
|
296
306
|
};
|
|
297
307
|
};
|
|
298
308
|
|
|
@@ -307,8 +317,8 @@ export const resolveOgFontSources = (fonts: OgFont[], root: string): OgFont[] =>
|
|
|
307
317
|
* always wins (including `[]` to opt out, keeping the card's role styling
|
|
308
318
|
* untouched); otherwise a site that explicitly set `theme.fonts` gets its
|
|
309
319
|
* display/body fonts derived so cards match the site without extra config,
|
|
310
|
-
* and either way
|
|
311
|
-
*
|
|
320
|
+
* and either way every card gets the script fallbacks, the configured
|
|
321
|
+
* locales' first.
|
|
312
322
|
*/
|
|
313
323
|
export const resolveOgFonts = (
|
|
314
324
|
options: {
|
|
@@ -328,7 +338,7 @@ export const resolveOgFonts = (
|
|
|
328
338
|
const derived = options.themeFontsConfigured
|
|
329
339
|
? deriveOgFonts(options.themeFonts, root)
|
|
330
340
|
: { fonts: [] };
|
|
331
|
-
return
|
|
341
|
+
return withFallbacks(derived, options.locales ?? []);
|
|
332
342
|
};
|
|
333
343
|
|
|
334
344
|
/**
|
package/src/og/index.ts
CHANGED
package/src/openapi/asyncapi.ts
CHANGED
|
@@ -46,7 +46,8 @@ export interface AsyncApiChannelObject {
|
|
|
46
46
|
messages?: Record<string, AsyncApiRefLike>;
|
|
47
47
|
parameters?: Record<string, AsyncApiRefLike>;
|
|
48
48
|
servers?: AsyncApiRefLike[];
|
|
49
|
-
|
|
49
|
+
/** Protocol-keyed binding objects, or a `$ref` to a components entry. */
|
|
50
|
+
bindings?: Record<string, AsyncApiSpecValue>;
|
|
50
51
|
[key: string]: AsyncApiSpecValue;
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -61,7 +62,8 @@ export interface AsyncApiOperationObject {
|
|
|
61
62
|
tags?: { name?: string; description?: string }[];
|
|
62
63
|
security?: AsyncApiRefLike[];
|
|
63
64
|
messages?: AsyncApiRefLike[];
|
|
64
|
-
|
|
65
|
+
/** Protocol-keyed binding objects, or a `$ref` to a components entry. */
|
|
66
|
+
bindings?: Record<string, AsyncApiSpecValue>;
|
|
65
67
|
[key: string]: AsyncApiSpecValue;
|
|
66
68
|
}
|
|
67
69
|
|
package/src/openapi/model.ts
CHANGED
|
@@ -46,6 +46,9 @@ export type HttpMethod = (typeof HTTP_METHODS)[number];
|
|
|
46
46
|
/** Group used for operations that declare no tag. */
|
|
47
47
|
const UNTAGGED = "Operations";
|
|
48
48
|
|
|
49
|
+
/** Group used for webhooks that declare no tag. */
|
|
50
|
+
const UNTAGGED_WEBHOOKS = "Webhooks";
|
|
51
|
+
|
|
49
52
|
/** A lower-case letter or digit followed by a capital: `addPet`, `v2List`. */
|
|
50
53
|
const CASE_BOUNDARY = /(?<before>[\p{Ll}\p{N}])(?<capital>\p{Lu})/gu;
|
|
51
54
|
/** The last capital of an acronym before a capitalized word: `HTTPResponse`. */
|
|
@@ -101,6 +104,12 @@ export interface ApiOperationRef {
|
|
|
101
104
|
deprecated: boolean;
|
|
102
105
|
/** The channel the operation acts on (AsyncAPI only). */
|
|
103
106
|
channelId?: string;
|
|
107
|
+
/**
|
|
108
|
+
* An OpenAPI 3.1 webhook: a request the API sends to the reader's endpoint
|
|
109
|
+
* rather than one it serves. `path` then holds the webhook's name, the key
|
|
110
|
+
* it has under the document's `webhooks`.
|
|
111
|
+
*/
|
|
112
|
+
webhook?: true;
|
|
104
113
|
}
|
|
105
114
|
|
|
106
115
|
/**
|
|
@@ -134,8 +143,8 @@ export interface ApiSpecData {
|
|
|
134
143
|
/** Operations keyed by {@link ApiOperationRef.key}. */
|
|
135
144
|
operations: Record<string, ApiOperationRef>;
|
|
136
145
|
tags: ApiTagRef[];
|
|
137
|
-
/** Code-sample languages to render per operation. */
|
|
138
|
-
codeSamples: string[];
|
|
146
|
+
/** Code-sample languages to render per operation; `false` for none. */
|
|
147
|
+
codeSamples: string[] | false;
|
|
139
148
|
/** Whether nested schema rows start expanded. */
|
|
140
149
|
expandSchemas: boolean;
|
|
141
150
|
/**
|
|
@@ -260,9 +269,18 @@ const isOperation = (
|
|
|
260
269
|
value: OperationObject | undefined
|
|
261
270
|
): value is OperationObject => typeof value === "object" && value !== null;
|
|
262
271
|
|
|
263
|
-
/**
|
|
264
|
-
const
|
|
265
|
-
typeof
|
|
272
|
+
/** Whether a spec value is text YAML may have read as a number. */
|
|
273
|
+
const isText = <Value>(value: Value): value is Value & (string | number) =>
|
|
274
|
+
typeof value === "string" || typeof value === "number";
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* A spec field that names something, as a string. YAML reads an unquoted
|
|
278
|
+
* `operationId: 404` or `tags: [2024]` as a number, which still names the
|
|
279
|
+
* operation or tag; anything else a hand-written spec puts there counts as
|
|
280
|
+
* absent.
|
|
281
|
+
*/
|
|
282
|
+
const specText = <Value>(value: Value): string | undefined =>
|
|
283
|
+
isText(value) ? String(value) : undefined;
|
|
266
284
|
|
|
267
285
|
/**
|
|
268
286
|
* Assign each distinct tag name a unique slug. `slugify` can collapse
|
|
@@ -292,12 +310,14 @@ export const tagSlugger = (): ((name: string) => string) => {
|
|
|
292
310
|
};
|
|
293
311
|
};
|
|
294
312
|
|
|
313
|
+
/** One entry of a document's `paths` or `webhooks` map. */
|
|
314
|
+
type PathItemEntry =
|
|
315
|
+
| NonNullable<ApiDocument["paths"]>[string]
|
|
316
|
+
| NonNullable<ApiDocument["webhooks"]>[string];
|
|
317
|
+
|
|
295
318
|
/** An operation before the collector assigns its unique key and route. */
|
|
296
319
|
type CollectedOperation = Omit<ApiOperationRef, "route" | "tagSlug">;
|
|
297
320
|
|
|
298
|
-
/** A document's declared tag entry (`tags[n]`). */
|
|
299
|
-
type SpecTag = NonNullable<ApiDocument["tags"]>[number];
|
|
300
|
-
|
|
301
321
|
/** The flattened output both extractors produce. */
|
|
302
322
|
export interface CollectedOperations {
|
|
303
323
|
operations: ApiOperationRef[];
|
|
@@ -380,10 +400,10 @@ export const operationCollector = (
|
|
|
380
400
|
|
|
381
401
|
/**
|
|
382
402
|
* Flatten a 3.1 document into a route-mapped operation list and its ordered
|
|
383
|
-
* tags. Operations inherit the first tag they declare; keys
|
|
384
|
-
* a repeated `operationId` still yields distinct routes.
|
|
385
|
-
* anything skipped (a `$ref` path item
|
|
386
|
-
* aren't silent.
|
|
403
|
+
* tags, webhooks included. Operations inherit the first tag they declare; keys
|
|
404
|
+
* are de-duplicated so a repeated `operationId` still yields distinct routes.
|
|
405
|
+
* `warnings` reports anything skipped (a `$ref` path item), so missing
|
|
406
|
+
* operations aren't silent.
|
|
387
407
|
*/
|
|
388
408
|
export const extractOperations = (
|
|
389
409
|
document: ApiDocument,
|
|
@@ -391,48 +411,67 @@ export const extractOperations = (
|
|
|
391
411
|
): ExtractedOperations => {
|
|
392
412
|
const warnings: string[] = [];
|
|
393
413
|
const tagMeta = new Map(
|
|
394
|
-
(document.tags ?? [])
|
|
395
|
-
.
|
|
396
|
-
|
|
414
|
+
(document.tags ?? []).flatMap((tag): [string, string][] => {
|
|
415
|
+
const name = specText(tag.name);
|
|
416
|
+
return name === undefined ? [] : [[name, tag.description ?? ""]];
|
|
417
|
+
})
|
|
397
418
|
);
|
|
398
419
|
const collector = operationCollector(baseRoute, tagMeta);
|
|
399
420
|
|
|
400
|
-
|
|
421
|
+
// A path item's operations, filed under `name`: a path for `paths`, the
|
|
422
|
+
// webhook's key for `webhooks`.
|
|
423
|
+
const addPathItem = (
|
|
424
|
+
name: string,
|
|
425
|
+
item: PathItemEntry,
|
|
426
|
+
webhook: boolean
|
|
427
|
+
): void => {
|
|
401
428
|
// A parsed spec can carry a null path item despite the type; skip it.
|
|
402
429
|
if (!item) {
|
|
403
|
-
|
|
430
|
+
return;
|
|
404
431
|
}
|
|
405
432
|
if ("$ref" in item) {
|
|
406
433
|
warnings.push(
|
|
407
|
-
|
|
434
|
+
webhook
|
|
435
|
+
? `Webhook "${name}" is a $ref to a shared path item; referenced path items are not resolved, so it is missing from the reference. Inline the path item under "webhooks" to render it.`
|
|
436
|
+
: `Path "${name}" is a $ref to a shared path item; referenced path items are not resolved, so its operations are missing from the reference. Inline the path item under "paths" to render it.`
|
|
408
437
|
);
|
|
409
|
-
|
|
438
|
+
return;
|
|
410
439
|
}
|
|
411
440
|
for (const method of HTTP_METHODS) {
|
|
412
441
|
const operation = item[method];
|
|
413
442
|
if (!isOperation(operation)) {
|
|
414
443
|
continue;
|
|
415
444
|
}
|
|
416
|
-
|
|
445
|
+
const operationId = specText(operation.operationId);
|
|
446
|
+
const entry: CollectedOperation = {
|
|
417
447
|
deprecated: operation.deprecated ?? false,
|
|
418
|
-
description: operation.description ?? "",
|
|
419
|
-
|
|
448
|
+
description: specText(operation.description) ?? "",
|
|
449
|
+
// A webhook without an operationId is keyed by its name, which is
|
|
450
|
+
// already an identifier (`newPet` -> `new-pet`).
|
|
451
|
+
key: operationKey(
|
|
452
|
+
method,
|
|
453
|
+
name,
|
|
454
|
+
operationId ?? (webhook ? name : undefined)
|
|
455
|
+
),
|
|
420
456
|
method,
|
|
421
|
-
operationId
|
|
422
|
-
path,
|
|
423
|
-
summary: operation.summary ?? "",
|
|
424
|
-
tag:
|
|
425
|
-
|
|
457
|
+
operationId,
|
|
458
|
+
path: name,
|
|
459
|
+
summary: specText(operation.summary) ?? "",
|
|
460
|
+
tag:
|
|
461
|
+
specText(operation.tags?.[0]) ??
|
|
462
|
+
(webhook ? UNTAGGED_WEBHOOKS : UNTAGGED),
|
|
463
|
+
};
|
|
464
|
+
collector.add(webhook ? { ...entry, webhook: true } : entry);
|
|
426
465
|
}
|
|
427
|
-
}
|
|
466
|
+
};
|
|
428
467
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
);
|
|
468
|
+
for (const [path, item] of Object.entries(document.paths ?? {})) {
|
|
469
|
+
addPathItem(path, item, false);
|
|
470
|
+
}
|
|
471
|
+
// OpenAPI 3.1 webhooks: requests the API sends rather than serves. They
|
|
472
|
+
// follow the paths, so an untagged webhook group sits after the endpoints.
|
|
473
|
+
for (const [name, item] of Object.entries(document.webhooks ?? {})) {
|
|
474
|
+
addPathItem(name, item, true);
|
|
436
475
|
}
|
|
437
476
|
|
|
438
477
|
return { ...collector.finish(), warnings };
|
|
@@ -450,7 +489,9 @@ export const operationObject = (
|
|
|
450
489
|
// (AsyncAPI documents go to `asyncApiOperationObject`), so the spec's
|
|
451
490
|
// document is the OpenAPI shape.
|
|
452
491
|
const document = spec.document as ApiDocument;
|
|
453
|
-
const item =
|
|
492
|
+
const item = ref.webhook
|
|
493
|
+
? document.webhooks?.[ref.path]
|
|
494
|
+
: document.paths?.[ref.path];
|
|
454
495
|
const operation = method === undefined ? undefined : item?.[method];
|
|
455
496
|
return isOperation(operation) ? operation : undefined;
|
|
456
497
|
};
|